diff --git a/DEPS b/DEPS
index 2920dc4..a9c65e1a 100644
--- a/DEPS
+++ b/DEPS
@@ -311,11 +311,11 @@
   # 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': 'f1bc03fd6b4c201abd9f0fd9d51fb989150f97b9',
+  'v8_revision': 'c90f939a79eab36ff08b04ae6a619c718b363b22',
   # 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': '3ca4cde711b0ee03861d1294213c5b63dbee5ef9',
+  'angle_revision': '19fb11b67c6f30f440112ca5d9725d1bed9b232e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -334,7 +334,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:10.20221013.0.1',
+  'fuchsia_version': 'version:9.20221006.5.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -378,7 +378,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'df8440aca35dcbdaf56ecc3a5ded229fedf80cc7',
+  'catapult_revision': 'faaae893d5d2c4050d9ba741a2cbd70b4528c7fe',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -422,7 +422,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'aecf1a2ab5106c4a08f8e2ae79717483f3abf8ee',
+  'dawn_revision': '18bcdebc0256ad3d14bd1290163c98c84baddfa3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -818,7 +818,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    'f2f33b925ca49fa7e2c44d27e6a2f5b741855c0a',
+    'aa0b389580b88beb9ef353b3a7bb11cfa3f8bac6',
     'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
   },
 
@@ -923,7 +923,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'xH8MfShB-S7HYkM3gLOUa916ukoEtDJa-8X1bOwfevsC',
+          'version': 'Yl7cUc03IbwQqGpCBGiiefZ83rN4O-7cUEWedTJ0qLcC',
         },
       ],
       'dep_type': 'cipd',
@@ -934,7 +934,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'SWCvrm3LQO_Y0XbcVVs0q2CJOVKn0ImNLJ0WPQDKx5YC',
+          'version': 'h3TMxlBpShy8lGRaIG18Il0sqnAYBWm1qQ3jArztOiQC',
         },
       ],
       'dep_type': 'cipd',
@@ -1251,7 +1251,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'b2aab03500a9810f3d267f1bd72ae155937d45a0',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'd26f0c7dfd01f6ddc0a5fab146c54fa7cc31e8c0',
     'condition': 'checkout_src_internal',
   },
 
@@ -1406,7 +1406,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '41cdffd71c9948f63c7ad36e1fb0ff519aa7a37e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '20f8ac695af59b6c830def7d4e95bfeb13dd7be5',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'da07448619763d1cde255b361324242646f5b268',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1921,7 +1921,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f4fd7a75dd91cc4c56f00d09ee098d86775c6e10',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4bd291c858980c53e3127bcb8a7076502f87d6a1',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0adc954..7a9efbd4 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2772,7 +2772,6 @@
     "metrics/feature_discovery_duration_reporter_impl_unittest.cc",
     "metrics/histogram_macros_unittest.cc",
     "metrics/login_metrics_recorder_unittest.cc",
-    "metrics/login_unlock_throughput_recorder_unittest.cc",
     "metrics/pointer_metrics_recorder_unittest.cc",
     "metrics/stylus_metrics_recorder_unittest.cc",
     "metrics/task_switch_metrics_recorder_unittest.cc",
@@ -3215,7 +3214,6 @@
     "//chromeos/crosapi/cpp",
     "//chromeos/dbus/power",
     "//chromeos/dbus/power:power_manager_proto",
-    "//chromeos/login/login_state:login_state",
     "//chromeos/services/network_config/public/cpp",
     "//chromeos/services/network_config/public/mojom",
     "//chromeos/strings:strings_grit",
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index 1719f47..6da7baa 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -155,10 +155,6 @@
     "views/search_result_page_dialog_controller.h",
     "views/search_result_page_view.cc",
     "views/search_result_page_view.h",
-    "views/search_result_tile_item_list_view.cc",
-    "views/search_result_tile_item_list_view.h",
-    "views/search_result_tile_item_view.cc",
-    "views/search_result_tile_item_view.h",
     "views/search_result_view.cc",
     "views/search_result_view.h",
     "views/suggested_content_info_view.cc",
@@ -311,7 +307,6 @@
     "views/search_box_view_unittest.cc",
     "views/search_result_list_view_unittest.cc",
     "views/search_result_page_view_unittest.cc",
-    "views/search_result_tile_item_list_view_unittest.cc",
     "views/search_result_view_unittest.cc",
   ]
 
diff --git a/ash/app_list/app_list_color_provider_impl.cc b/ash/app_list/app_list_color_provider_impl.cc
index baf96e4c..049eae0 100644
--- a/ash/app_list/app_list_color_provider_impl.cc
+++ b/ash/app_list/app_list_color_provider_impl.cc
@@ -245,13 +245,6 @@
       kColorAshControlBackgroundColorInactive);
 }
 
-ui::ColorId AppListColorProviderImpl::GetSeparatorColorId() const {
-  if (ShouldUseDarkLightColors()) {
-    return ui::kColorAshAppListSeparatorLight;
-  }
-  return ui::kColorAshAppListSeparator;  // default_color
-}
-
 SkColor AppListColorProviderImpl::GetFocusRingColor(
     const views::Widget* app_list_widget) const {
   DCHECK(app_list_widget);
diff --git a/ash/app_list/app_list_color_provider_impl.h b/ash/app_list/app_list_color_provider_impl.h
index 0a4a6384..639274d 100644
--- a/ash/app_list/app_list_color_provider_impl.h
+++ b/ash/app_list/app_list_color_provider_impl.h
@@ -55,7 +55,6 @@
       const views::Widget* app_list_widget) const override;
   SkColor GetGridBackgroundCardInactiveColor(
       const views::Widget* app_list_widget) const override;
-  ui::ColorId GetSeparatorColorId() const override;
   SkColor GetFocusRingColor(
       const views::Widget* app_list_widget) const override;
   SkColor GetInkDropBaseColor(
diff --git a/ash/app_list/app_list_metrics_unittest.cc b/ash/app_list/app_list_metrics_unittest.cc
index 6dc6946d..7d978703 100644
--- a/ash/app_list/app_list_metrics_unittest.cc
+++ b/ash/app_list/app_list_metrics_unittest.cc
@@ -26,7 +26,6 @@
 #include "ash/app_list/views/recent_apps_view.h"
 #include "ash/app_list/views/search_result_container_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
@@ -116,45 +115,6 @@
     LeftClickOn(view_model->view_at(kBrowserAppIndexOnShelf));
   }
 
-  void PopulateAndLaunchSearchBoxTileItem() {
-    // Populate 4 tile items.
-    for (size_t i = 0; i < 4; i++) {
-      auto search_result = std::make_unique<SearchResult>();
-      search_result->set_display_type(SearchResultDisplayType::kTile);
-
-      // Give each item a name so that the accessibility paint checks pass.
-      // (Focusable items should have accessible names.)
-      search_result->SetAccessibleName(
-          base::UTF8ToUTF16(base::StringPrintf("item %zu", i)));
-
-      search_model_->results()->Add(std::move(search_result));
-    }
-    GetAppListTestHelper()->WaitUntilIdle();
-
-    // Mark the privacy notices as dismissed so that the tile items will be the
-    // first search container.
-    ContentsView* contents_view = Shell::Get()
-                                      ->app_list_controller()
-                                      ->fullscreen_presenter()
-                                      ->GetView()
-                                      ->app_list_main_view()
-                                      ->contents_view();
-    Shell::Get()->app_list_controller()->MarkSuggestedContentInfoDismissed();
-    contents_view->search_result_page_view()
-        ->GetPrivacyContainerViewForTest()
-        ->Update();
-
-    SearchResultContainerView* search_result_container_view =
-        contents_view->search_result_page_view()
-            ->GetSearchResultTileItemListViewForTest();
-
-    // Request focus on the first tile item view.
-    search_result_container_view->GetFirstResultView()->RequestFocus();
-
-    // Press return to simulate an app launch from the tile item.
-    PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN);
-  }
-
   void PopulateAndLaunchAppInGrid(int num = 4) {
     // Populate apps in the root app grid.
     AppListModel* model = AppListModelProvider::Get()->model();
@@ -253,33 +213,6 @@
       1 /* Number of times launched from shelf */);
 }
 
-// Test that the histogram records an app launch from the search box while the
-// homercher search state is showing.
-TEST_P(AppListMetricsTabletTest, HomecherSearchLaunchFromSearchBox) {
-  // ProductivityLauncher does not tile search results.
-  if (features::IsProductivityLauncherEnabled())
-    return;
-
-  base::HistogramTester histogram_tester;
-
-  // Enable tablet mode.
-  GetAppListTestHelper()->WaitUntilIdle();
-  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
-
-  // Press a letter key, the AppListView should transition to kFullscreenSearch.
-  PressAndReleaseKey(ui::KeyboardCode::VKEY_H);
-  GetAppListTestHelper()->WaitUntilIdle();
-  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
-
-  // Populate search box with tile items and launch a tile item.
-  PopulateAndLaunchSearchBoxTileItem();
-
-  histogram_tester.ExpectBucketCount(
-      "Apps.AppListAppLaunchedV2.HomecherSearch",
-      AppListLaunchedFrom::kLaunchedFromSearchBox,
-      1 /* Number of times launched from search box */);
-}
-
 // Tests with feature ProductivityLauncher enabled.
 class AppListMetricsProductivityLauncherTest : public AppListMetricsTest {
  public:
diff --git a/ash/app_list/app_list_presenter_impl.cc b/ash/app_list/app_list_presenter_impl.cc
index c801b68..1d68b14d 100644
--- a/ash/app_list/app_list_presenter_impl.cc
+++ b/ash/app_list/app_list_presenter_impl.cc
@@ -29,6 +29,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/containers/contains.h"
+#include "base/functional/callback_forward.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h"
@@ -37,6 +38,8 @@
 #include "ui/aura/window.h"
 #include "ui/compositor/animation_throughput_reporter.h"
 #include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animation_element.h"
+#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/screen.h"
 #include "ui/display/types/display_constants.h"
@@ -53,6 +56,14 @@
 
 using assistant::AssistantExitPoint;
 
+// The target scale to which (or from which) the fullscreen launcher will
+// animate between tablet <-> clamshell mode transition.
+constexpr float kFullscreenLauncherFadeAnimationScale = 0.92f;
+
+// The fade in/out animation duration for tablet <-> clamshell mode transition.
+constexpr base::TimeDelta kFullscreenLauncherTransitionDuration =
+    base::Milliseconds(350);
+
 inline ui::Layer* GetLayer(views::Widget* widget) {
   return widget->GetNativeView()->layer();
 }
@@ -105,6 +116,42 @@
   }
 }
 
+// Invokes `complete_callback_` at the end of animation.
+class FullscreenLauncherAnimationObserver
+    : public ui::ImplicitAnimationObserver {
+ public:
+  explicit FullscreenLauncherAnimationObserver(
+      base::OnceClosure complete_callback)
+      : complete_callback_(std::move(complete_callback)) {}
+  FullscreenLauncherAnimationObserver(
+      const FullscreenLauncherAnimationObserver& other) = delete;
+  FullscreenLauncherAnimationObserver& operator=(
+      const FullscreenLauncherAnimationObserver& other) = delete;
+  ~FullscreenLauncherAnimationObserver() override {
+    StopObservingImplicitAnimations();
+  }
+
+  // ui::ImplicitAnimationObserver:
+  void OnImplicitAnimationsCompleted() override {
+    std::move(complete_callback_).Run();
+    delete this;
+  }
+
+ private:
+  base::OnceClosure complete_callback_;
+};
+
+void UpdateTabletModeTransitionAnimationSettings(
+    FullscreenLauncherAnimationObserver* animation_observer,
+    ui::ScopedLayerAnimationSettings* settings) {
+  settings->SetTransitionDuration(kFullscreenLauncherTransitionDuration);
+  settings->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
+  settings->SetPreemptionStrategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  if (animation_observer)
+    settings->AddObserver(animation_observer);
+}
+
 // Implicit animation observer that runs a scoped closure runner, and deletes
 // itself when the observed implicit animations complete.
 class CallbackRunnerLayerAnimationObserver
@@ -227,8 +274,35 @@
   last_open_source_ = show_source;
   last_open_time_ = base::Time::Now();
 
+  auto* layer = view_->GetWidget()->GetNativeWindow()->layer();
+
+  float initial_opacity;
+  if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+    // `0.01f` prevents a DCHECK error (widgets cannot be shown when visible and
+    // fully transparent at the same time).
+    initial_opacity = layer->opacity() == 0.0f ? 0.01f : layer->opacity();
+  } else {
+    initial_opacity = 1.0f;
+  }
+  layer->SetOpacity(initial_opacity);
+
   view_->Show(preferred_state, IsSideShelf(shelf));
 
+  if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+    // Set initial transform only if layer is not currently animating one (for
+    // example during hide animation).
+    if (!layer->GetAnimator()->IsAnimatingProperty(
+            ui::LayerAnimationElement::TRANSFORM)) {
+      layer->SetTransform(
+          gfx::GetScaleTransform(gfx::Rect(layer->size()).CenterPoint(),
+                                 kFullscreenLauncherFadeAnimationScale));
+    }
+    UpdateScaleAndOpacityForHomeLauncher(
+        1.0f, 1.0f, absl::nullopt,
+        base::BindRepeating(&UpdateTabletModeTransitionAnimationSettings,
+                            nullptr));
+  }
+
   SnapAppListBoundsToDisplayEdge();
 
   event_filter_ =
@@ -304,8 +378,20 @@
   last_open_source_.reset();
   last_open_time_.reset();
 
-  if (!view_->GetWidget()->GetNativeWindow()->is_destroying())
+  if (!view_->GetWidget()->GetNativeWindow()->is_destroying()) {
+    if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+      base::OnceClosure animation_complete_callback = base::BindOnce(
+          &AppListPresenterImpl::OnTabletToClamshellTransitionAnimationDone,
+          weak_ptr_factory_.GetWeakPtr());
+      auto* animation_observer = new FullscreenLauncherAnimationObserver(
+          std::move(animation_complete_callback));
+      UpdateScaleAndOpacityForHomeLauncher(
+          kFullscreenLauncherFadeAnimationScale, 0.0f, absl::nullopt,
+          base::BindRepeating(&UpdateTabletModeTransitionAnimationSettings,
+                              animation_observer));
+    }
     view_->SetState(AppListViewState::kClosed);
+  }
 
   view_->SetDragAndDropHostOfCurrentAppList(nullptr);
 
@@ -400,17 +486,12 @@
     float opacity,
     absl::optional<TabletModeAnimationTransition> transition,
     UpdateHomeLauncherAnimationSettingsCallback callback) {
-  if (!view_)
+  // Exiting from overview in clamshell mode should not affect the hidden
+  // fullscreen launcher.
+  if (!view_ || view_->app_list_state() == AppListViewState::kClosed)
     return;
 
   ui::Layer* layer = view_->GetWidget()->GetNativeWindow()->layer();
-  if (!Shell::Get()->IsInTabletMode()) {
-    // In clamshell mode, set the opacity of the AppList immediately to
-    // instantly hide it. Opacity of the AppList is reset when it is shown
-    // again.
-    layer->SetOpacity(opacity);
-    return;
-  }
 
   if (layer->GetAnimator()->is_animating()) {
     layer->GetAnimator()->StopAnimating();
@@ -695,4 +776,13 @@
   SetViewIgnoredForAccessibility(view_->search_box_view(), false);
 }
 
+void AppListPresenterImpl::OnTabletToClamshellTransitionAnimationDone() {
+  if (!view_)
+    return;
+
+  auto* window = view_->GetWidget()->GetNativeWindow();
+  if (window->layer()->GetTargetOpacity() == 0.0f)
+    window->Hide();
+}
+
 }  // namespace ash
diff --git a/ash/app_list/app_list_presenter_impl.h b/ash/app_list/app_list_presenter_impl.h
index 2955f37c..ed06dbdb 100644
--- a/ash/app_list/app_list_presenter_impl.h
+++ b/ash/app_list/app_list_presenter_impl.h
@@ -205,6 +205,10 @@
   // Called when the reorder animation completes.
   void OnAppListReorderAnimationDone();
 
+  // Called when the tablet to clamshell transition animation completes.
+  // Hides the `AppListView`'s window if target opacity is zero.
+  void OnTabletToClamshellTransitionAnimationDone();
+
   // Owns |this|.
   AppListControllerImpl* const controller_;
 
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc
index dc2ec57..5de9776e 100644
--- a/ash/app_list/app_list_presenter_unittest.cc
+++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -37,13 +37,13 @@
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/app_list/views/search_result_page_anchored_dialog.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/constants/ash_features.h"
 #include "ash/keyboard/keyboard_controller_impl.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
 #include "ash/public/cpp/app_list/app_list_color_provider.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
 #include "ash/public/cpp/shelf_config.h"
@@ -89,6 +89,9 @@
 #include "ui/display/test/display_manager_test_api.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/transform_util.h"
 #include "ui/touch_selection/touch_selection_menu_runner.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/textfield/textfield.h"
@@ -3353,12 +3356,6 @@
   EXPECT_TRUE(search_box_view->is_search_box_active());
   GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
 
-  SearchResultContainerView* const tile_item_container =
-      search_result_page()->GetSearchResultTileItemListViewForTest();
-  ASSERT_EQ(1, tile_item_container->num_results());
-  EXPECT_EQ("test_tile",
-            tile_item_container->GetResultViewAt(0)->result()->id());
-
   SearchResultContainerView* item_list_container =
       search_result_page()->GetSearchResultListViewForTest();
   ASSERT_EQ(1, item_list_container->num_results());
@@ -3400,10 +3397,6 @@
   EXPECT_TRUE(search_box_view->is_search_box_active());
   GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenSearch);
 
-  ASSERT_EQ(1, tile_item_container->num_results());
-  EXPECT_EQ("test_tile_override",
-            tile_item_container->GetResultViewAt(0)->result()->id());
-
   ASSERT_EQ(1, item_list_container->num_results());
   EXPECT_EQ("test_override",
             item_list_container->GetResultViewAt(0)->result()->id());
@@ -4413,4 +4406,88 @@
   EXPECT_LT(textfield->GetCursorPosition(), initial_cursor_position);
 }
 
+// Temporary class to test `kAnimateScaleOnTabletModeTransition` related
+// animations.
+class AppListPresenterWithScaleAnimationOnTabletModeTransitionTest
+    : public AppListPresenterTest {
+ public:
+  AppListPresenterWithScaleAnimationOnTabletModeTransitionTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        app_list_features::kAnimateScaleOnTabletModeTransition);
+  }
+
+ protected:
+  void EnsureAppListViewIsCached() {
+    ASSERT_FALSE(GetAppListTestHelper()->GetAppListView());
+
+    EnableTabletMode(true);
+    GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+    GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
+
+    EnableTabletMode(false);
+    GetAppListTestHelper()->WaitUntilIdle();
+    GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
+
+    // Entering and exiting from tablet mode should keep `AppListView` cached.
+    ASSERT_TRUE(GetAppListTestHelper()->GetAppListView());
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(AppListPresenterWithScaleAnimationOnTabletModeTransitionTest,
+       UpdatesScaleAndOpacity) {
+  // Enter tablet mode.
+  EnableTabletMode(true);
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
+
+  auto* const window =
+      GetAppListTestHelper()->GetAppListView()->GetWidget()->GetNativeWindow();
+  auto* const layer = window->layer();
+  const auto center_point = gfx::Rect(layer->size()).CenterPoint();
+  const auto no_transform = gfx::GetScaleTransform(center_point, 1.0f);
+  const auto scaled_down_transform =
+      gfx::GetScaleTransform(center_point, 0.92f);
+
+  // The layer is fully visible and without applied transform.
+  EXPECT_EQ(layer->opacity(), 1.0f);
+  EXPECT_EQ(layer->transform(), no_transform);
+  EXPECT_TRUE(window->IsVisible());
+
+  // Exit tablet mode.
+  EnableTabletMode(false);
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
+
+  // The layer is fully transparent, scaled down and the window is hidden.
+  EXPECT_EQ(layer->opacity(), 0.00f);
+  EXPECT_EQ(layer->transform(), scaled_down_transform);
+  EXPECT_FALSE(window->IsVisible());
+}
+
+TEST_F(AppListPresenterWithScaleAnimationOnTabletModeTransitionTest,
+       ExitingFromOverviewInClamshellModeShouldNotAffectFullscreenLauncher) {
+  EnsureAppListViewIsCached();
+
+  auto* const layer = GetAppListTestHelper()
+                          ->GetAppListView()
+                          ->GetWidget()
+                          ->GetNativeWindow()
+                          ->layer();
+  const auto expected_opacity = layer->opacity();
+  const auto expected_transform = layer->transform();
+
+  OverviewController* overview_controller = Shell::Get()->overview_controller();
+
+  EnterOverview();
+  EXPECT_TRUE(overview_controller->InOverviewSession());
+  ExitOverview();
+  EXPECT_FALSE(overview_controller->InOverviewSession());
+
+  // Layer's opacity and transform should stay the same.
+  EXPECT_EQ(layer->opacity(), expected_opacity);
+  EXPECT_EQ(layer->transform(), expected_transform);
+}
+
 }  // namespace ash
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 05da13f..fdbfb7e1 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -21,6 +21,7 @@
 #include "ash/app_list/views/paged_apps_grid_view.h"
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ash/public/cpp/metrics_util.h"
 #include "ash/shell.h"
@@ -499,9 +500,6 @@
 void AppListView::Show(AppListViewState preferred_state, bool is_side_shelf) {
   if (!time_shown_.has_value())
     time_shown_ = base::Time::Now();
-  // The opacity of the AppListView may have been manipulated by overview mode,
-  // so reset it before it is shown.
-  GetWidget()->GetLayer()->SetOpacity(1.0f);
   is_side_shelf_ = is_side_shelf;
 
   AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
@@ -730,10 +728,20 @@
         AppListState::kStateApps, !is_side_shelf_);
   }
 
-  if (target_state == AppListViewState::kClosed && is_side_shelf_) {
-    // Reset the search box to be shown again. This is done after the animation
-    // is complete normally, but there is no animation when |is_side_shelf_|.
-    search_box_view_->ClearSearchAndDeactivateSearchBox();
+  if (target_state == AppListViewState::kClosed) {
+    if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+      if (app_list_state_ == AppListViewState::kFullscreenSearch)
+        search_box_view_->ClearSearchAndDeactivateSearchBox();
+
+      auto* contents_view = app_list_main_view_->contents_view();
+      if (contents_view->IsShowingEmbeddedAssistantUI())
+        contents_view->ShowEmbeddedAssistantUI(false);
+    } else if (is_side_shelf_) {
+      // Reset the search box to be shown again. This is done after the
+      // animation is complete normally, but there is no animation when
+      // |is_side_shelf_|.
+      search_box_view_->ClearSearchAndDeactivateSearchBox();
+    }
   }
 }
 
@@ -1086,7 +1094,9 @@
   base::TimeDelta animation_duration =
       GetStateTransitionAnimationDuration(target_state);
 
-  ApplyBoundsAnimation(target_state, animation_duration);
+  if (!app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled())
+    ApplyBoundsAnimation(target_state, animation_duration);
+
   app_list_main_view_->contents_view()->OnAppListViewTargetStateChanged(
       target_state);
   app_list_main_view_->contents_view()->AnimateToViewState(target_state,
@@ -1413,6 +1423,8 @@
     case AppListViewState::kFullscreenSearch:
       return fullscreen_height;
     case AppListViewState::kClosed:
+      if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled())
+        return fullscreen_height;
       // Align the widget y with shelf y to avoid flicker in show animation. In
       // side shelf mode, the widget y is the top of work area because the
       // widget does not animate.
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc
index f0aa533..b76d98d 100644
--- a/ash/app_list/views/app_list_view_unittest.cc
+++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -33,8 +33,6 @@
 #include "ash/app_list/views/search_result_container_view.h"
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
-#include "ash/app_list/views/search_result_tile_item_view.h"
 #include "ash/app_list/views/search_result_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
@@ -633,12 +631,6 @@
     view_->Show(AppListViewState::kFullscreenAllApps, /*is_side_shelf=*/false);
   }
 
-  SearchResultTileItemListView* GetSearchResultTileItemListView() {
-    return contents_view()
-        ->search_result_page_view()
-        ->GetSearchResultTileItemListViewForTest();
-  }
-
   SearchResultListView* GetSearchResultListView() {
     return contents_view()
         ->search_result_page_view()
@@ -658,28 +650,18 @@
   }
 
   // Add search results for test on focus movement.
-  void SetUpSearchResults(int tile_results_num, int list_results_num) {
-    std::vector<std::pair<SearchResult::DisplayType, int>> result_types;
-    result_types.emplace_back(SearchResultDisplayType::kTile, tile_results_num);
-    result_types.emplace_back(SearchResultDisplayType::kList, list_results_num);
-
+  void SetUpSearchResults(int list_results_num) {
     SearchModel::SearchResults* results = GetSearchModel()->results();
     results->DeleteAll();
-    double display_score = result_types.size();
-    for (const auto& data : result_types) {
-      // Set the display score of the results in each group in decreasing order
-      // (so the earlier groups have higher display score, and therefore appear
-      // first).
-      display_score -= 0.5;
-      for (int i = 0; i < data.second; ++i) {
-        std::unique_ptr<TestSearchResult> result =
-            std::make_unique<TestSearchResult>();
-        result->set_display_type(data.first);
-        result->set_display_score(display_score);
-        result->SetTitle(u"Test");
-        result->set_best_match(true);
-        results->Add(std::move(result));
-      }
+
+    for (int i = 0; i < list_results_num; ++i) {
+      std::unique_ptr<TestSearchResult> result =
+          std::make_unique<TestSearchResult>();
+      result->set_display_type(SearchResultDisplayType::kList);
+      result->set_display_score(1);
+      result->SetTitle(u"Test");
+      result->set_best_match(true);
+      results->Add(std::move(result));
     }
 
     // Adding results will schedule Update().
@@ -1104,9 +1086,8 @@
   search_box_view()->search_box()->InsertText(
       u"test",
       ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-  constexpr int kTileResults = 3;
   constexpr int kListResults = 2;
-  SetUpSearchResults(kTileResults, kListResults);
+  SetUpSearchResults(kListResults);
 
   // Move focus to the first search result.
   SimulateKeyPress(ui::VKEY_TAB, false);
@@ -1153,7 +1134,7 @@
       u"test",
       ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   const int kListResults = 2;
-  SetUpSearchResults(0, kListResults);
+  SetUpSearchResults(kListResults);
   SearchResultListView* list_view = GetSearchResultListView();
 
   EXPECT_EQ(search_box_view()->search_box(), focused_view());
@@ -1161,28 +1142,15 @@
             contents_view()->search_result_page_view()->first_result_view());
   EXPECT_TRUE(list_view->GetResultViewAt(0)->selected());
 
-  // Populate both fake list results and tile results.
-  const int kTileResults = 3;
-  SetUpSearchResults(kTileResults, kListResults);
-  const std::vector<SearchResultTileItemView*>& tile_views =
-      GetSearchResultTileItemListView()->tile_views_for_test();
-  EXPECT_EQ(search_box_view()->search_box(), focused_view());
-  EXPECT_EQ(tile_views[0],
-            contents_view()->search_result_page_view()->first_result_view());
-  EXPECT_TRUE(tile_views[0]->selected());
-
   ResultSelectionController* selection_controller =
       contents_view()->search_result_page_view()->result_selection_controller();
 
-  // Ensures the |ResultSelectionController| selects the correct result
-  EXPECT_EQ(selection_controller->selected_result(), tile_views[0]);
-
-  // Ensure current highlighted result loses highlight on transition
-  SimulateKeyPress(ui::VKEY_TAB, false);
-  EXPECT_FALSE(tile_views[0]->selected());
+  // Ensures the |ResultSelectionController| selects the correct result.
+  EXPECT_EQ(selection_controller->selected_result(),
+            list_view->GetResultViewAt(0));
 
   // Clear up all search results.
-  SetUpSearchResults(0, 0);
+  SetUpSearchResults(0);
   EXPECT_EQ(search_box_view()->search_box(), focused_view());
   EXPECT_EQ(nullptr,
             contents_view()->search_result_page_view()->first_result_view());
@@ -1206,23 +1174,16 @@
       u"test",
       ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
   const int kListResults = 2;
-  SetUpSearchResults(0, kListResults);
+  SetUpSearchResults(kListResults);
   SimulateKeyPress(ui::VKEY_RETURN, false);
   EXPECT_EQ(1, GetOpenFirstSearchResultCount());
   EXPECT_EQ(1, GetTotalOpenSearchResultCount());
 
-  // Populate both fake list results and tile results. Then hit Enter key.
-  const int kTileResults = 3;
-  SetUpSearchResults(kTileResults, kListResults);
-  SimulateKeyPress(ui::VKEY_RETURN, false);
-  EXPECT_EQ(2, GetOpenFirstSearchResultCount());
-  EXPECT_EQ(2, GetTotalOpenSearchResultCount());
-
   // Clear up all search results. Then hit Enter key.
-  SetUpSearchResults(0, 0);
+  SetUpSearchResults(0);
   SimulateKeyPress(ui::VKEY_RETURN, false);
-  EXPECT_EQ(2, GetOpenFirstSearchResultCount());
-  EXPECT_EQ(2, GetTotalOpenSearchResultCount());
+  EXPECT_EQ(1, GetOpenFirstSearchResultCount());
+  EXPECT_EQ(1, GetTotalOpenSearchResultCount());
 }
 
 // Tests that search box becomes focused when it is activated.
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc
index aadacba..c79e83e 100644
--- a/ash/app_list/views/contents_view.cc
+++ b/ash/app_list/views/contents_view.cc
@@ -18,7 +18,6 @@
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
@@ -611,8 +610,13 @@
           ConvertRectToWidgetWithoutTransform(search_box_bounds));
   search_box->GetWidget()->SetBounds(search_rect);
 
-  const float search_box_opacity =
-      target_view_state() != AppListViewState::kClosed ? 1.0f : 0.0f;
+  float search_box_opacity;
+  if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+    search_box_opacity = 1.0f;
+  } else {
+    search_box_opacity =
+        target_view_state() != AppListViewState::kClosed ? 1.0f : 0.0f;
+  }
   search_box->layer()->SetOpacity(search_box_opacity);
 
   for (AppListPage* page : app_list_pages_) {
@@ -631,6 +635,12 @@
                                ? pagination_model_.transition().target_page
                                : pagination_model_.selected_page());
 
+  if (app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled()) {
+    last_target_view_state_ = target_view_state;
+    target_page_for_last_view_state_update_ = target_page;
+    return;
+  }
+
   // Animates layer's opacity.
   // |duration| - The default transition duration. The actual transition gets
   //     halved when animating to hidden state.
@@ -786,7 +796,9 @@
     AppListViewState view_state) const {
   switch (view_state) {
     case AppListViewState::kClosed:
-      return 0;
+      if (!app_list_features::IsAnimateScaleOnTabletModeTransitionEnabled())
+        return 0;
+      [[fallthrough]];
     case AppListViewState::kFullscreenAllApps:
     case AppListViewState::kFullscreenSearch:
       return apps_container_view_
diff --git a/ash/app_list/views/search_box_view_unittest.cc b/ash/app_list/views/search_box_view_unittest.cc
index 6dd1064..f3b34834 100644
--- a/ash/app_list/views/search_box_view_unittest.cc
+++ b/ash/app_list/views/search_box_view_unittest.cc
@@ -23,7 +23,6 @@
 #include "ash/app_list/views/search_box_view_delegate.h"
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/app_list/views/search_result_page_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_color_provider.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -604,19 +603,6 @@
   selection = GetResultSelectionController()->selected_result();
   EXPECT_EQ(u"testing", selection->result()->title());
 
-  // Tile containers are deprecated for productivity launcher.
-  if (!IsProductivityLauncherEnabled()) {
-    // Add a new result in a tile container - verify the selected result remains
-    // the same.
-    CreateSearchResultAt(0, ash::SearchResultDisplayType::kTile, 0.9,
-                         u"test tile", std::u16string());
-    // Finish results update.
-    base::RunLoop().RunUntilIdle();
-
-    selection = GetResultSelectionController()->selected_result();
-    EXPECT_EQ(u"testing", selection->result()->title());
-  }
-
   // Add a new result at the end, and verify the selection stays the same.
   CreateSearchResult(ash::SearchResultDisplayType::kList, 0.2,
                      u"testing almost", std::u16string());
@@ -627,35 +613,28 @@
 
   // Remove the result before the selected one, and verify the selection remains
   // the same.
-  results()->RemoveAt(IsProductivityLauncherEnabled() ? 0 : 1);
+  results()->RemoveAt(0);
   base::RunLoop().RunUntilIdle();
 
   selection = GetResultSelectionController()->selected_result();
   EXPECT_EQ(u"testing", selection->result()->title());
 
   // Result should be reset if the selected result is removed.
-  results()->RemoveAt(IsProductivityLauncherEnabled() ? 0 : 1);
+  results()->RemoveAt(0);
   base::RunLoop().RunUntilIdle();
 
   // Tile results are not created when testing productivity launcher.
   selection = GetResultSelectionController()->selected_result();
-  if (IsProductivityLauncherEnabled()) {
+
     EXPECT_EQ(u"testing almost", selection->result()->title());
 
     // New result can override the default selection.
     CreateSearchResultAt(0, ash::SearchResultDisplayType::kList, 1.0, u"test",
                          std::u16string());
-  } else {
-    EXPECT_EQ(u"test tile", selection->result()->title());
+    base::RunLoop().RunUntilIdle();
 
-    // New result can override the default selection.
-    CreateSearchResultAt(0, ash::SearchResultDisplayType::kTile, 1.0, u"test",
-                         std::u16string());
-  }
-  base::RunLoop().RunUntilIdle();
-
-  selection = GetResultSelectionController()->selected_result();
-  EXPECT_EQ(u"test", selection->result()->title());
+    selection = GetResultSelectionController()->selected_result();
+    EXPECT_EQ(u"test", selection->result()->title());
 }
 
 // Tests that the default selection is reset after resetting and reactivating
@@ -942,93 +921,39 @@
 // titles.
 TEST_P(SearchBoxViewAutocompleteTest,
        SearchBoxAutocompletesTopListResultTitle) {
-  // Search result tile tests are not relevant for productivity launcher.
-  if (IsProductivityLauncherEnabled())
-    return;
-
   SimulateQuery(u"he");
 
-  // Add two SearchResults, one tile and one list result. Initialize their title
-  // field to a non-empty string.
-  CreateSearchResult(ash::SearchResultDisplayType::kList, 1.0, u"hello list",
+  // Add two SearchResults. The higher ranked result should be selected by
+  // default and it's title should be autocompleted into the search box.
+  CreateSearchResult(ash::SearchResultDisplayType::kList, 2.0, u"hello list",
                      std::u16string());
-  CreateSearchResult(ash::SearchResultDisplayType::kTile, 0.5, u"hello tile",
+  CreateSearchResult(ash::SearchResultDisplayType::kList, 1.0, u"hello list2",
                      std::u16string());
   base::RunLoop().RunUntilIdle();
 
   ProcessAutocomplete();
-  EXPECT_EQ(view()->search_box()->GetText(), u"hello tile");
-  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo tile");
-}
-
-// Tests that autocomplete suggestions are consistent with top SearchResult tile
-// titles.
-TEST_P(SearchBoxViewAutocompleteTest,
-       SearchBoxAutocompletesTopTileResultTitle) {
-  // Search result tile tests are not relevant for productivity launcher.
-  if (IsProductivityLauncherEnabled())
-    return;
-
-  SimulateQuery(u"he");
-
-  // Add two SearchResults, one tile and one list result. Initialize their title
-  // field to a non-empty string.
-  CreateSearchResult(ash::SearchResultDisplayType::kTile, 1.0, u"hello tile",
-                     std::u16string());
-  CreateSearchResult(ash::SearchResultDisplayType::kList, 0.5, u"hello list",
-                     std::u16string());
+  EXPECT_EQ(view()->search_box()->GetText(), u"hello list");
+  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo list");
   base::RunLoop().RunUntilIdle();
-
-  ProcessAutocomplete();
-  EXPECT_EQ(view()->search_box()->GetText(), u"hello tile");
-  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo tile");
 }
 
 // Tests that autocomplete suggestions are consistent with top SearchResult list
 // details.
 TEST_P(SearchBoxViewAutocompleteTest,
        SearchBoxAutocompletesTopListResultDetails) {
-  // Search result tile tests are not relevant for productivity launcher.
-  if (IsProductivityLauncherEnabled())
-    return;
-
   SimulateQuery(u"he");
 
-  // Add two SearchResults, one tile and one list result. The tile should
-  // display first, despite having a lower score. Initialize their details field
-  // to a non-empty string.
+  // Add two SearchResults. The higher ranked result should be selected by
+  // default and it's title should be autocompleted into the search box.
+  CreateSearchResult(ash::SearchResultDisplayType::kList, 2.0, std::u16string(),
+                     u"hello list");
   CreateSearchResult(ash::SearchResultDisplayType::kList, 1.0, std::u16string(),
-                     u"hello list");
-  CreateSearchResult(ash::SearchResultDisplayType::kTile, 0.5, std::u16string(),
-                     u"hello tile");
+                     u"hello list2");
   base::RunLoop().RunUntilIdle();
 
   ProcessAutocomplete();
-  EXPECT_EQ(view()->search_box()->GetText(), u"hello tile");
-  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo tile");
-}
-
-// Tests that autocomplete suggestions are consistent with top SearchResult tile
-// details.
-TEST_P(SearchBoxViewAutocompleteTest,
-       SearchBoxAutocompletesTopTileResultDetails) {
-  // Search result tile tests are not relevant for productivity launcher.
-  if (IsProductivityLauncherEnabled())
-    return;
-
-  SimulateQuery(u"he");
-
-  // Add two SearchResults, one tile and one list result. Initialize their
-  // details field to a non-empty string.
-  CreateSearchResult(ash::SearchResultDisplayType::kTile, 1.0, std::u16string(),
-                     u"hello tile");
-  CreateSearchResult(ash::SearchResultDisplayType::kList, 0.5, std::u16string(),
-                     u"hello list");
-  base::RunLoop().RunUntilIdle();
-
-  ProcessAutocomplete();
-  EXPECT_EQ(view()->search_box()->GetText(), u"hello tile");
-  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo tile");
+  EXPECT_EQ(view()->search_box()->GetText(), u"hello list");
+  EXPECT_EQ(view()->search_box()->GetSelectedText(), u"llo list");
 }
 
 // Tests that SearchBoxView's textfield text does not autocomplete if the top
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc
index 51838ed5..92c29f2 100644
--- a/ash/app_list/views/search_result_page_view.cc
+++ b/ash/app_list/views/search_result_page_view.cc
@@ -18,7 +18,6 @@
 #include "ash/app_list/views/search_result_base_view.h"
 #include "ash/app_list/views/search_result_list_view.h"
 #include "ash/app_list/views/search_result_page_anchored_dialog.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_color_provider.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
@@ -61,19 +60,9 @@
 constexpr int kMinHeight = 440;
 constexpr int kWidth = 640;
 
-// The horizontal padding of the separator.
-constexpr int kSeparatorPadding = 12;
-constexpr int kSeparatorThickness = 1;
-
 // The height of the active search box in this page.
 constexpr int kActiveSearchBoxHeight = 56;
 
-// The spacing between search box bottom and separator line.
-// Add 1 pixel spacing so that the search bbox bottom will not paint over
-// the separator line drawn by SearchResultPageBackground in some scale factors
-// due to the round up.
-constexpr int kSearchBoxBottomSpacing = 1;
-
 // Minimum spacing between shelf and bottom of search box.
 constexpr int kSearchResultPageMinimumBottomMargin = 24;
 
@@ -133,64 +122,8 @@
   }
 };
 
-class SearchResultPageBackground : public views::Background {
- public:
-  SearchResultPageBackground() = default;
-  SearchResultPageBackground(const SearchResultPageBackground&) = delete;
-  SearchResultPageBackground& operator=(const SearchResultPageBackground&) =
-      delete;
-  ~SearchResultPageBackground() override = default;
-
- private:
-  // views::Background overrides:
-  void Paint(gfx::Canvas* canvas, views::View* view) const override {
-    canvas->DrawColor(get_color());
-    gfx::Rect bounds = view->GetContentsBounds();
-    if (bounds.height() <= kActiveSearchBoxHeight)
-      return;
-    // Draw a separator between SearchBoxView and SearchResultPageView.
-    bounds.set_y(kActiveSearchBoxHeight + kSearchBoxBottomSpacing);
-    bounds.set_height(kSeparatorThickness);
-    canvas->FillRect(bounds,
-                     view->GetColorProvider()->GetColor(
-                         AppListColorProvider::Get()->GetSeparatorColorId()));
-  }
-};
-
 }  // namespace
 
-class SearchResultPageView::HorizontalSeparator : public views::View {
- public:
-  explicit HorizontalSeparator(int preferred_width)
-      : preferred_width_(preferred_width) {
-    SetBorder(views::CreateEmptyBorder(
-        gfx::Insets::TLBR(0, kSeparatorPadding, 0, kSeparatorPadding)));
-  }
-
-  HorizontalSeparator(const HorizontalSeparator&) = delete;
-  HorizontalSeparator& operator=(const HorizontalSeparator&) = delete;
-
-  ~HorizontalSeparator() override = default;
-
-  // views::View overrides:
-  const char* GetClassName() const override { return "HorizontalSeparator"; }
-
-  gfx::Size CalculatePreferredSize() const override {
-    return gfx::Size(preferred_width_, kSeparatorThickness);
-  }
-
-  void OnPaint(gfx::Canvas* canvas) override {
-    gfx::Rect rect = GetContentsBounds();
-    canvas->FillRect(rect,
-                     GetColorProvider()->GetColor(
-                         AppListColorProvider::Get()->GetSeparatorColorId()));
-    View::OnPaint(canvas);
-  }
-
- private:
-  const int preferred_width_;
-};
-
 SearchResultPageView::SearchResultPageView() : contents_view_(new views::View) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
@@ -204,7 +137,7 @@
   // Hides this view behind the search box by using the same color and
   // background border corner radius. All child views' background should be
   // set transparent so that the rounded corner is not overwritten.
-  SetBackground(std::make_unique<SearchResultPageBackground>());
+  SetBackground(views::CreateSolidBackground(SK_ColorTRANSPARENT));
   if (features::IsProductivityLauncherEnabled()) {
     layer()->SetBackgroundBlur(ColorProvider::kBackgroundBlurSigma);
     layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
@@ -216,16 +149,14 @@
   // App list bubble search page has its own scroller and result selection
   // controller so we do not need to construct new ones here.
   if (features::IsProductivityLauncherEnabled()) {
-    contents_view_->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
-        kActiveSearchBoxHeight + kSearchBoxBottomSpacing + kSeparatorThickness,
-        0, 0, 0)));
+    contents_view_->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets::TLBR(kActiveSearchBoxHeight, 0, 0, 0)));
     AddChildView(contents_view_);
   } else {
     auto scroller = std::make_unique<views::ScrollView>();
     // Leaves a placeholder area for the search box and the separator below it.
-    scroller->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
-        kActiveSearchBoxHeight + kSearchBoxBottomSpacing + kSeparatorThickness,
-        0, 0, 0)));
+    scroller->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets::TLBR(kActiveSearchBoxHeight, 0, 0, 0)));
     scroller->SetDrawOverflowIndicator(false);
     scroller->SetContents(base::WrapUnique(contents_view_));
     // Setting clip height is necessary to make ScrollView take into account its
@@ -274,11 +205,6 @@
         std::make_unique<SearchResultPageDialogController>(this);
     privacy_container_view_ = AddSearchResultContainerView(
         std::make_unique<PrivacyContainerView>(view_delegate));
-    search_result_tile_item_list_view_ = AddSearchResultContainerView(
-        std::make_unique<SearchResultTileItemListView>(
-            search_box_view->search_box(), view_delegate));
-    result_lists_separator_ = contents_view_->AddChildView(
-        std::make_unique<HorizontalSeparator>(bounds().width()));
     // productivity_launcher_index is not set as the feature is not enabled.
     search_result_list_view_ =
         AddSearchResultContainerView(std::make_unique<SearchResultListView>(
@@ -327,8 +253,7 @@
   int adjusted_height = std::min(
       std::max(kMinHeight,
                productivity_launcher_search_view_->TabletModePreferredHeight() +
-                   kActiveSearchBoxHeight + kSearchBoxBottomSpacing +
-                   kSeparatorThickness +
+                   kActiveSearchBoxHeight +
                    kExpandedSearchBoxCornerRadiusForProductivityLauncher),
       AppListPage::contents_view()->height());
   return gfx::Size(kWidth, adjusted_height);
@@ -424,10 +349,6 @@
           should_show_page_view || should_show_container_view;
     }
 
-    result_lists_separator_->SetVisible(
-        search_result_tile_item_list_view_->num_results() &&
-        search_result_list_view_->num_results() &&
-        ShouldShowSearchResultView());
     AppListPage::contents_view()
         ->GetSearchBoxView()
         ->OnResultContainerVisibilityChanged(should_show_page_view);
@@ -766,11 +687,6 @@
   return privacy_container_view_;
 }
 
-SearchResultTileItemListView*
-SearchResultPageView::GetSearchResultTileItemListViewForTest() {
-  return search_result_tile_item_list_view_;
-}
-
 SearchResultListView* SearchResultPageView::GetSearchResultListViewForTest() {
   return search_result_list_view_;
 }
diff --git a/ash/app_list/views/search_result_page_view.h b/ash/app_list/views/search_result_page_view.h
index 3b69eb8b..55ae04f5 100644
--- a/ash/app_list/views/search_result_page_view.h
+++ b/ash/app_list/views/search_result_page_view.h
@@ -27,7 +27,6 @@
 class SearchBoxView;
 class SearchResultBaseView;
 class SearchResultListView;
-class SearchResultTileItemListView;
 class SearchResultPageAnchoredDialog;
 class SystemShadow;
 
@@ -126,7 +125,6 @@
   void UpdateResultContainersVisibility();
 
   PrivacyContainerView* GetPrivacyContainerViewForTest();
-  SearchResultTileItemListView* GetSearchResultTileItemListViewForTest();
   SearchResultListView* GetSearchResultListViewForTest();
 
  private:
@@ -134,9 +132,6 @@
   // launcher.
   enum class SearchResultsState { kClosed, kActive, kExpanded };
 
-  // Separator between SearchResultContainerView.
-  class HorizontalSeparator;
-
   // Passed to |result_selection_controller_| as a callback that gets called
   // when the currently selected result changes.
   // Ensures that |scroller_| visible rect contains the newly selected result.
@@ -209,15 +204,10 @@
   // Search result containers shown within search results page (and added to
   // `result_container_views_`).
   PrivacyContainerView* privacy_container_view_ = nullptr;
-  SearchResultTileItemListView* search_result_tile_item_list_view_ = nullptr;
   SearchResultListView* search_result_list_view_ = nullptr;
   // Search result container used for productivity launcher.
   ProductivityLauncherSearchView* productivity_launcher_search_view_ = nullptr;
 
-  // Separator view shown between search result tile item list and search
-  // results list.
-  HorizontalSeparator* result_lists_separator_ = nullptr;
-
   // View containing SearchCardView instances. Owned by view hierarchy.
   views::View* const contents_view_;
 
diff --git a/ash/app_list/views/search_result_page_view_unittest.cc b/ash/app_list/views/search_result_page_view_unittest.cc
index a6cce84..5ec227a 100644
--- a/ash/app_list/views/search_result_page_view_unittest.cc
+++ b/ash/app_list/views/search_result_page_view_unittest.cc
@@ -15,7 +15,6 @@
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/app_list/views/contents_view.h"
 #include "ash/app_list/views/search_result_list_view.h"
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
 #include "ash/app_list/views/search_result_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -56,8 +55,6 @@
     ContentsView* contents_view =
         app_list_view_->app_list_main_view()->contents_view();
     view_ = contents_view->search_result_page_view();
-    tile_list_view_ = contents_view->search_result_page_view()
-                          ->GetSearchResultTileItemListViewForTest();
     list_view_ = contents_view->search_result_page_view()
                      ->GetSearchResultListViewForTest();
   }
@@ -69,9 +66,6 @@
  protected:
   SearchResultPageView* view() const { return view_; }
 
-  SearchResultTileItemListView* tile_list_view() const {
-    return tile_list_view_;
-  }
   SearchResultListView* list_view() const { return list_view_; }
 
   SearchModel::SearchResults* GetResults() const {
@@ -82,8 +76,6 @@
   TestAppListColorProvider color_provider_;  // Needed by AppListView.
   AppListView* app_list_view_ = nullptr;  // Owned by native widget.
   SearchResultPageView* view_ = nullptr;  // Owned by views hierarchy.
-  SearchResultTileItemListView* tile_list_view_ =
-      nullptr;                                 // Owned by views hierarchy.
   SearchResultListView* list_view_ = nullptr;  // Owned by views hierarchy.
   std::unique_ptr<AppListTestViewDelegate> delegate_;
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -114,13 +106,11 @@
   // Adding results will schedule Update().
   RunPendingMessages();
 
-  ASSERT_GE(view()->result_container_views().size(), 3u);
+  ASSERT_GE(view()->result_container_views().size(), 2u);
   // Privacy container is hidden.
   EXPECT_FALSE(view()->result_container_views()[0]->GetVisible());
-  EXPECT_TRUE(tile_list_view()->GetVisible());
-  EXPECT_EQ(tile_list_view(), view()->result_container_views()[1]);
   EXPECT_TRUE(list_view()->GetVisible());
-  EXPECT_EQ(list_view(), view()->result_container_views()[2]);
+  EXPECT_EQ(list_view(), view()->result_container_views()[1]);
 
   // Change the relevance of the tile result to be lower than list results. The
   // tile container should still be displayed first.
@@ -131,9 +121,7 @@
 
   // Privacy container is hidden.
   EXPECT_FALSE(view()->result_container_views()[0]->GetVisible());
-  EXPECT_EQ(tile_list_view(), view()->result_container_views()[1]);
-  EXPECT_TRUE(tile_list_view()->GetVisible());
-  EXPECT_EQ(list_view(), view()->result_container_views()[2]);
+  EXPECT_EQ(list_view(), view()->result_container_views()[1]);
   EXPECT_TRUE(list_view()->GetVisible());
 }
 
@@ -150,7 +138,6 @@
   // Adding results will schedule Update().
   RunPendingMessages();
 
-  EXPECT_TRUE(tile_list_view()->GetVisible());
   EXPECT_FALSE(list_view()->GetVisible());
 }
 
@@ -168,7 +155,6 @@
   RunPendingMessages();
 
   EXPECT_TRUE(list_view()->GetVisible());
-  EXPECT_FALSE(tile_list_view()->GetVisible());
 }
 
 }  // namespace test
diff --git a/ash/app_list/views/search_result_tile_item_list_view.cc b/ash/app_list/views/search_result_tile_item_list_view.cc
deleted file mode 100644
index 6f5bd45..0000000
--- a/ash/app_list/views/search_result_tile_item_list_view.cc
+++ /dev/null
@@ -1,368 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <memory>
-#include <set>
-#include <string>
-
-#include "ash/app_list/app_list_model_provider.h"
-#include "ash/app_list/app_list_util.h"
-#include "ash/app_list/app_list_view_delegate.h"
-#include "ash/app_list/model/search/search_result.h"
-#include "ash/app_list/views/search_result_page_view.h"
-#include "ash/public/cpp/app_list/app_list_color_provider.h"
-#include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/app_list/app_list_notifier.h"
-#include "ash/public/cpp/app_list/app_list_types.h"
-#include "ash/public/cpp/app_list/internal_app_id_constants.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/i18n/rtl.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/stl_util.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/separator.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-
-namespace {
-
-// Layout constants used when fullscreen app list feature is enabled.
-constexpr int kItemListVerticalSpacing = 16;
-constexpr int kItemListHorizontalSpacing = 12;
-constexpr int kBetweenItemSpacing = 8;
-constexpr int kSeparatorLeftRightPadding = 4;
-constexpr int kSeparatorHeight = 46;
-constexpr int kSeparatorTopPadding = 10;
-
-// The Delay before recording play store app results impression, i.e., if the
-// play store results are displayed less than the duration, we assume user
-// won't have chance to see them clearly and click on them, and wont' log
-// the impression.
-constexpr int kPlayStoreImpressionDelayInMs = 1000;
-
-// Returns true if the search result is an installable app.
-bool IsResultAnInstallableApp(SearchResult* result) {
-  SearchResult::ResultType result_type = result->result_type();
-  return result_type == AppListSearchResultType::kPlayStoreApp ||
-         result_type == AppListSearchResultType::kPlayStoreReinstallApp ||
-         result_type == AppListSearchResultType::kInstantApp;
-}
-
-bool IsPlayStoreApp(SearchResult* result) {
-  return result->result_type() == AppListSearchResultType::kPlayStoreApp;
-}
-
-}  // namespace
-
-SearchResultTileItemListView::SearchResultTileItemListView(
-    views::Textfield* search_box,
-    AppListViewDelegate* view_delegate)
-    : SearchResultContainerView(view_delegate),
-      search_box_(search_box),
-      is_app_reinstall_recommendation_enabled_(
-          app_list_features::IsAppReinstallZeroStateEnabled()),
-      max_search_result_tiles_(
-          SharedAppListConfig::instance().max_search_result_tiles()) {
-  layout_ = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kHorizontal,
-      gfx::Insets::VH(kItemListVerticalSpacing, kItemListHorizontalSpacing),
-      kBetweenItemSpacing));
-  for (size_t i = 0; i < max_search_result_tiles_; ++i) {
-    views::Separator* separator =
-        AddChildView(std::make_unique<views::Separator>());
-    separator->SetVisible(false);
-    separator->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
-        kSeparatorTopPadding, kSeparatorLeftRightPadding,
-        SharedAppListConfig::instance().search_tile_height() - kSeparatorHeight,
-        kSeparatorLeftRightPadding)));
-    separator->SetColorId(AppListColorProvider::Get()->GetSeparatorColorId());
-    separator_views_.push_back(separator);
-    layout_->SetFlexForView(separator, 0);
-
-    SearchResultTileItemView* tile_item =
-        AddChildView(std::make_unique<SearchResultTileItemView>(view_delegate));
-    tile_item->set_index_in_container(i);
-    tile_views_.push_back(tile_item);
-    AddObservedResultView(tile_item);
-  }
-
-  // Tile items are shown horizontally.
-  set_horizontally_traversable(true);
-}
-
-SearchResultTileItemListView::~SearchResultTileItemListView() = default;
-
-SearchResultTileItemView* SearchResultTileItemListView::GetResultViewAt(
-    size_t index) {
-  DCHECK(index >= 0 && index < tile_views_.size());
-  return tile_views_[index];
-}
-
-int SearchResultTileItemListView::DoUpdate() {
-  if (!GetWidget() || !GetWidget()->IsVisible() || !GetWidget()->IsActive()) {
-    for (size_t i = 0; i < max_search_result_tiles_; ++i) {
-      SearchResultBaseView* result_view = GetResultViewAt(i);
-      result_view->SetResult(nullptr);
-      result_view->SetVisible(false);
-    }
-    return 0;
-  }
-
-  std::vector<SearchResult*> display_results = GetDisplayResults();
-
-  std::set<std::string> result_id_removed, result_id_added;
-  bool is_result_an_installable_app = false;
-  bool is_previous_result_installable_app = false;
-  int installed_app_index = -1;
-  int playstore_app_index = -1;
-  int app_group_index = -1;
-  bool found_playstore_results = false;
-
-  for (size_t i = 0; i < max_search_result_tiles_; ++i) {
-    // If the current result at i exists, wants to be notified and is a
-    // different id, notify it that it is being hidden.
-    SearchResult* current_result = tile_views_[i]->result();
-    if (current_result != nullptr) {
-      result_id_removed.insert(current_result->id());
-    }
-
-    if (i >= display_results.size()) {
-      separator_views_[i]->SetVisible(false);
-
-      GetResultViewAt(i)->SetResult(nullptr);
-      continue;
-    }
-
-    SearchResult* item = display_results[i];
-    if (IsPlayStoreApp(item)) {
-      ++playstore_app_index;
-      app_group_index = playstore_app_index;
-      found_playstore_results = true;
-    } else if (item->result_type() ==
-               AppListSearchResultType::kPlayStoreReinstallApp) {
-      app_group_index = playstore_app_index;
-    } else {
-      ++installed_app_index;
-      app_group_index = installed_app_index;
-    }
-
-    GetResultViewAt(i)->SetResult(item);
-    GetResultViewAt(i)->set_group_index_in_container_view(app_group_index);
-    result_id_added.insert(item->id());
-    is_result_an_installable_app = IsResultAnInstallableApp(item);
-
-    if (i > 0 &&
-        (is_result_an_installable_app != is_previous_result_installable_app)) {
-      // Add a separator between installed apps and installable apps.
-      // This assumes the search results are already separated in groups for
-      // installed and installable apps.
-      separator_views_[i]->SetVisible(true);
-    } else {
-      separator_views_[i]->SetVisible(false);
-    }
-
-    is_previous_result_installable_app = is_result_an_installable_app;
-  }
-
-  auto* notifier = view_delegate()->GetNotifier();
-  if (notifier) {
-    std::vector<AppListNotifier::Result> notifier_results;
-    for (const auto* result : display_results)
-      notifier_results.emplace_back(result->id(), result->metrics_type());
-    notifier->NotifyResultsUpdated(SearchResultDisplayType::kTile,
-                                   notifier_results);
-  }
-
-  // Track play store results and start the timer for recording their impression
-  // UMA metrics.
-  std::u16string user_typed_query = GetUserTypedQuery();
-  if (found_playstore_results && user_typed_query != recent_playstore_query_) {
-    recent_playstore_query_ = user_typed_query;
-    playstore_impression_timer_.Stop();
-    playstore_impression_timer_.Start(
-        FROM_HERE, base::Milliseconds(kPlayStoreImpressionDelayInMs), this,
-        &SearchResultTileItemListView::OnPlayStoreImpressionTimer);
-    // Set the starting time in result view for play store results.
-    base::TimeTicks result_display_start = base::TimeTicks::Now();
-    for (size_t i = 0; i < max_search_result_tiles_; ++i) {
-      SearchResult* result = GetResultViewAt(i)->result();
-      if (result && IsPlayStoreApp(result)) {
-        GetResultViewAt(i)->set_result_display_start_time(result_display_start);
-      }
-    }
-  } else if (!found_playstore_results) {
-    playstore_impression_timer_.Stop();
-  }
-
-  return display_results.size();
-}
-
-std::vector<SearchResult*> SearchResultTileItemListView::GetDisplayResults() {
-  std::u16string raw_query = search_box_->GetText();
-  std::u16string query;
-  base::TrimWhitespace(raw_query, base::TRIM_ALL, &query);
-
-  // We ask for |max_search_result_tiles_| policy tile results first,
-  // then add them to their preferred position in the tile list if found.
-  // Note: Policy tile provides a mechanism to display the result tile at the
-  // preferred position recommended by display_index() property of the search
-  // result. This is what policy referred to. It has nothing to do with
-  // Enterprise policy.
-  auto policy_tiles_filter =
-      base::BindRepeating([](const SearchResult& r) -> bool {
-        return r.display_index() != SearchResultDisplayIndex::kUndefined &&
-               r.display_type() == SearchResultDisplayType::kTile &&
-               r.is_recommendation();
-      });
-  std::vector<SearchResult*> policy_tiles_results =
-      is_app_reinstall_recommendation_enabled_ && query.empty()
-          ? SearchModel::FilterSearchResultsByFunction(
-                results(), policy_tiles_filter, max_search_result_tiles_)
-          : std::vector<SearchResult*>();
-
-  SearchResult::DisplayType display_type = SearchResultDisplayType::kTile;
-  size_t display_num = max_search_result_tiles_ - policy_tiles_results.size();
-
-  // Do not display the repeat reinstall results or continue reading app in the
-  // search result list.
-  auto non_policy_tiles_filter = base::BindRepeating(
-      [](const SearchResult::DisplayType& display_type,
-         const SearchResult& r) -> bool {
-        return r.display_type() == display_type &&
-               r.result_type() !=
-                   AppListSearchResultType::kPlayStoreReinstallApp &&
-               r.id() != kInternalAppIdContinueReading;
-      },
-      display_type);
-  std::vector<SearchResult*> display_results =
-      SearchModel::FilterSearchResultsByFunction(
-          results(), non_policy_tiles_filter, display_num);
-
-  // Policy tile results will be appended to the final tiles list
-  // based on their specified index. If the requested index is out of
-  // range of the current list, the result will be appended to the back.
-  std::sort(policy_tiles_results.begin(), policy_tiles_results.end(),
-            [](const SearchResult* r1, const SearchResult* r2) -> bool {
-              return r1->display_index() < r2->display_index();
-            });
-
-  const SearchResultDisplayIndex display_results_last_index =
-      static_cast<SearchResultDisplayIndex>(display_results.size() - 1);
-  for (auto* result : policy_tiles_results) {
-    const SearchResultDisplayIndex result_index = result->display_index();
-    if (result_index > display_results_last_index) {
-      display_results.emplace_back(result);
-    } else {
-      // TODO(newcomer): Remove this check once we determine the root cause for
-      // https://crbug.com/992344.
-      CHECK_GE(result_index, SearchResultDisplayIndex::kFirstIndex);
-      display_results.emplace(display_results.begin() + result_index, result);
-    }
-  }
-
-  return display_results;
-}
-
-std::u16string SearchResultTileItemListView::GetUserTypedQuery() {
-  std::u16string search_box_text = search_box_->GetText();
-  gfx::Range range = search_box_->GetSelectedRange();
-  std::u16string raw_query = range.is_empty()
-                                 ? search_box_text
-                                 : search_box_text.substr(0, range.start());
-  std::u16string query;
-  base::TrimWhitespace(raw_query, base::TRIM_ALL, &query);
-  return query;
-}
-
-void SearchResultTileItemListView::OnPlayStoreImpressionTimer() {
-  size_t playstore_app_num = 0;
-  for (const auto* tile_view : tile_views_) {
-    SearchResult* result = tile_view->result();
-    if (result == nullptr)
-      continue;
-    if (IsPlayStoreApp(result))
-      ++playstore_app_num;
-  }
-
-  // Log the UMA metrics of play store impression.
-  base::RecordAction(
-      base::UserMetricsAction("AppList_ShowPlayStoreQueryResults"));
-
-  DCHECK_LE(playstore_app_num, max_search_result_tiles_);
-  UMA_HISTOGRAM_EXACT_LINEAR("Apps.AppListPlayStoreSearchAppsDisplayed",
-                             playstore_app_num, max_search_result_tiles_);
-}
-
-void SearchResultTileItemListView::CleanUpOnViewHide() {
-  playstore_impression_timer_.Stop();
-  recent_playstore_query_.clear();
-}
-
-const char* SearchResultTileItemListView::GetClassName() const {
-  return "SearchResultTileItemListView";
-}
-
-void SearchResultTileItemListView::Layout() {
-  const bool flex = GetContentsBounds().width() < GetPreferredSize().width();
-  layout_->SetDefaultFlex(flex ? 1 : 0);
-  layout_->set_between_child_spacing(flex ? 1 : kBetweenItemSpacing);
-
-  views::View::Layout();
-}
-
-void SearchResultTileItemListView::OnShownChanged() {
-  SearchResultContainerView::OnShownChanged();
-  for (const auto* tile_view : tile_views_) {
-    SearchResult* result = tile_view->result();
-    if (result == nullptr) {
-      continue;
-    }
-  }
-}
-
-void SearchResultTileItemListView::OnThemeChanged() {
-  SearchResultContainerView::OnThemeChanged();
-
-  const auto parent_background_color =
-      AppListColorProvider::Get()->GetSearchBoxCardBackgroundColor(GetWidget());
-
-  for (auto* tile_view : tile_views_)
-    tile_view->SetParentBackgroundColor(parent_background_color);
-}
-
-void SearchResultTileItemListView::VisibilityChanged(View* starting_from,
-                                                     bool is_visible) {
-  SearchResultContainerView::VisibilityChanged(starting_from, is_visible);
-  // We only do this work when is_visible is false, since this is how we
-  // receive the event. We filter and only run when shown.
-  if (is_visible && shown()) {
-    return;
-  }
-
-  CleanUpOnViewHide();
-
-  for (const auto* tile_view : tile_views_) {
-    SearchResult* result = tile_view->result();
-    if (result == nullptr) {
-      continue;
-    }
-  }
-}
-
-}  // namespace ash
diff --git a/ash/app_list/views/search_result_tile_item_list_view.h b/ash/app_list/views/search_result_tile_item_list_view.h
deleted file mode 100644
index 886c14c..0000000
--- a/ash/app_list/views/search_result_tile_item_list_view.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_LIST_VIEW_H_
-#define ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_LIST_VIEW_H_
-
-#include <vector>
-
-#include "ash/app_list/views/search_result_container_view.h"
-#include "ash/app_list/views/search_result_tile_item_view.h"
-#include "base/timer/timer.h"
-
-namespace views {
-class BoxLayout;
-class Separator;
-class Textfield;
-}  // namespace views
-
-namespace ash {
-
-class AppListViewDelegate;
-
-// Displays a list of SearchResultTileItemView.
-class ASH_EXPORT SearchResultTileItemListView
-    : public SearchResultContainerView {
- public:
-  SearchResultTileItemListView(views::Textfield* search_box,
-                               AppListViewDelegate* view_delegate);
-  SearchResultTileItemListView(const SearchResultTileItemListView&) = delete;
-  SearchResultTileItemListView& operator=(const SearchResultTileItemListView&) =
-      delete;
-  ~SearchResultTileItemListView() override;
-
-  // Overridden from SearchResultContainerView:
-  SearchResultTileItemView* GetResultViewAt(size_t index) override;
-
-  // Overridden from views::View:
-  const char* GetClassName() const override;
-  void Layout() override;
-
-  const std::vector<SearchResultTileItemView*>& tile_views_for_test() const {
-    return tile_views_;
-  }
-
-  // Overridden from SearchResultContainerView:
-  void OnShownChanged() override;
-  void OnThemeChanged() override;
-
- protected:
-  // View overrides:
-  void VisibilityChanged(View* starting_from, bool is_visible) override;
-
- private:
-  // Overridden from SearchResultContainerView:
-  int DoUpdate() override;
-
-  std::vector<SearchResult*> GetDisplayResults();
-
-  std::u16string GetUserTypedQuery();
-
-  void OnPlayStoreImpressionTimer();
-
-  // Cleans up when the view is hid due to closing the suggestion widow
-  // or closing the launcher.
-  void CleanUpOnViewHide();
-
-  std::vector<SearchResultTileItemView*> tile_views_;
-
-  std::vector<views::Separator*> separator_views_;
-
-  // Owned by the views hierarchy.
-  views::Textfield* search_box_ = nullptr;
-  views::BoxLayout* layout_ = nullptr;
-
-  std::u16string recent_playstore_query_;
-
-  base::OneShotTimer playstore_impression_timer_;
-
-  const bool is_app_reinstall_recommendation_enabled_;
-
-  const size_t max_search_result_tiles_;
-};
-
-}  // namespace ash
-
-#endif  // ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_LIST_VIEW_H_
diff --git a/ash/app_list/views/search_result_tile_item_list_view_unittest.cc b/ash/app_list/views/search_result_tile_item_list_view_unittest.cc
deleted file mode 100644
index 036c87b..0000000
--- a/ash/app_list/views/search_result_tile_item_list_view_unittest.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/app_list/views/search_result_tile_item_list_view.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "ash/app_list/app_list_test_view_delegate.h"
-#include "ash/app_list/model/app_list_model.h"
-#include "ash/app_list/model/search/test_search_result.h"
-#include "ash/app_list/views/search_result_tile_item_view.h"
-#include "ash/app_list/views/search_result_view.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/test/test_app_list_color_provider.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/test/widget_test.h"
-
-namespace ash {
-
-namespace {
-constexpr size_t kInstalledApps = 4;
-constexpr size_t kPlayStoreApps = 2;
-constexpr size_t kRecommendedApps = 1;
-
-// used to test when multiple chips with specified display
-// indexes have been added
-constexpr size_t kRecommendedAppsWithDisplayIndex = 3;
-}  // namespace
-
-class SearchResultTileItemListViewTest
-    : public views::test::WidgetTest,
-      public ::testing::WithParamInterface<std::pair<bool, bool>> {
- public:
-  SearchResultTileItemListViewTest() = default;
-
-  SearchResultTileItemListViewTest(const SearchResultTileItemListViewTest&) =
-      delete;
-  SearchResultTileItemListViewTest& operator=(
-      const SearchResultTileItemListViewTest&) = delete;
-
-  ~SearchResultTileItemListViewTest() override = default;
-
-  // Overridden from testing::Test:
-  void SetUp() override {
-    views::test::WidgetTest::SetUp();
-    widget_ = CreateTopLevelPlatformWidget();
-  }
-
-  void TearDown() override {
-    view_.reset();
-    widget_->CloseNow();
-    views::test::WidgetTest::TearDown();
-  }
-
- protected:
-  void CreateSearchResultTileItemListView() {
-    scoped_feature_list_.InitWithFeatureState(
-        app_list_features::kEnableAppReinstallZeroState,
-        IsReinstallAppRecommendationEnabled());
-
-    // Sets up the views.
-    textfield_ = std::make_unique<views::Textfield>();
-    view_ = std::make_unique<SearchResultTileItemListView>(textfield_.get(),
-                                                           &view_delegate_);
-    widget_->SetBounds(gfx::Rect(0, 0, 300, 200));
-    widget_->GetContentsView()->AddChildView(view_.get());
-    widget_->Show();
-    view_->SetResults(GetResults());
-  }
-
-  bool IsReinstallAppRecommendationEnabled() const { return GetParam().first; }
-
-  SearchResultTileItemListView* view() { return view_.get(); }
-
-  SearchModel::SearchResults* GetResults() {
-    return AppListModelProvider::Get()->search_model()->results();
-  }
-
-  void SetUpSearchResults() {
-    SearchModel::SearchResults* results = GetResults();
-
-    // Populate results for installed applications.
-    for (size_t i = 0; i < kInstalledApps; ++i) {
-      std::unique_ptr<TestSearchResult> result =
-          std::make_unique<TestSearchResult>();
-      result->set_result_id("InstalledApp " + base::NumberToString(i));
-      result->set_display_type(SearchResultDisplayType::kTile);
-      result->set_result_type(AppListSearchResultType::kInstalledApp);
-      result->SetTitle(u"InstalledApp " + base::NumberToString16(i));
-      results->Add(std::move(result));
-    }
-
-    // Populate results for Play Store search applications.
-    for (size_t i = 0; i < kPlayStoreApps; ++i) {
-      std::unique_ptr<TestSearchResult> result =
-          std::make_unique<TestSearchResult>();
-      result->set_result_id("PlayStoreApp " + base::NumberToString(i));
-      result->set_display_type(SearchResultDisplayType::kTile);
-      result->set_result_type(AppListSearchResultType::kPlayStoreApp);
-      result->SetTitle(u"PlayStoreApp " + base::NumberToString16(i));
-      result->SetRating(1 + i);
-      result->SetFormattedPrice(u"Price " + base::NumberToString16(i));
-      results->Add(std::move(result));
-    }
-
-    if (IsReinstallAppRecommendationEnabled()) {
-      for (size_t i = 0; i < kRecommendedApps; ++i) {
-        std::unique_ptr<TestSearchResult> result =
-            std::make_unique<TestSearchResult>();
-        result->set_result_id("RecommendedApp " + base::NumberToString(i));
-        result->set_display_type(SearchResultDisplayType::kTile);
-        result->set_is_recommendation(true);
-        result->set_result_type(
-            AppListSearchResultType::kPlayStoreReinstallApp);
-        result->set_display_index(SearchResultDisplayIndex::kSixthIndex);
-        result->SetTitle(u"RecommendedApp " + base::NumberToString16(i));
-        result->SetRating(1 + i);
-        results->Add(std::move(result));
-      }
-    }
-
-    // Adding results calls SearchResultContainerView::ScheduleUpdate().
-    // It will post a delayed task to update the results and relayout.
-    RunPendingMessages();
-  }
-
-  void SetUpSearchResultsWithMultipleDisplayIndexesRequested() {
-    SearchModel::SearchResults* results = GetResults();
-
-    // Populate results for installed applications.
-    for (size_t i = 0; i < kInstalledApps; ++i) {
-      std::unique_ptr<TestSearchResult> result =
-          std::make_unique<TestSearchResult>();
-      result->set_result_id("InstalledApp " + base::NumberToString(i));
-      result->set_display_type(SearchResultDisplayType::kTile);
-      result->set_result_type(AppListSearchResultType::kInstalledApp);
-      result->SetTitle(u"InstalledApp " + base::NumberToString16(i));
-      results->Add(std::move(result));
-    }
-
-    // Populate results for Play Store search applications.
-    for (size_t i = 0; i < kPlayStoreApps; ++i) {
-      std::unique_ptr<TestSearchResult> result =
-          std::make_unique<TestSearchResult>();
-      result->set_result_id("PlayStoreApp " + base::NumberToString(i));
-      result->set_display_type(SearchResultDisplayType::kTile);
-      result->set_result_type(AppListSearchResultType::kPlayStoreApp);
-      result->SetTitle(u"PlayStoreApp " + base::NumberToString16(i));
-      result->SetRating(1 + i);
-      result->SetFormattedPrice(u"Price " + base::NumberToString16(i));
-      results->Add(std::move(result));
-    }
-
-    const SearchResultDisplayIndex
-        display_indexes[kRecommendedAppsWithDisplayIndex] = {
-            SearchResultDisplayIndex::kFourthIndex,
-            SearchResultDisplayIndex::kFifthIndex,
-            SearchResultDisplayIndex::kSixthIndex,
-        };
-
-    if (IsReinstallAppRecommendationEnabled()) {
-      for (size_t i = 0; i < kRecommendedAppsWithDisplayIndex; ++i) {
-        std::unique_ptr<TestSearchResult> result =
-            std::make_unique<TestSearchResult>();
-        result->set_result_id("RecommendedApp " + base::NumberToString(i));
-        result->set_display_type(SearchResultDisplayType::kTile);
-        result->set_is_recommendation(true);
-        result->set_result_type(
-            AppListSearchResultType::kPlayStoreReinstallApp);
-        result->set_display_index(display_indexes[i]);
-        result->SetTitle(u"RecommendedApp " + base::NumberToString16(i));
-        result->SetRating(1 + i);
-        results->AddAt(display_indexes[i], std::move(result));
-      }
-    }
-
-    // Adding results calls SearchResultContainerView::ScheduleUpdate().
-    // It will post a delayed task to update the results and relayout.
-    RunPendingMessages();
-  }
-
-  size_t GetOpenResultCount(int ranking) {
-    return view_delegate_.open_search_result_counts()[ranking];
-  }
-
-  void ResetOpenResultCount() {
-    view_delegate_.open_search_result_counts().clear();
-  }
-
-  size_t GetResultCount() const { return view_->num_results(); }
-
- private:
-  TestAppListColorProvider color_provider_;  // Needed by AppListView.
-  test::AppListTestViewDelegate view_delegate_;
-  std::unique_ptr<SearchResultTileItemListView> view_;
-  views::Widget* widget_;
-  std::unique_ptr<views::Textfield> textfield_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_P(SearchResultTileItemListViewTest, Basic) {
-  CreateSearchResultTileItemListView();
-  SetUpSearchResults();
-
-  const size_t results = GetResultCount();
-  size_t expected_results = kInstalledApps;
-  expected_results += kPlayStoreApps;
-
-  if (IsReinstallAppRecommendationEnabled()) {
-    expected_results += kRecommendedApps;
-  }
-  constexpr size_t kMaxNumSearchResultTiles = 6;
-  expected_results = std::min(kMaxNumSearchResultTiles, expected_results);
-
-  ASSERT_EQ(expected_results, results);
-
-  // When the Play Store app search or app reinstallation results are
-  // present, for each result, we added a separator for result type grouping.
-  const size_t child_step = 2;
-  const size_t expected_num_children = kMaxNumSearchResultTiles * child_step;
-  EXPECT_EQ(expected_num_children, view()->children().size());
-
-  /// Test accessibility descriptions of tile views.
-  const size_t first_child = child_step - 1;
-  for (size_t i = 0; i < kInstalledApps; ++i) {
-    ui::AXNodeData node_data;
-    view()->children()[first_child + i * child_step]->GetAccessibleNodeData(
-        &node_data);
-    EXPECT_EQ(ax::mojom::Role::kListBoxOption, node_data.role);
-    EXPECT_EQ(l10n_util::GetStringFUTF8(
-                  IDS_APP_ACCESSIBILITY_INSTALLED_APP_ANNOUNCEMENT,
-                  base::UTF8ToUTF16("InstalledApp " + base::NumberToString(i))),
-              node_data.GetStringAttribute(ax::mojom::StringAttribute::kName));
-  }
-
-  const size_t expected_install_apps =
-      expected_results -
-      (IsReinstallAppRecommendationEnabled() ? kRecommendedApps : 0) -
-      kInstalledApps;
-  for (size_t i = 0; i < expected_install_apps; ++i) {
-    ui::AXNodeData node_data;
-    view()
-        ->children()[first_child + (i + kInstalledApps) * child_step]
-        ->GetAccessibleNodeData(&node_data);
-    EXPECT_EQ(ax::mojom::Role::kListBoxOption, node_data.role);
-    EXPECT_EQ(
-        l10n_util::GetStringFUTF8(
-            IDS_APP_ACCESSIBILITY_ARC_APP_ANNOUNCEMENT,
-            base::UTF8ToUTF16("PlayStoreApp " + base::NumberToString(i))) +
-            ", Star rating " + base::NumberToString(i + 1) + ".0",
-        node_data.GetStringAttribute(ax::mojom::StringAttribute::kName));
-  }
-
-  // Recommendations.
-  const size_t start_index = kInstalledApps + expected_install_apps;
-  for (size_t i = 0; i < expected_results - start_index; ++i) {
-    ui::AXNodeData node_data;
-    view()
-        ->children()[first_child + (i + start_index) * child_step]
-        ->GetAccessibleNodeData(&node_data);
-    EXPECT_EQ(ax::mojom::Role::kListBoxOption, node_data.role);
-    EXPECT_EQ(
-        l10n_util::GetStringFUTF8(
-            IDS_APP_ACCESSIBILITY_APP_RECOMMENDATION_ARC,
-            base::UTF8ToUTF16("RecommendedApp " + base::NumberToString(i))) +
-            ", Star rating " + base::NumberToString(i + 1) + ".0",
-        node_data.GetStringAttribute(ax::mojom::StringAttribute::kName));
-  }
-
-  ResetOpenResultCount();
-  for (size_t i = 0; i < results; ++i) {
-    ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE);
-    for (size_t j = 0; j <= i; ++j)
-      view()->tile_views_for_test()[i]->OnKeyEvent(&event);
-    // When app reinstalls is enabled, we actually instantiate 7 results,
-    // but only show 6. So we have to look, for exactly 1 result, a "skip"
-    // ahead for the reinstall result.
-    if (IsReinstallAppRecommendationEnabled() && i == (results - 1)) {
-      EXPECT_EQ(i + 1, GetOpenResultCount(i + 1));
-    } else {
-      EXPECT_EQ(i + 1, GetOpenResultCount(i));
-    }
-  }
-}
-
-// Tests that when multiple apps with specified indexes are added to the app
-// results list, they are found at the indexes they requested.
-TEST_P(SearchResultTileItemListViewTest, TestRecommendations) {
-  if (!IsReinstallAppRecommendationEnabled())
-    return;
-
-  CreateSearchResultTileItemListView();
-  SetUpSearchResultsWithMultipleDisplayIndexesRequested();
-
-  const size_t child_step = 2;
-
-  size_t first_index = kInstalledApps + kRecommendedAppsWithDisplayIndex;
-
-  size_t stepper = 3;
-  for (size_t i = 0; i < stepper; ++i) {
-    ui::AXNodeData node_data;
-    view()->children()[first_index + i * child_step]->GetAccessibleNodeData(
-        &node_data);
-    EXPECT_EQ(ax::mojom::Role::kListBoxOption, node_data.role);
-    EXPECT_EQ(
-        l10n_util::GetStringFUTF8(
-            IDS_APP_ACCESSIBILITY_APP_RECOMMENDATION_ARC,
-            base::UTF8ToUTF16("RecommendedApp " + base::NumberToString(i))) +
-            ", Star rating " + base::NumberToString(i + 1) + ".0",
-        node_data.GetStringAttribute(ax::mojom::StringAttribute::kName));
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(,
-                         SearchResultTileItemListViewTest,
-                         testing::ValuesIn({std::make_pair(false, false),
-                                            std::make_pair(false, true),
-                                            std::make_pair(true, false),
-                                            std::make_pair(true, true)}));
-
-}  // namespace ash
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
deleted file mode 100644
index 603ddbe9..0000000
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ /dev/null
@@ -1,579 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/app_list/views/search_result_tile_item_view.h"
-
-#include <utility>
-
-#include "ash/app_list/app_list_metrics.h"
-#include "ash/app_list/app_list_util.h"
-#include "ash/app_list/app_list_view_delegate.h"
-#include "ash/app_list/model/app_list_model.h"
-#include "ash/app_list/model/search/search_model.h"
-#include "ash/app_list/model/search/search_result.h"
-#include "ash/app_list/views/app_list_item_view.h"
-#include "ash/public/cpp/app_list/app_list_color_provider.h"
-#include "ash/public/cpp/app_list/app_list_config.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/app_list/app_list_types.h"
-#include "ash/public/cpp/app_list/vector_icons/vector_icons.h"
-#include "ash/public/cpp/ash_typography.h"
-#include "ash/public/cpp/pagination/pagination_model.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "ash/style/ash_color_id.h"
-#include "base/bind.h"
-#include "base/i18n/number_formatting.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/models/image_model.h"
-#include "ui/base/themed_vector_icon.h"
-#include "ui/chromeos/styles/cros_styles.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/views/accessibility/view_accessibility.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/style/typography.h"
-
-namespace ash {
-
-namespace {
-
-// The width of the focus ring.
-constexpr int kSelectionRingWidth = 2;
-
-constexpr int kSearchTileWidth = 80;
-constexpr int kSearchTileTopPadding = 4;
-constexpr int kSearchTitleSpacing = 7;
-constexpr int kSearchPriceSize = 37;
-constexpr int kSearchRatingSize = 26;
-constexpr int kSearchRatingStarSize = 12;
-constexpr int kSearchRatingStarHorizontalSpacing = 1;
-constexpr int kSearchRatingStarVerticalSpacing = 2;
-// Text line height in the search result tile.
-constexpr int kTileTextLineHeight = 16;
-constexpr int kBadgeIconShadowWidth = 1;
-
-// Delta applied to the font size of SearchResultTile title.
-constexpr int kSearchResultTileTitleTextSizeDelta = 1;
-
-constexpr int kIconSelectedSize = 58;
-constexpr int kIconSelectedCornerRadius = 4;
-
-// Offset for centering star rating when there is no price.
-constexpr int kSearchRatingCenteringOffset =
-    ((kSearchTileWidth -
-      (kSearchRatingSize + kSearchRatingStarHorizontalSpacing +
-       kSearchRatingStarSize)) /
-     2);
-
-}  // namespace
-
-SearchResultTileItemView::SearchResultTileItemView(
-    AppListViewDelegate* view_delegate)
-    : view_delegate_(view_delegate),
-      is_app_reinstall_recommendation_enabled_(
-          app_list_features::IsAppReinstallZeroStateEnabled()) {
-  SetCallback(base::BindRepeating(&SearchResultTileItemView::OnButtonPressed,
-                                  base::Unretained(this)));
-  SetFocusBehavior(FocusBehavior::ALWAYS);
-
-  // When |result_| is null, the tile is invisible. Calling SetSearchResult with
-  // a non-null item makes the tile visible.
-  SetVisible(false);
-
-  GetViewAccessibility().OverrideIsLeaf(true);
-
-  // Prevent the icon view from interfering with our mouse events.
-  icon_ = AddChildView(std::make_unique<views::ImageView>());
-  icon_->SetCanProcessEventsWithinSubtree(false);
-  icon_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
-
-  badge_ = AddChildView(std::make_unique<views::ImageView>());
-  badge_->SetCanProcessEventsWithinSubtree(false);
-  badge_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
-  badge_->SetVisible(false);
-
-  title_ = AddChildView(std::make_unique<views::Label>());
-  title_->SetEnabledColorId(cros_tokens::kTextColorSecondary);
-  title_->SetAutoColorReadabilityEnabled(false);
-  title_->SetLineHeight(kTileTextLineHeight);
-  title_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-  title_->SetHandlesTooltips(false);
-  title_->SetAllowCharacterBreak(true);
-
-  rating_ = AddChildView(std::make_unique<views::Label>());
-  rating_->SetLineHeight(kTileTextLineHeight);
-  rating_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
-  rating_->SetVisible(false);
-
-  rating_star_ = AddChildView(std::make_unique<views::ImageView>());
-  rating_star_->SetCanProcessEventsWithinSubtree(false);
-  rating_star_->SetVerticalAlignment(views::ImageView::Alignment::kLeading);
-  rating_star_->SetVisible(false);
-
-  price_ = AddChildView(std::make_unique<views::Label>());
-  price_->SetEnabledColorId(cros_tokens::kTextColorSecondary);
-  price_->SetLineHeight(kTileTextLineHeight);
-  price_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  price_->SetVisible(false);
-
-  set_context_menu_controller(this);
-}
-
-SearchResultTileItemView::~SearchResultTileItemView() = default;
-
-void SearchResultTileItemView::OnResultChanged() {
-  // Handle the case where this may be called from a nested run loop while its
-  // context menu is showing. This cancels the menu (it's for the old item).
-  context_menu_.reset();
-
-  SetVisible(!!result());
-
-  if (!result())
-    return;
-
-  SetTitle(result()->title());
-  SetTitleTags(result()->title_tags());
-  SetRating(result()->rating());
-  SetPrice(result()->formatted_price());
-
-  const gfx::FontList& font =
-      SharedAppListConfig::instance().search_result_recommendation_title_font();
-  if (rating_) {
-    if (!IsSuggestedAppTile()) {
-      // App search results use different fonts than AppList apps.
-      rating_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
-          SharedAppListConfig::instance().search_result_title_font_style()));
-    } else {
-      rating_->SetFontList(font);
-    }
-  }
-  if (price_) {
-    if (!IsSuggestedAppTile()) {
-      // App search results use different fonts than AppList apps.
-      price_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
-          SharedAppListConfig::instance().search_result_title_font_style()));
-    } else {
-      price_->SetFontList(font);
-    }
-  }
-  if (!IsSuggestedAppTile()) {
-    // App search results use different fonts than AppList apps.
-    title_->SetFontList(
-        ui::ResourceBundle::GetSharedInstance()
-            .GetFontList(SharedAppListConfig::instance()
-                             .search_result_title_font_style())
-            .DeriveWithSizeDelta(kSearchResultTileTitleTextSizeDelta));
-  } else {
-    title_->SetFontList(font);
-  }
-  title_->SetEnabledColorId(cros_tokens::kTextColorPrimary);
-  title_->SetMaxLines(2);
-  title_->SetMultiLine(
-      (result()->display_type() == SearchResultDisplayType::kTile ||
-       IsSuggestedAppTile()) &&
-      (result()->result_type() == AppListSearchResultType::kInstalledApp ||
-       result()->result_type() == AppListSearchResultType::kArcAppShortcut));
-
-  // If the new icon is null, it's being decoded asynchronously. Not updating it
-  // now to prevent flickering from showing an empty icon while decoding.
-  if (!result()->icon().icon.isNull())
-    OnMetadataChanged();
-
-  UpdateAccessibleName();
-}
-
-void SearchResultTileItemView::SetParentBackgroundColor(SkColor color) {
-  parent_background_color_ = color;
-  UpdateBackgroundColor();
-}
-
-void SearchResultTileItemView::GetAccessibleNodeData(
-    ui::AXNodeData* node_data) {
-  views::Button::GetAccessibleNodeData(node_data);
-
-  // The tile is a list item in the search result page's result list.
-  node_data->role = ax::mojom::Role::kListBoxOption;
-  node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kClick);
-
-  // Specify |ax::mojom::StringAttribute::kDescription| with an empty string, so
-  // that long truncated names are not read twice. Details of this issue: - The
-  // Play Store app's name is shown in a label |title_|. - If the name is too
-  // long, it'll get truncated and the full name will
-  //   go to the label's tooltip.
-  // - SearchResultTileItemView uses that label's tooltip as its tooltip.
-  // - If a view doesn't have |ax::mojom::StringAttribute::kDescription| defined
-  // in the
-  //   |AXNodeData|, |AXViewObjWrapper::Serialize| will use the tooltip text
-  //   as its description.
-  // - We're customizing this view's accessible name, so it get focused
-  //   ChromeVox will read its accessible name and then its description.
-  node_data->AddStringAttribute(ax::mojom::StringAttribute::kDescription, "");
-}
-
-bool SearchResultTileItemView::OnKeyPressed(const ui::KeyEvent& event) {
-  // Return early if |result()| was deleted due to the search result list
-  // changing. see crbug.com/801142
-  if (!result())
-    return true;
-
-  if (event.key_code() == ui::VKEY_RETURN) {
-    ActivateResult(event.flags(), false /* by_button_press */);
-    return true;
-  }
-  return false;
-}
-
-void SearchResultTileItemView::StateChanged(ButtonState old_state) {
-  SearchResultBaseView::StateChanged(old_state);
-  UpdateBackgroundColor();
-}
-
-void SearchResultTileItemView::PaintButtonContents(gfx::Canvas* canvas) {
-  if (!result() || !selected())
-    return;
-
-  cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setStyle(cc::PaintFlags::kStroke_Style);
-  flags.setStrokeWidth(kSelectionRingWidth);
-  flags.setColor(AppListColorProvider::Get()->GetFocusRingColor(GetWidget()));
-
-  gfx::RectF selection_ring = GetSelectionRingBounds();
-  selection_ring.Inset(gfx::InsetsF::VH(kSelectionRingWidth / 2.0, 0));
-  canvas->DrawRoundRect(selection_ring, kIconSelectedCornerRadius, flags);
-}
-
-void SearchResultTileItemView::OnThemeChanged() {
-  SearchResultBaseView::OnThemeChanged();
-  rating_star_->SetImage(gfx::CreateVectorIcon(
-      kBadgeRatingIcon, kSearchRatingStarSize,
-      AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor(
-          gfx::kGoogleGrey700, GetWidget())));
-}
-
-gfx::RectF SearchResultTileItemView::GetSelectionRingBounds() const {
-  gfx::RectF bounds(GetContentsBounds());
-  const float horizontal_padding = (bounds.width() - kIconSelectedSize) / 2.0;
-  bounds.Inset(gfx::InsetsF::VH(0, horizontal_padding));
-  bounds.set_height(kIconSelectedSize);
-  return bounds;
-}
-
-void SearchResultTileItemView::OnMetadataChanged() {
-  SetIcon(result()->icon().icon);
-  SetTitle(result()->title());
-  SetTitleTags(result()->title_tags());
-  SetBadgeIcon(result()->badge_icon(), result()->use_badge_icon_background());
-  SetRating(result()->rating());
-  SetPrice(result()->formatted_price());
-  Layout();
-}
-
-void SearchResultTileItemView::ShowContextMenuForViewImpl(
-    views::View* source,
-    const gfx::Point& point,
-    ui::MenuSourceType source_type) {
-  // |result()| could be null when result list is changing.
-  if (!result())
-    return;
-
-  view_delegate_->GetSearchResultContextMenuModel(
-      result()->id(),
-      base::BindOnce(&SearchResultTileItemView::OnGetContextMenuModel,
-                     weak_ptr_factory_.GetWeakPtr(), source, point,
-                     source_type));
-}
-
-void SearchResultTileItemView::OnGetContextMenuModel(
-    views::View* source,
-    const gfx::Point& point,
-    ui::MenuSourceType source_type,
-    std::unique_ptr<ui::SimpleMenuModel> menu_model) {
-  if (!menu_model || (context_menu_ && context_menu_->IsShowingMenu()))
-    return;
-
-  // Anchor the menu to the same rect that is used for selection ring.
-  gfx::Rect anchor_rect = gfx::ToEnclosingRect(GetSelectionRingBounds());
-  views::View::ConvertRectToScreen(this, &anchor_rect);
-
-  AppLaunchedMetricParams metric_params(
-      AppListLaunchedFrom::kLaunchedFromSearchBox,
-      AppListLaunchType::kAppSearchResult);
-  view_delegate_->GetAppLaunchedMetricParams(&metric_params);
-
-  context_menu_ = std::make_unique<AppListMenuModelAdapter>(
-      result()->id(), std::move(menu_model), GetWidget(), source_type,
-      metric_params, GetAppType(),
-      base::BindOnce(&SearchResultTileItemView::OnMenuClosed,
-                     weak_ptr_factory_.GetWeakPtr()),
-      view_delegate_->IsInTabletMode());
-  context_menu_->Run(anchor_rect, views::MenuAnchorPosition::kBubbleRight,
-                     views::MenuRunner::HAS_MNEMONICS |
-                         views::MenuRunner::USE_ASH_SYS_UI_LAYOUT |
-                         views::MenuRunner::CONTEXT_MENU |
-                         views::MenuRunner::FIXED_ANCHOR);
-  if (!selected()) {
-    selected_for_context_menu_ = true;
-    SetSelected(true, absl::nullopt);
-  }
-}
-
-void SearchResultTileItemView::OnMenuClosed() {
-  // Release menu since its menu model delegate (AppContextMenu) could be
-  // released as a result of menu command execution.
-  context_menu_.reset();
-  if (selected_for_context_menu_) {
-    selected_for_context_menu_ = false;
-    SetSelected(false, absl::nullopt);
-  }
-}
-
-void SearchResultTileItemView::OnButtonPressed(const ui::Event& event) {
-  ActivateResult(event.flags(), true /* by_button_press */);
-}
-
-void SearchResultTileItemView::ActivateResult(int event_flags,
-                                              bool by_button_press) {
-  const bool launch_as_default = is_default_result() && !by_button_press;
-  if (result()->result_type() == AppListSearchResultType::kPlayStoreApp) {
-    const base::TimeDelta activation_delay =
-        base::TimeTicks::Now() - result_display_start_time();
-    UMA_HISTOGRAM_MEDIUM_TIMES("Arc.PlayStoreSearch.ResultClickLatency",
-                               activation_delay);
-    UMA_HISTOGRAM_EXACT_LINEAR(
-        "Apps.AppListPlayStoreAppLaunchedIndex",
-        group_index_in_container_view(),
-        SharedAppListConfig::instance().max_search_result_tiles());
-    if (launch_as_default) {
-      UMA_HISTOGRAM_MEDIUM_TIMES(
-          "Arc.PlayStoreSearch.DefaultResultClickLatency", activation_delay);
-    }
-  }
-
-  LogAppLaunchForSuggestedApp();
-
-  RecordSearchResultOpenSource(result(), view_delegate_->GetAppListViewState(),
-                               view_delegate_->IsInTabletMode());
-  view_delegate_->OpenSearchResult(result()->id(), event_flags,
-                                   AppListLaunchedFrom::kLaunchedFromSearchBox,
-                                   AppListLaunchType::kAppSearchResult,
-                                   index_in_container(), launch_as_default);
-}
-
-void SearchResultTileItemView::SetIcon(const gfx::ImageSkia& icon) {
-  const int icon_size =
-      SharedAppListConfig::instance().search_tile_icon_dimension();
-  gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
-      icon, skia::ImageOperations::RESIZE_BEST,
-      gfx::Size(icon_size, icon_size)));
-  icon_->SetImage(resized);
-}
-
-void SearchResultTileItemView::SetBadgeIcon(const ui::ImageModel& badge_icon,
-                                            bool use_badge_icon_background) {
-  if (badge_icon.IsEmpty()) {
-    badge_->SetVisible(false);
-    return;
-  }
-
-  gfx::ImageSkia badge_icon_skia = badge_icon.Rasterize(GetColorProvider());
-
-  if (use_badge_icon_background) {
-    badge_icon_skia = CreateIconWithCircleBackground(badge_icon_skia);
-  }
-
-  gfx::ImageSkia resized_badge_icon(
-      gfx::ImageSkiaOperations::CreateResizedImage(
-          badge_icon_skia, skia::ImageOperations::RESIZE_BEST,
-          SharedAppListConfig::instance().search_tile_badge_icon_size()));
-
-  gfx::ShadowValues shadow_values;
-  shadow_values.push_back(
-      gfx::ShadowValue(gfx::Vector2d(0, kBadgeIconShadowWidth), 0,
-                       SkColorSetARGB(0x33, 0, 0, 0)));
-  shadow_values.push_back(
-      gfx::ShadowValue(gfx::Vector2d(0, kBadgeIconShadowWidth), 2,
-                       SkColorSetARGB(0x33, 0, 0, 0)));
-  badge_->SetImage(gfx::ImageSkiaOperations::CreateImageWithDropShadow(
-      resized_badge_icon, shadow_values));
-  badge_->SetVisible(true);
-}
-
-void SearchResultTileItemView::SetTitle(const std::u16string& title) {
-  title_->SetText(title);
-}
-
-void SearchResultTileItemView::SetTitleTags(const SearchResultTags& tags) {
-  for (const auto& tag : tags) {
-    if (tag.styles & SearchResult::Tag::MATCH) {
-      title_->SetTextStyleRange(views::style::STYLE_EMPHASIZED, tag.range);
-    }
-  }
-}
-
-void SearchResultTileItemView::SetRating(float rating) {
-  if (!rating_)
-    return;
-
-  if (rating < 0) {
-    rating_->SetVisible(false);
-    rating_star_->SetVisible(false);
-    return;
-  }
-
-  rating_->SetText(base::FormatDouble(rating, 1));
-  rating_->SetVisible(true);
-  rating_star_->SetVisible(true);
-}
-
-void SearchResultTileItemView::SetPrice(const std::u16string& price) {
-  if (!price_)
-    return;
-
-  if (price.empty()) {
-    price_->SetVisible(false);
-    return;
-  }
-
-  price_->SetText(price);
-  price_->SetVisible(true);
-}
-
-AppListMenuModelAdapter::AppListViewAppType
-SearchResultTileItemView::GetAppType() const {
-  if (IsSuggestedAppTile())
-    return AppListMenuModelAdapter::FULLSCREEN_SUGGESTED;
-
-  if (view_delegate_->GetAppListViewState() ==
-      AppListViewState::kFullscreenSearch) {
-    return AppListMenuModelAdapter::FULLSCREEN_SEARCH_RESULT;
-  }
-
-  NOTREACHED();
-  return AppListMenuModelAdapter::APP_LIST_APP_TYPE_LAST;
-}
-
-bool SearchResultTileItemView::IsSuggestedAppTile() const {
-  return result() && result()->is_recommendation();
-}
-
-void SearchResultTileItemView::LogAppLaunchForSuggestedApp() const {
-  // Only log the app launch if the class is being used as a suggested app.
-  if (!IsSuggestedAppTile())
-    return;
-
-  // We only need to record opening the installed app in zero state, no need to
-  // record the opening of a fast re-installed app, since the latter is already
-  // recorded in ArcAppReinstallAppResult::Open.
-  if (result()->result_type() !=
-      AppListSearchResultType::kPlayStoreReinstallApp) {
-    base::RecordAction(
-        base::UserMetricsAction("AppList_ZeroStateOpenInstalledApp"));
-  }
-}
-
-void SearchResultTileItemView::UpdateBackgroundColor() {
-  // Tell the label what color it will be drawn onto. It will use whether the
-  // background color is opaque or transparent to decide whether to use subpixel
-  // rendering. Does not actually set the label's background color.
-  title_->SetBackgroundColor(parent_background_color_);
-  SchedulePaint();
-}
-
-void SearchResultTileItemView::Layout() {
-  gfx::Rect rect(GetContentsBounds());
-  if (rect.IsEmpty() || !result())
-    return;
-
-  gfx::Rect icon_rect(rect);
-  icon_rect.ClampToCenteredSize(icon_->GetImage().size());
-  icon_rect.set_y(kSearchTileTopPadding);
-  icon_->SetBoundsRect(icon_rect);
-
-  const int badge_icon_dimension =
-      SharedAppListConfig::instance().search_tile_badge_icon_dimension() +
-      2 * kBadgeIconShadowWidth;
-  const int badge_icon_offset =
-      SharedAppListConfig::instance().search_tile_badge_icon_offset();
-  const gfx::Rect badge_rect(
-      icon_rect.right() - badge_icon_dimension + badge_icon_offset,
-      icon_rect.bottom() - badge_icon_dimension + badge_icon_offset,
-      badge_icon_dimension, badge_icon_dimension);
-  badge_->SetBoundsRect(badge_rect);
-
-  rect.set_y(icon_rect.bottom() + kSearchTitleSpacing);
-  rect.set_height(title_->GetPreferredSize().height());
-  title_->SetBoundsRect(rect);
-
-  // If there is no price set, we center the rating.
-  const bool center_rating =
-      rating_ && rating_star_ && price_ && price_->GetText().empty();
-  const int rating_horizontal_offset =
-      center_rating ? kSearchRatingCenteringOffset : 0;
-
-  if (rating_) {
-    gfx::Rect rating_rect(rect);
-    rating_rect.Inset(gfx::Insets::TLBR(title_->GetPreferredSize().height(),
-                                        rating_horizontal_offset, 0, 0));
-    rating_rect.set_size(rating_->GetPreferredSize());
-    rating_rect.set_width(kSearchRatingSize);
-    rating_->SetBoundsRect(rating_rect);
-  }
-
-  if (rating_star_) {
-    gfx::Rect rating_star_rect(rect);
-    rating_star_rect.Inset(gfx::Insets::TLBR(
-        title_->GetPreferredSize().height() + kSearchRatingStarVerticalSpacing,
-        rating_horizontal_offset + kSearchRatingSize +
-            kSearchRatingStarHorizontalSpacing,
-        0, 0));
-    rating_star_rect.set_size(rating_star_->GetPreferredSize());
-    rating_star_->SetBoundsRect(rating_star_rect);
-  }
-
-  if (price_) {
-    gfx::Rect price_rect(rect);
-    price_rect.Inset(gfx::Insets::TLBR(title_->GetPreferredSize().height(),
-                                       rect.width() - kSearchPriceSize, 0, 0));
-    price_rect.set_size(price_->GetPreferredSize());
-    price_->SetBoundsRect(price_rect);
-  }
-}
-
-const char* SearchResultTileItemView::GetClassName() const {
-  return "SearchResultTileItemView";
-}
-
-gfx::Size SearchResultTileItemView::CalculatePreferredSize() const {
-  if (!result())
-    return gfx::Size();
-
-  return gfx::Size(kSearchTileWidth,
-                   SharedAppListConfig::instance().search_tile_height());
-}
-
-std::u16string SearchResultTileItemView::GetTooltipText(
-    const gfx::Point& p) const {
-  // Use the label to generate a tooltip, so that it will consider its text
-  // truncation in making the tooltip. We do not want the label itself to have a
-  // tooltip, so we only temporarily enable it to get the tooltip text from the
-  // label, then disable it again.
-  title_->SetHandlesTooltips(true);
-  std::u16string tooltip = title_->GetTooltipText(p);
-  title_->SetHandlesTooltips(false);
-  return tooltip;
-}
-
-}  // namespace ash
diff --git a/ash/app_list/views/search_result_tile_item_view.h b/ash/app_list/views/search_result_tile_item_view.h
deleted file mode 100644
index 3930629..0000000
--- a/ash/app_list/views/search_result_tile_item_view.h
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_VIEW_H_
-#define ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_VIEW_H_
-
-#include <memory>
-#include <vector>
-
-#include "ash/app_list/views/app_list_menu_model_adapter.h"
-#include "ash/app_list/views/search_result_base_view.h"
-#include "ash/ash_export.h"
-#include "ash/public/cpp/app_list/app_list_types.h"
-#include "ui/views/context_menu_controller.h"
-
-namespace ui {
-class ImageModel;
-}  // namespace ui
-
-namespace views {
-class ImageView;
-class Label;
-}  // namespace views
-
-namespace ash {
-
-class AppListViewDelegate;
-class SearchResult;
-
-// A tile view that displays a search result. It hosts view for search result
-// that has SearchResult::DisplayType DISPLAY_TILE or DISPLAY_RECOMMENDATION.
-class ASH_EXPORT SearchResultTileItemView
-    : public SearchResultBaseView,
-      public views::ContextMenuController {
- public:
-  explicit SearchResultTileItemView(AppListViewDelegate* view_delegate);
-
-  SearchResultTileItemView(const SearchResultTileItemView&) = delete;
-  SearchResultTileItemView& operator=(const SearchResultTileItemView&) = delete;
-
-  ~SearchResultTileItemView() override;
-
-  void OnResultChanged() override;
-
-  // Informs the SearchResultTileItemView of its parent's background color. The
-  // controls within the SearchResultTileItemView will adapt to suit the given
-  // color.
-  void SetParentBackgroundColor(SkColor color);
-
-  void set_group_index_in_container_view(int index) {
-    group_index_in_container_view_ = index;
-  }
-  int group_index_in_container_view() const {
-    return group_index_in_container_view_;
-  }
-
-  // Overridden from views::Button:
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-  bool OnKeyPressed(const ui::KeyEvent& event) override;
-  void StateChanged(ButtonState old_state) override;
-  void PaintButtonContents(gfx::Canvas* canvas) override;
-  void OnThemeChanged() override;
-
-  // Overridden from SearchResultObserver:
-  void OnMetadataChanged() override;
-
-  // views::ContextMenuController overrides:
-  void ShowContextMenuForViewImpl(views::View* source,
-                                  const gfx::Point& point,
-                                  ui::MenuSourceType source_type) override;
-
- private:
-  // Launch the result and log to various histograms.
-  // |by_button_press|: True if |result_| is activated by button pressing;
-  //                    otherwise |result| is activated by ENTER key pressing.
-  void ActivateResult(int event_flags, bool by_button_press);
-
-  // Bound by ShowContextMenuForViewImpl().
-  void OnGetContextMenuModel(views::View* source,
-                             const gfx::Point& point,
-                             ui::MenuSourceType source_type,
-                             std::unique_ptr<ui::SimpleMenuModel> menu_model);
-
-  // The callback used when a menu closes.
-  void OnMenuClosed();
-
-  void OnButtonPressed(const ui::Event& event);
-
-  void SetIcon(const gfx::ImageSkia& icon);
-  void SetBadgeIcon(const ui::ImageModel& badge_icon,
-                    bool use_badge_icon_background);
-  void SetTitle(const std::u16string& title);
-  void SetTitleTags(const SearchResultTags& tags);
-  void SetRating(float rating);
-  void SetPrice(const std::u16string& price);
-
-  AppListMenuModelAdapter::AppListViewAppType GetAppType() const;
-
-  // Whether the tile view is a suggested app.
-  bool IsSuggestedAppTile() const;
-
-  // Records an app being launched.
-  void LogAppLaunchForSuggestedApp() const;
-
-  void UpdateBackgroundColor();
-
-  // Gets the bounds for the selection ring (shown when the result is selected).
-  gfx::RectF GetSelectionRingBounds() const;
-
-  // Overridden from views::View:
-  void Layout() override;
-  const char* GetClassName() const override;
-  gfx::Size CalculatePreferredSize() const override;
-  std::u16string GetTooltipText(const gfx::Point& p) const override;
-
-  AppListViewDelegate* const view_delegate_;  // Owned by AppListView.
-
-  views::ImageView* icon_ = nullptr;         // Owned by views hierarchy.
-  views::ImageView* badge_ = nullptr;        // Owned by views hierarchy.
-  views::Label* title_ = nullptr;            // Owned by views hierarchy.
-  views::Label* rating_ = nullptr;           // Owned by views hierarchy.
-  views::Label* price_ = nullptr;            // Owned by views hierarchy.
-  views::ImageView* rating_star_ = nullptr;  // Owned by views hierarchy.
-
-  SkColor parent_background_color_ = SK_ColorTRANSPARENT;
-
-  // The index of the app in its display group in its container view. Currently,
-  // there are three separately displayed groups for apps in launcher's
-  // suggestion window: Installed apps, play store apps, play store reinstalled
-  // app.
-  int group_index_in_container_view_;
-  const bool is_app_reinstall_recommendation_enabled_;
-
-  // Whether the result view moved into selected state only because a context
-  // menu was shown.
-  bool selected_for_context_menu_ = false;
-
-  std::unique_ptr<AppListMenuModelAdapter> context_menu_;
-
-  base::WeakPtrFactory<SearchResultTileItemView> weak_ptr_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // ASH_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_VIEW_H_
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index c53c7bb5..2a2ddde 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2,6 +2,15 @@
 
 <!--
 This file contains the strings for ash.
+
+Style notes:
+* Most strings are "Sentence case" with the first word capitalized and other
+  words not capitalized
+* Specific features may be capitalized (e.g. "Bluetooth", "Nearby Share") even
+  if they appear in the middle of a string
+* Most strings do not end in a period (e.g. "Show settings")
+* Multi-phrase strings that contain a period in the middle also have a period
+  at the end (e.g. "Show Bluetooth settings. Bluetooth is on.")
 -->
 
 <grit base_dir="." latest_public_release="0" current_release="1"
@@ -427,10 +436,10 @@
         <ph name="SECONDS">$1<ex>40</ex></ph> sec
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NEARBY_SHARE_SETTINGS_TOOLTIP" desc="Tooltip text for the status tray button that shows settings for the Nearby Share feature.">
-        Show Nearby Share settings.
+        Show Nearby Share settings
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NEARBY_SHARE_TOGGLE_TOOLTIP" desc="Tooltip text used for the Nearby Share status tray button, which toggles Nearby Share high visibility mode on/off.">
-        Toggle Nearby Share high visibility.
+        Toggle Nearby Share high visibility
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_BUTTON_LABEL" desc="The shorter label used for the button in the status tray to toggle the Night Light feature (which controls the color temperature of the screen) on or off. [CHAR_LIMIT=14]">
         Night Light
@@ -472,7 +481,7 @@
         Cast
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_TOOLTIP" desc="The tooltip text used for Cast button in system tray bubble.">
-        Show cast devices.
+        Show cast devices
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_NOTIFICATION_TITLE" desc="The notification title to tell the user we are casting to a cast device.">
         Casting to <ph name="RECEIVER_NAME">$1<ex>Living Room</ex></ph>
@@ -487,7 +496,7 @@
         Dark theme
       </message>
       <message name="IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP" desc="The tooltip text used for the button in the status tray to toggle the Dark theme feature on or off.">
-        Toggle Dark theme. <ph name="STATE_TEXT">$1<ex>Dark theme is on.</ex></ph>
+        Toggle Dark theme. <ph name="STATE_TEXT">$1<ex>Dark theme is on</ex></ph>.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_DARK_THEME_ENABLED_STATE_TOOLTIP" desc="The tooltip text indicating the Dark theme feature is on.">
         Dark theme is on
@@ -578,10 +587,10 @@
         Bluetooth
       </message>
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP" desc="The tooltip text in the button that toggles Blueooth enabled/disabled.">
-        Toggle Bluetooth. <ph name="STATE_TEXT">$1<ex>Connected to 2 devices</ex></ph>
+        Toggle Bluetooth. <ph name="STATE_TEXT">$1<ex>Connected to 2 devices</ex></ph>.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS_TOOLTIP" desc="The tooltip text in the button that shows Blueooth settings.">
-        Show Bluetooth settings. <ph name="STATE_TEXT">$1<ex>Connected to 2 devices</ex></ph>
+        Show Bluetooth settings. <ph name="STATE_TEXT">$1<ex>Connected to 2 devices</ex></ph>.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED_TOOLTIP" desc="The tooltip text to notify that bluetooth is enabled.">
         Bluetooth is on
@@ -949,7 +958,7 @@
         Show keyboard settings
       </message>
       <message name="IDS_ASH_STATUS_TRAY_IME_TOOLTIP_WITH_NAME" desc="The tooltip text used for IME button in system tray bubble.">
-        Show keyboard settings. <ph name="KEYBOARD_NAME">$1<ex>US keyboard</ex></ph> is selected
+        Show keyboard settings. <ph name="KEYBOARD_NAME">$1<ex>US keyboard</ex></ph> is selected.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_IME" desc="The label used as the header in the IME popup. [CHAR_LIMIT=18]">
         Input methods
@@ -2423,10 +2432,10 @@
       </message>
 
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP" desc="The tooltip text for the button that toggles network enabled/disabled state.">
-        Toggle network connection. <ph name="STATE_TEXT">$1<ex>Connected to public wifi</ex></ph>
+        Toggle network connection. <ph name="STATE_TEXT">$1<ex>Connected to public wifi</ex></ph>.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP" desc="The tooltip text for the button that shows network list.">
-        Show network list. <ph name="STATE_TEXT">$1<ex>Connected to public wifi</ex></ph>
+        Show network list. <ph name="STATE_TEXT">$1<ex>Connected to public wifi</ex></ph>.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_NETWORK_PROGRESS_ACCESSIBLE_NAME" desc="The accessible name for the progress bar shown in the network settings.">
         Scanning
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS_TOOLTIP.png.sha1
new file mode 100644
index 0000000..85a08e3
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+14506683f4860247eb998fefef35e68d8d5ba681
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..0b4171ee
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+5e34a89e2a19ab9c3309ecb3db36a2fcc7caafb1
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CAST_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CAST_TOOLTIP.png.sha1
new file mode 100644
index 0000000..fd8132f
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_CAST_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+0122e9b5756ac230cb7b723e042098776c119cf6
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP.png.sha1
index 3b00f1d..a5d652c 100644
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP.png.sha1
@@ -1 +1 @@
-a3cbce9b0bd7654915d9ea33f1b1b0a151fc3388
\ No newline at end of file
+24e630801e46d8a1e2adb054186bef9cf2619281
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_IME_TOOLTIP_WITH_NAME.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_IME_TOOLTIP_WITH_NAME.png.sha1
new file mode 100644
index 0000000..9c55b4ea
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_IME_TOOLTIP_WITH_NAME.png.sha1
@@ -0,0 +1 @@
+fe626ac766446f602d894e35d882a5558d81cda3
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_SETTINGS_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_SETTINGS_TOOLTIP.png.sha1
index e264bcc..c71f6cc 100644
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_SETTINGS_TOOLTIP.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_SETTINGS_TOOLTIP.png.sha1
@@ -1 +1 @@
-14fa83bd6816e26df5e9ac72cbceb09818990031
\ No newline at end of file
+c0e2a814eab217357d2fe53af41a110f70276f2a
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_TOGGLE_TOOLTIP.png.sha1
index 3371c2cd..0253090 100644
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_TOGGLE_TOOLTIP.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NEARBY_SHARE_TOGGLE_TOOLTIP.png.sha1
@@ -1 +1 @@
-14577c7eda36f1ee897e9d6974c02c969d478199
\ No newline at end of file
+7992b9ffd8afbe69bbe52a87329d14b41537c2ac
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP.png.sha1
new file mode 100644
index 0000000..0d52da5
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+b18e7c706cfa38cd962fe35e810a1fc7ed7df4b6
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP.png.sha1
new file mode 100644
index 0000000..c90d6e4
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+f1346ee4f1f4af37d07953ffff206e5d72118225
\ No newline at end of file
diff --git a/ash/metrics/login_unlock_throughput_recorder.cc b/ash/metrics/login_unlock_throughput_recorder.cc
index 28520c2..76b25081 100644
--- a/ash/metrics/login_unlock_throughput_recorder.cc
+++ b/ash/metrics/login_unlock_throughput_recorder.cc
@@ -5,67 +5,20 @@
 #include "ash/metrics/login_unlock_throughput_recorder.h"
 
 #include "ash/public/cpp/metrics_util.h"
-#include "ash/public/cpp/shelf_model.h"
 #include "ash/session/session_controller_impl.h"
-#include "ash/shelf/shelf_view.h"
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/bind.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "chromeos/metrics/login_event_recorder.h"
-#include "components/app_constants/constants.h"
-#include "components/app_restore/window_properties.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/compositor/compositor.h"
-#include "ui/compositor/layer.h"
 #include "ui/compositor/total_animation_throughput_reporter.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/animation/bounds_animator_observer.h"
 
 namespace ash {
 namespace {
 
-// A class used to wait for animations.
-class AnimationObserver : public views::BoundsAnimatorObserver {
- public:
-  AnimationObserver(ShelfView* shelf_view, base::OnceClosure& on_animation_end)
-      : shelf_view_(shelf_view),
-        on_animation_end_(std::move(on_animation_end)) {}
-
-  AnimationObserver(const AnimationObserver&) = delete;
-  AnimationObserver& operator=(const AnimationObserver&) = delete;
-
-  ~AnimationObserver() override = default;
-
-  // ShelfViewObserver overrides:
-  void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override {}
-  void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override {
-    shelf_view_->RemoveAnimationObserver(this);
-    RunCallbackAndDestroy();
-  }
-
-  void StartObserving() {
-    if (shelf_view_->IsAnimating()) {
-      shelf_view_->AddAnimationObserver(this);
-      return;
-    }
-    RunCallbackAndDestroy();
-  }
-
- private:
-  void RunCallbackAndDestroy() {
-    std::move(on_animation_end_).Run();
-    delete this;
-  }
-
-  base::raw_ptr<ShelfView> shelf_view_;
-  base::OnceClosure on_animation_end_;
-};
-
 std::string GetDeviceModeSuffix() {
   return Shell::Get()->tablet_mode_controller()->InTabletMode()
              ? "TabletMode"
@@ -104,7 +57,6 @@
     LOG(WARNING) << "Zero frames expected in login animation throughput data";
     return;
   }
-
   chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
       "LoginAnimationEnd",
       /*send_to_uma=*/false,
@@ -124,14 +76,6 @@
                 "Ash.UnlockAnimation.Jank.", "Ash.UnlockAnimation.Duration.");
 }
 
-void OnRestoredWindowPresentationFeedbackReceived(
-    int restore_window_id,
-    const gfx::PresentationFeedback& feedback) {
-  LoginUnlockThroughputRecorder* throughput_recorder =
-      Shell::Get()->login_unlock_throughput_recorder();
-  throughput_recorder->OnRestoredWindowPresented(restore_window_id);
-}
-
 }  // namespace
 
 LoginUnlockThroughputRecorder::LoginUnlockThroughputRecorder() {
@@ -154,160 +98,24 @@
     new ui::TotalAnimationThroughputReporter(
         primary_root->GetHost()->compositor(),
         base::BindOnce(&ReportUnlock, base::TimeTicks::Now()),
-        /*should_delete=*/true);
+        /*self_destruct=*/true);
   }
 }
 
 void LoginUnlockThroughputRecorder::LoggedInStateChanged() {
   auto* login_state = chromeos::LoginState::Get();
   auto logged_in_user = login_state->GetLoggedInUserType();
-
-  if (user_logged_in_)
-    return;
-
-  if (!login_state->IsUserLoggedIn())
-    return;
-
-  if (logged_in_user != chromeos::LoginState::LOGGED_IN_USER_OWNER &&
-      logged_in_user != chromeos::LoginState::LOGGED_IN_USER_REGULAR) {
-    return;
+  if (login_state->IsUserLoggedIn() &&
+      (logged_in_user == chromeos::LoginState::LOGGED_IN_USER_OWNER ||
+       logged_in_user == chromeos::LoginState::LOGGED_IN_USER_REGULAR)) {
+    ui_recorder_.OnUserLoggedIn();
+    auto* primary_root = Shell::GetPrimaryRootWindow();
+    new ui::TotalAnimationThroughputReporter(
+        primary_root->GetHost()->compositor(),
+        base::BindOnce(&LoginUnlockThroughputRecorder::OnLoginAnimationFinish,
+                       weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()),
+        /*self_destruct=*/true);
   }
-
-  user_logged_in_ = true;
-  ui_recorder_.OnUserLoggedIn();
-  auto* primary_root = Shell::GetPrimaryRootWindow();
-  primary_user_logged_in_ = base::TimeTicks::Now();
-  auto* rec = new ui::TotalAnimationThroughputReporter(
-      primary_root->GetHost()->compositor(),
-      base::BindOnce(&LoginUnlockThroughputRecorder::OnLoginAnimationFinish,
-                     weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()),
-      /*should_delete=*/true);
-  login_animation_throughput_reporter_ = rec->GetWeakPtr();
-  DCHECK(!scoped_throughput_reporter_blocker_);
-  // Login animation metrics should not be reported until all shelf icons
-  // were loaded.
-  scoped_throughput_reporter_blocker_ =
-      login_animation_throughput_reporter_->NewScopedBlocker();
-}
-
-void LoginUnlockThroughputRecorder::AddScheduledRestoreWindow(
-    int restore_window_id,
-    const std::string& app_id,
-    RestoreWindowType window_type) {
-  switch (window_type) {
-    case LoginUnlockThroughputRecorder::kBrowser:
-      DCHECK(restore_window_id);
-      if (app_id.empty() || app_id == app_constants::kLacrosAppId)
-        windows_to_restore_.insert(restore_window_id);
-
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-void LoginUnlockThroughputRecorder::OnRestoredWindowCreated(
-    int restore_window_id) {
-  auto it = windows_to_restore_.find(restore_window_id);
-  if (it == windows_to_restore_.end())
-    return;
-  windows_to_restore_.erase(it);
-  if (windows_to_restore_.empty() && !primary_user_logged_in_.is_null()) {
-    const base::TimeDelta duration_ms =
-        base::TimeTicks::Now() - primary_user_logged_in_;
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Ash.LoginSessionRestore.AllBrowserWindowsCreated", duration_ms,
-        base::Milliseconds(1), base::Seconds(100), 100);
-  }
-  restore_windows_not_shown_.insert(restore_window_id);
-}
-
-void LoginUnlockThroughputRecorder::OnBeforeRestoredWindowShown(
-    int restore_window_id,
-    ui::Compositor* compositor) {
-  auto it = restore_windows_not_shown_.find(restore_window_id);
-  if (it == restore_windows_not_shown_.end())
-    return;
-
-  restore_windows_not_shown_.erase(it);
-  if (windows_to_restore_.empty() && restore_windows_not_shown_.empty() &&
-      !primary_user_logged_in_.is_null()) {
-    const base::TimeDelta duration_ms =
-        base::TimeTicks::Now() - primary_user_logged_in_;
-    UMA_HISTOGRAM_CUSTOM_TIMES("Ash.LoginSessionRestore.AllBrowserWindowsShown",
-                               duration_ms, base::Milliseconds(1),
-                               base::Seconds(100), 100);
-  }
-
-  if (!compositor)
-    return;
-
-  restore_windows_presentation_time_requested_.insert(restore_window_id);
-  compositor->RequestPresentationTimeForNextFrame(base::BindOnce(
-      &OnRestoredWindowPresentationFeedbackReceived, restore_window_id));
-}
-
-void LoginUnlockThroughputRecorder::OnRestoredWindowPresented(
-    int restore_window_id) {
-  auto it =
-      restore_windows_presentation_time_requested_.find(restore_window_id);
-  if (it == restore_windows_presentation_time_requested_.end())
-    return;
-
-  restore_windows_presentation_time_requested_.erase(it);
-  if (windows_to_restore_.empty() && restore_windows_not_shown_.empty() &&
-      restore_windows_presentation_time_requested_.empty() &&
-      !primary_user_logged_in_.is_null()) {
-    const base::TimeDelta duration_ms =
-        base::TimeTicks::Now() - primary_user_logged_in_;
-    UMA_HISTOGRAM_CUSTOM_TIMES(
-        "Ash.LoginSessionRestore.AllBrowserWindowsPresented", duration_ms,
-        base::Milliseconds(1), base::Seconds(100), 100);
-  }
-  restore_windows_presented_.insert(restore_window_id);
-}
-
-void LoginUnlockThroughputRecorder::InitShelfIconList(const ShelfModel* model) {
-  shelf_initialized_ = true;
-
-  // Copy shelf icons to the expected list.
-  for (int index = 0; index < model->item_count(); ++index) {
-    const ShelfID& id = model->items()[index].id;
-    const ShelfItem& item = model->items()[index];
-    if (item.image.isNull())
-      expected_shelf_icons_.insert(id);
-  }
-
-  if (expected_shelf_icons_.empty())
-    OnAllExpectedShelfIconsLoaded();
-}
-
-void LoginUnlockThroughputRecorder::UpdateShelfIconList(
-    const ShelfModel* model) {
-  if (!shelf_initialized_)
-    return;
-
-  // Remove IDs that have icons loaded or were already deleted.
-  base::flat_set<ShelfID> expected_ids_without_icons;
-
-  for (int index = 0; index < model->item_count(); ++index) {
-    const ShelfItem& item = model->items()[index];
-    const ShelfID& id = item.id;
-    if (!expected_shelf_icons_.contains(id))
-      continue;
-
-    if (item.image.isNull())
-      expected_ids_without_icons.insert(id);
-  }
-  expected_shelf_icons_ = expected_ids_without_icons;
-
-  if (expected_shelf_icons_.empty())
-    OnAllExpectedShelfIconsLoaded();
-}
-
-void LoginUnlockThroughputRecorder::
-    ResetScopedThroughputReporterBlockerForTesting() {
-  scoped_throughput_reporter_blocker_.reset();
 }
 
 void LoginUnlockThroughputRecorder::OnLoginAnimationFinish(
@@ -317,43 +125,4 @@
   ReportLogin(start, data);
 }
 
-void LoginUnlockThroughputRecorder::SetShelfViewIfNotSet(
-    ShelfView* shelf_view) {
-  if (!shelf_view_)
-    shelf_view_ = shelf_view;
-}
-
-void LoginUnlockThroughputRecorder::ScheduleWaitForShelfAnimationEnd() {
-  DCHECK(shelf_view_);
-  if (!shelf_view_)
-    return;
-
-  base::OnceCallback on_animation_end = base::BindOnce(
-      [](base::TimeTicks primary_user_logged_in) {
-        const base::TimeDelta duration_ms =
-            base::TimeTicks::Now() - primary_user_logged_in;
-        UMA_HISTOGRAM_CUSTOM_TIMES(
-            "Ash.LoginSessionRestore.ShelfLoginAnimationEnd", duration_ms,
-            base::Milliseconds(1), base::Seconds(100), 100);
-      },
-      primary_user_logged_in_);
-
-  (new AnimationObserver(shelf_view_, on_animation_end))->StartObserving();
-}
-
-void LoginUnlockThroughputRecorder::OnAllExpectedShelfIconsLoaded() {
-  if (shelf_icons_loaded_)
-    return;
-
-  scoped_throughput_reporter_blocker_.reset();
-
-  shelf_icons_loaded_ = true;
-  const base::TimeDelta duration_ms =
-      base::TimeTicks::Now() - primary_user_logged_in_;
-  UMA_HISTOGRAM_CUSTOM_TIMES("Ash.LoginSessionRestore.AllShelfIconsLoaded",
-                             duration_ms, base::Milliseconds(1),
-                             base::Seconds(100), 100);
-  ScheduleWaitForShelfAnimationEnd();
-}
-
 }  // namespace ash
diff --git a/ash/metrics/login_unlock_throughput_recorder.h b/ash/metrics/login_unlock_throughput_recorder.h
index 8c1dd7e9..55f5bbc 100644
--- a/ash/metrics/login_unlock_throughput_recorder.h
+++ b/ash/metrics/login_unlock_throughput_recorder.h
@@ -5,38 +5,20 @@
 #ifndef ASH_METRICS_LOGIN_UNLOCK_THROUGHPUT_RECORDER_H_
 #define ASH_METRICS_LOGIN_UNLOCK_THROUGHPUT_RECORDER_H_
 
-#include <string>
-
 #include "ash/ash_export.h"
 #include "ash/metrics/ui_throughput_recorder.h"
 #include "ash/public/cpp/session/session_observer.h"
-#include "ash/public/cpp/shelf_types.h"
-#include "base/containers/flat_set.h"
-#include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "cc/metrics/frame_sequence_metrics.h"
 #include "chromeos/login/login_state/login_state.h"
-#include "ui/compositor/total_animation_throughput_reporter.h"
-
-namespace ui {
-class Compositor;
-}
 
 namespace ash {
 
-class ShelfModel;
-class ShelfView;
-
 class ASH_EXPORT LoginUnlockThroughputRecorder
     : public SessionObserver,
       public chromeos::LoginState::Observer {
  public:
-  enum RestoreWindowType {
-    kBrowser,
-    kArc,
-  };
-
   LoginUnlockThroughputRecorder();
   LoginUnlockThroughputRecorder(const LoginUnlockThroughputRecorder&) = delete;
   LoginUnlockThroughputRecorder& operator=(
@@ -49,85 +31,12 @@
   // chromeos::LoginState::Observer:
   void LoggedInStateChanged() override;
 
-  // Adds "restore_window_id" to the list of potentially restored windows.
-  // See
-  // https://source.chromium.org/chromium/chromium/src/+/main:ui/views/widget/widget.h;l=404-415.
-  void AddScheduledRestoreWindow(int restore_window_id,
-                                 const std::string& app_id,
-                                 RestoreWindowType window_type);
-
-  // This is called when restored window was created.
-  void OnRestoredWindowCreated(int restore_window_id);
-
-  // This is called before window is shown to request presentation feedback.
-  void OnBeforeRestoredWindowShown(int restore_window_id,
-                                   ui::Compositor* compositor);
-
-  // This is called when restored window was presented.
-  void OnRestoredWindowPresented(int restore_window_id);
-
-  // This is called when the list of shelf icons is initialized.
-  void InitShelfIconList(const ShelfModel* model);
-
-  // This is called when the list of shelf icons is updated.
-  void UpdateShelfIconList(const ShelfModel* model);
-
-  // Remembers ShelfView pointer to watch for shelf animation finish.
-  void SetShelfViewIfNotSet(ShelfView* shelf_view);
-
-  void ResetScopedThroughputReporterBlockerForTesting();
-
-  const ui::TotalAnimationThroughputReporter*
-  login_animation_throughput_reporter() const {
-    return login_animation_throughput_reporter_.get();
-  }
-
  private:
   void OnLoginAnimationFinish(
       base::TimeTicks start,
       const cc::FrameSequenceMetrics::CustomReportData& data);
 
-  void ScheduleWaitForShelfAnimationEnd();
-
-  void OnAllExpectedShelfIconsLoaded();
-
   UiThroughputRecorder ui_recorder_;
-
-  // Set of window IDs ("restore_window_id") that could be restored but
-  // for which windows have not been created yet.
-  base::flat_set<int> windows_to_restore_;
-
-  // Set of window IDs ("restore_window_id") that were created as a part of the
-  // session restore but not yet shown.
-  base::flat_set<int> restore_windows_not_shown_;
-
-  // Set of window IDs ("restore_window_id") that were shown and presentation
-  // time was requested.
-  base::flat_set<int> restore_windows_presentation_time_requested_;
-
-  // Set of window IDs ("restore_window_id") for which presentation time
-  // was received.
-  base::flat_set<int> restore_windows_presented_;
-
-  base::TimeTicks primary_user_logged_in_;
-
-  base::raw_ptr<ShelfView> shelf_view_ = nullptr;
-
-  bool shelf_initialized_ = false;
-
-  bool shelf_icons_loaded_ = false;
-
-  bool user_logged_in_ = false;
-
-  base::WeakPtr<ui::TotalAnimationThroughputReporter>
-      login_animation_throughput_reporter_;
-
-  std::unique_ptr<
-      ui::TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>
-      scoped_throughput_reporter_blocker_;
-
-  base::flat_set<ShelfID> expected_shelf_icons_;
-
   base::WeakPtrFactory<LoginUnlockThroughputRecorder> weak_ptr_factory_{this};
 };
 
diff --git a/ash/metrics/login_unlock_throughput_recorder_unittest.cc b/ash/metrics/login_unlock_throughput_recorder_unittest.cc
deleted file mode 100644
index 9051400..0000000
--- a/ash/metrics/login_unlock_throughput_recorder_unittest.cc
+++ /dev/null
@@ -1,542 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/metrics/login_unlock_throughput_recorder.h"
-
-#include <memory>
-#include <string>
-
-#include "ash/login/ui/login_test_base.h"
-#include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/shelf_item_delegate.h"
-#include "ash/public/cpp/shelf_model.h"
-#include "ash/session/test_session_controller_client.h"
-#include "ash/shell.h"
-#include "ash/wm/tablet_mode/tablet_mode_controller.h"
-#include "base/run_loop.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "chromeos/login/login_state/login_state.h"
-#include "components/app_constants/constants.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/compositor/test/draw_waiter_for_test.h"
-#include "ui/gfx/image/image_unittest_util.h"
-
-namespace ash {
-namespace {
-
-constexpr char kAshLoginAnimationDurationTabletMode[] =
-    "Ash.LoginAnimation.Duration.TabletMode";
-constexpr char kAshLoginAnimationDurationClamshellMode[] =
-    "Ash.LoginAnimation.Duration.ClamshellMode";
-constexpr char kAshUnlockAnimationDurationTabletMode[] =
-    "Ash.UnlockAnimation.Duration.TabletMode";
-constexpr char kAshUnlockAnimationDurationClamshellMode[] =
-    "Ash.UnlockAnimation.Duration.ClamshellMode";
-
-// A test shelf item delegate that simulates an activated window when a shelf
-// item is selected.
-class TestShelfItemDelegate : public ShelfItemDelegate {
- public:
-  explicit TestShelfItemDelegate(const ShelfID& shelf_id)
-      : ShelfItemDelegate(shelf_id) {}
-
-  // ShelfItemDelegate:
-  void ItemSelected(std::unique_ptr<ui::Event> event,
-                    int64_t display_id,
-                    ash::ShelfLaunchSource source,
-                    ItemSelectedCallback callback,
-                    const ItemFilterPredicate& filter_predicate) override {
-    std::move(callback).Run(SHELF_ACTION_WINDOW_ACTIVATED, {});
-  }
-  void ExecuteCommand(bool from_context_menu,
-                      int64_t command_id,
-                      int32_t event_flags,
-                      int64_t display_id) override {}
-  void Close() override {}
-};
-
-class TestShelfModel : public ShelfModel {
- public:
-  TestShelfModel() = default;
-  TestShelfModel(const TestShelfModel&) = delete;
-  TestShelfModel& operator=(const TestShelfModel&) = delete;
-
-  ~TestShelfModel() = default;
-
-  void InitializeIconList(const std::vector<int>& ids) {
-    while (!items().empty())
-      RemoveItemAt(0);
-
-    for (int n : ids) {
-      ShelfItem item;
-      item.id = ShelfID(base::StringPrintf("item%d", n));
-      item.type = TYPE_PINNED_APP;
-      Add(item, std::make_unique<TestShelfItemDelegate>(item.id));
-    }
-  }
-
-  void SetIconsLoadedFor(const std::vector<int>& ids) {
-    for (int n : ids) {
-      const ShelfID id(base::StringPrintf("item%d", n));
-      int index = ItemIndexByID(id);
-      // Expect item exists.
-      ASSERT_GE(index, 0);
-
-      ShelfItem item = items()[index];
-      item.image = gfx::test::CreateImageSkia(/*width=*/10, /*height=*/10);
-
-      Set(index, item);
-    }
-  }
-};
-
-class TestObserver final : public ui::CompositorAnimationObserver {
- public:
-  explicit TestObserver(ui::Compositor* compositor) : compositor_(compositor) {
-    compositor_->AddAnimationObserver(this);
-  }
-  TestObserver(const TestObserver&) = delete;
-  TestObserver& operator=(const TestObserver&) = delete;
-  ~TestObserver() override = default;
-
-  // ui::CompositorAnimationObserver:
-  void OnAnimationStep(base::TimeTicks timestamp) override {
-    ++count_;
-    if (count_ < 3)
-      compositor_->ScheduleFullRedraw();
-    else
-      compositor_->RemoveAnimationObserver(this);
-  }
-
-  void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
-
- private:
-  int count_ = 0;
-  const base::raw_ptr<ui::Compositor> compositor_;
-};
-
-class BeginMainFrameWaiter : public ui::CompositorObserver {
- public:
-  explicit BeginMainFrameWaiter(ui::Compositor* compositor)
-      : compositor_(compositor) {
-    compositor->AddObserver(this);
-  }
-
-  ~BeginMainFrameWaiter() override { compositor_->RemoveObserver(this); }
-
-  // ui::CompositorObserver
-  void OnDidBeginMainFrame(ui::Compositor* compositor) override {
-    DCHECK_EQ(compositor_, compositor);
-    done_ = true;
-    if (run_loop_)
-      run_loop_->Quit();
-  }
-
-  void Wait() {
-    if (done_)
-      return;
-
-    run_loop_ = std::make_unique<base::RunLoop>(
-        base::RunLoop::Type::kNestableTasksAllowed);
-    run_loop_->Run();
-    run_loop_.reset();
-  }
-
- private:
-  const base::raw_ptr<ui::Compositor> compositor_;
-  bool done_ = false;
-  std::unique_ptr<base::RunLoop> run_loop_;
-};
-
-class FirstNonAnimatedFrameStartedWaiter : public ui::CompositorObserver {
- public:
-  explicit FirstNonAnimatedFrameStartedWaiter(ui::Compositor* compositor)
-      : compositor_(compositor) {
-    compositor->AddObserver(this);
-  }
-
-  ~FirstNonAnimatedFrameStartedWaiter() override {
-    compositor_->RemoveObserver(this);
-  }
-
-  // ui::CompositorObserver
-  void OnFirstNonAnimatedFrameStarted(ui::Compositor* compositor) override {
-    DCHECK_EQ(compositor_, compositor);
-    done_ = true;
-    if (run_loop_)
-      run_loop_->Quit();
-  }
-
-  void Wait() {
-    if (done_)
-      return;
-
-    run_loop_ = std::make_unique<base::RunLoop>(
-        base::RunLoop::Type::kNestableTasksAllowed);
-    run_loop_->Run();
-    run_loop_.reset();
-  }
-
- private:
-  ui::Compositor* compositor_;
-  bool done_ = false;
-  std::unique_ptr<base::RunLoop> run_loop_;
-};
-
-void GiveItSomeTime(base::TimeDelta delta) {
-  // Due to the |frames_to_terminate_tracker|=3 constant in
-  // FrameSequenceTracker::ReportSubmitFrame we need to continue generating
-  // frames to receive feedback.
-  base::RepeatingTimer begin_main_frame_scheduler(
-      FROM_HERE, base::Milliseconds(16), base::BindRepeating([]() {
-        auto* compositor =
-            Shell::GetPrimaryRootWindow()->GetHost()->compositor();
-        compositor->ScheduleFullRedraw();
-      }));
-  begin_main_frame_scheduler.Reset();
-
-  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  auto* compositor = Shell::GetPrimaryRootWindow()->GetHost()->compositor();
-  compositor->ScheduleFullRedraw();
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(), delta);
-  run_loop.Run();
-}
-
-class MetricsWaiter {
- public:
-  MetricsWaiter(base::HistogramTester* histogram_tester,
-                std::string metrics_name)
-      : histogram_tester_(histogram_tester), metrics_name_(metrics_name) {}
-
-  MetricsWaiter(const MetricsWaiter&) = delete;
-  MetricsWaiter& operator=(const MetricsWaiter&) = delete;
-
-  ~MetricsWaiter() = default;
-
-  void Wait() {
-    while (histogram_tester_->GetTotalSum(metrics_name_) == 0) {
-      GiveItSomeTime(base::Milliseconds(16));
-    }
-  }
-
- private:
-  base::raw_ptr<base::HistogramTester> histogram_tester_;
-  const std::string metrics_name_;
-};
-
-}  // namespace
-
-// Test fixture for the LoginUnlockThroughputRecorder class.
-class LoginUnlockThroughputRecorderTestBase
-    : public LoginTestBase,
-      public testing::WithParamInterface<bool> {
- public:
-  LoginUnlockThroughputRecorderTestBase() = default;
-
-  LoginUnlockThroughputRecorderTestBase(
-      const LoginUnlockThroughputRecorderTestBase&) = delete;
-  LoginUnlockThroughputRecorderTestBase& operator=(
-      const LoginUnlockThroughputRecorderTestBase&) = delete;
-
-  ~LoginUnlockThroughputRecorderTestBase() override = default;
-
-  // LoginTestBase:
-  void SetUp() override {
-    LoginTestBase::SetUp();
-    histogram_tester_ = std::make_unique<base::HistogramTester>();
-  }
-
-  void LoginOwner() {
-    CreateUserSessions(1);
-    LoginState::Get()->SetLoggedInState(
-        LoginState::LOGGED_IN_ACTIVE,
-        chromeos::LoginState::LOGGED_IN_USER_OWNER);
-  }
-
-  void LockScreenAndAnimate() {
-    GetSessionControllerClient()->LockScreen();
-    RunSimpleAnimation();
-  }
-
-  void UnlockScreenAndAnimate() {
-    GetSessionControllerClient()->UnlockScreen();
-    RunSimpleAnimation();
-  }
-
-  void AddScheduledRestoreBrowserWindows(const std::vector<int>& ids,
-                                         bool is_lacros) {
-    for (int n : ids) {
-      throughput_recorder()->AddScheduledRestoreWindow(
-          n, is_lacros ? app_constants::kLacrosAppId : "",
-          LoginUnlockThroughputRecorder::kBrowser);
-    }
-  }
-
-  void AddScheduledRestoreNonBrowserWindows(const std::vector<int>& ids) {
-    for (int n : ids) {
-      throughput_recorder()->AddScheduledRestoreWindow(
-          n, base::StringPrintf("some_app%d", n),
-          LoginUnlockThroughputRecorder::kBrowser);
-    }
-  }
-
-  void RestoredWindowsCreated(const std::vector<int>& ids) {
-    for (int n : ids) {
-      throughput_recorder()->OnRestoredWindowCreated(n);
-    }
-  }
-
-  void RestoredWindowsShown(const std::vector<int>& ids) {
-    ui::Compositor* compositor =
-        Shell::GetPrimaryRootWindow()->GetHost()->compositor();
-    for (int n : ids) {
-      throughput_recorder()->OnBeforeRestoredWindowShown(n, compositor);
-    }
-  }
-
-  void RestoredWindowsPresented(const std::vector<int>& ids) {
-    for (int n : ids) {
-      throughput_recorder()->OnRestoredWindowPresented(n);
-    }
-  }
-
- protected:
-  void RunSimpleAnimation() {
-    ui::Compositor* compositor =
-        Shell::GetPrimaryRootWindow()->GetHost()->compositor();
-    TestObserver observer(compositor);
-    BeginMainFrameWaiter(compositor).Wait();
-    FirstNonAnimatedFrameStartedWaiter(compositor).Wait();
-    ui::DrawWaiterForTest::WaitForCompositingEnded(compositor);
-  }
-
-  void EnableTabletMode(bool enable) {
-    Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
-  }
-
-  LoginUnlockThroughputRecorder* throughput_recorder() {
-    return Shell::Get()->login_unlock_throughput_recorder();
-  }
-
-  bool IsThroughputRecorderBlocked() {
-    return throughput_recorder()
-        ->login_animation_throughput_reporter()
-        ->IsBlocked();
-  }
-
-  // Used to verify recorded data.
-  std::unique_ptr<base::HistogramTester> histogram_tester_;
-};
-
-using LoginUnlockThroughputRecorderLoginAnimationTest =
-    LoginUnlockThroughputRecorderTestBase;
-
-// Boolean parameter controls tablet mode.
-INSTANTIATE_TEST_SUITE_P(All,
-                         LoginUnlockThroughputRecorderLoginAnimationTest,
-                         testing::Bool());
-
-// Verifies that login animation metrics are reported correctly ignoring shelf
-// initialization.
-TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest,
-       ReportLoginAnimationOnly) {
-  EnableTabletMode(GetParam());
-  const std::string metrics_name =
-      GetParam() ? kAshLoginAnimationDurationTabletMode
-                 : kAshLoginAnimationDurationClamshellMode;
-
-  LoginOwner();
-  RunSimpleAnimation();
-  GiveItSomeTime(base::Milliseconds(100));
-
-  // Should not report login histogram until shelf is initialized.
-  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
-
-  // In this test case we ignore the shelf initialization. Pretend that it
-  // was done.
-  throughput_recorder()->ResetScopedThroughputReporterBlockerForTesting();
-  RunSimpleAnimation();
-
-  MetricsWaiter(histogram_tester_.get(),
-                GetParam() ? kAshLoginAnimationDurationTabletMode
-                           : kAshLoginAnimationDurationClamshellMode)
-      .Wait();
-}
-
-// Verifies that login animation metrics are reported correctly after shelf is
-// initialized.
-TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest,
-       ReportLoginWithShelfInitialization) {
-  EnableTabletMode(GetParam());
-  const std::string metrics_name =
-      GetParam() ? kAshLoginAnimationDurationTabletMode
-                 : kAshLoginAnimationDurationClamshellMode;
-
-  LoginOwner();
-  GiveItSomeTime(base::Milliseconds(100));
-
-  // Should not report login histogram until shelf is initialized.
-  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
-
-  TestShelfModel model;
-  model.InitializeIconList({1, 2, 3, 4, 5, 6});
-
-  // None of the expected shelf items have icons loaded.
-  throughput_recorder()->InitShelfIconList(&model);
-
-  RunSimpleAnimation();
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_TRUE(IsThroughputRecorderBlocked());
-
-  model.SetIconsLoadedFor({1, 2, 3});
-  throughput_recorder()->UpdateShelfIconList(&model);
-  EXPECT_TRUE(IsThroughputRecorderBlocked());
-
-  // Remove last shelf button.
-  model.InitializeIconList({1, 2, 3, 4, 5});
-  model.SetIconsLoadedFor({1, 2, 3});
-  throughput_recorder()->UpdateShelfIconList(&model);
-  EXPECT_TRUE(IsThroughputRecorderBlocked());
-
-  // Add extra buttons.
-  model.InitializeIconList({4, 5, 6, 7, 8, 9});
-  model.SetIconsLoadedFor({7, 8, 9});
-  // Only 4 and 5 are not loaded yet.
-  throughput_recorder()->UpdateShelfIconList(&model);
-  EXPECT_TRUE(IsThroughputRecorderBlocked());
-
-  model.SetIconsLoadedFor({4, 5});
-  // All buttons should have icons.
-  throughput_recorder()->UpdateShelfIconList(&model);
-  // All loaded icons should trigger login histograms.
-  EXPECT_FALSE(IsThroughputRecorderBlocked());
-  EXPECT_GT(histogram_tester_.get()->GetTotalSum(
-                "Ash.LoginSessionRestore.AllShelfIconsLoaded"),
-            0);
-
-  GiveItSomeTime(base::Milliseconds(100));
-  // Should not report login histogram until login animation starts.
-  EXPECT_EQ(histogram_tester_.get()->GetTotalSum(metrics_name), 0);
-  // Shelf metrics should be already reported. Did not specifically start shelf
-  // animations, but it should be reported immediately when there are no shelf
-  // animation.
-  EXPECT_GT(histogram_tester_.get()->GetTotalSum(
-                "Ash.LoginSessionRestore.ShelfLoginAnimationEnd"),
-            0);
-
-  // Start login animation. It should trigger metrics reporting.
-  RunSimpleAnimation();
-  MetricsWaiter(histogram_tester_.get(), metrics_name).Wait();
-}
-
-TEST_P(LoginUnlockThroughputRecorderLoginAnimationTest, ReportUnlock) {
-  LoginOwner();
-
-  EnableTabletMode(GetParam());
-
-  LockScreenAndAnimate();
-  UnlockScreenAndAnimate();
-
-  MetricsWaiter(histogram_tester_.get(),
-                GetParam() ? kAshUnlockAnimationDurationTabletMode
-                           : kAshUnlockAnimationDurationClamshellMode)
-      .Wait();
-}
-
-using LoginUnlockThroughputRecorderWindowRestoreTest =
-    LoginUnlockThroughputRecorderTestBase;
-
-// Boolean parameter controls lacros mode.
-INSTANTIATE_TEST_SUITE_P(All,
-                         LoginUnlockThroughputRecorderWindowRestoreTest,
-                         testing::Bool());
-
-// Verifies that window restore metrics are reported correctly.
-TEST_P(LoginUnlockThroughputRecorderWindowRestoreTest,
-       ReportWindowRestoreMetrics) {
-  const bool is_lacros = GetParam();
-
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  LoginOwner();
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  AddScheduledRestoreBrowserWindows({1, 2, 3, 4, 5, 6}, is_lacros);
-  AddScheduledRestoreNonBrowserWindows({7, 8, 9, 10, 11, 12});
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  // The unexpected windows do not trigger the metrics.
-  RestoredWindowsCreated({21, 22, 23, 24, 25, 26});
-  RestoredWindowsShown({21, 22, 23, 24, 25, 26});
-  RestoredWindowsPresented({21, 22, 23, 24, 25, 26});
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  // Window must go through all of the expected steps
-  // (Created->Shown->Presented). The non-created windows do not trigger
-  // metrics.
-  RestoredWindowsShown({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
-  RestoredWindowsPresented({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  // Only wait for the expected browser windows: expected window 1 is missing.
-  RestoredWindowsCreated({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
-  RestoredWindowsShown({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
-  RestoredWindowsPresented({2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  // Last window created.
-  RestoredWindowsCreated({1});
-  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsCreated"));
-  GiveItSomeTime(base::Milliseconds(100));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-  EXPECT_FALSE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-
-  RestoredWindowsShown({1});
-  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsShown"));
-
-  RestoredWindowsPresented({1});
-  EXPECT_TRUE(histogram_tester_.get()->GetTotalSum(
-      "Ash.LoginSessionRestore.AllBrowserWindowsPresented"));
-}
-
-}  // namespace ash
diff --git a/ash/projector/projector_annotation_tray.cc b/ash/projector/projector_annotation_tray.cc
index d73175e6..f73f889 100644
--- a/ash/projector/projector_annotation_tray.cc
+++ b/ash/projector/projector_annotation_tray.cc
@@ -24,6 +24,7 @@
 #include "components/prefs/pref_service.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer.h"
+#include "ui/events/event.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/separator.h"
@@ -61,7 +62,7 @@
 
 ProjectorTool GetCurrentTool() {
   auto* controller = Shell::Get()->projector_controller();
-  // ProjctorController may not be available yet as the ProjectorAnnotationTray
+  // `controller` may not be available yet as the `ProjectorAnnotationTray`
   // is created before it.
   if (!controller)
     return kToolNone;
@@ -100,6 +101,27 @@
       image_view_(
           tray_container()->AddChildView(std::make_unique<views::ImageView>())),
       pen_view_(nullptr) {
+  SetPressedCallback(base::BindRepeating(
+      [](ProjectorAnnotationTray* projector_annotation_tray,
+         const ui::Event& event) {
+        // NOTE: Long press not supported via the `views::Button` callback, it
+        // is handled via OnGestureEvent override.
+        if (event.IsMouseEvent() &&
+            event.AsMouseEvent()->IsRightMouseButton()) {
+          projector_annotation_tray->ShowBubble();
+          return;
+        }
+
+        projector_annotation_tray->ToggleAnnotator();
+      },
+      base::Unretained(this)));
+  // Right click should show the bubble. In tablet mode, long press is
+  // synonymous with right click, gesture long press must be intercepted via
+  // `OnGestureEvent()` override, as `views::Button` forces long press to show a
+  // contextual menu.
+  SetTriggerableEventFlags(ui::EF_LEFT_MOUSE_BUTTON |
+                           ui::EF_RIGHT_MOUSE_BUTTON);
+
   image_view_->SetTooltipText(GetTooltip());
   image_view_->SetHorizontalAlignment(views::ImageView::Alignment::kCenter);
   image_view_->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
@@ -111,28 +133,18 @@
 
 ProjectorAnnotationTray::~ProjectorAnnotationTray() = default;
 
-bool ProjectorAnnotationTray::PerformAction(const ui::Event& event) {
-  ToggleAnnotator();
-  return true;
-}
-
-void ProjectorAnnotationTray::OnMouseEvent(ui::MouseEvent* event) {
-  if (event->type() != ui::ET_MOUSE_PRESSED) {
+void ProjectorAnnotationTray::OnGestureEvent(ui::GestureEvent* event) {
+  // Long Press typically is used to show a contextual menu, but because in
+  // tablet mode tapping the pod is used to toggle a feature, long press is the
+  // only available way to show the bubble.
+  // TODO(crbug/1374368): Put this where we handle other button activations,
+  // once the `views::Button` code allows it.
+  if (event->details().type() != ui::ET_GESTURE_LONG_PRESS) {
+    TrayBackgroundView::OnGestureEvent(event);
     return;
   }
-  if (event->IsRightMouseButton()) {
-    ShowBubble();
-  } else if (event->IsLeftMouseButton()) {
-    ToggleAnnotator();
-  }
-}
 
-void ProjectorAnnotationTray::OnGestureEvent(ui::GestureEvent* event) {
-  if (event->details().type() == ui::ET_GESTURE_LONG_PRESS) {
-    ShowBubble();
-  } else if (event->details().type() == ui::ET_GESTURE_TAP) {
-    ToggleAnnotator();
-  }
+  ShowBubble();
 }
 
 void ProjectorAnnotationTray::ClickedOutsideBubble() {
diff --git a/ash/projector/projector_annotation_tray.h b/ash/projector/projector_annotation_tray.h
index e11414e..442d018 100644
--- a/ash/projector/projector_annotation_tray.h
+++ b/ash/projector/projector_annotation_tray.h
@@ -11,6 +11,15 @@
 #include "ash/system/tray/view_click_listener.h"
 #include "base/scoped_observation.h"
 
+namespace ui {
+class GestureEvent;
+}  // namespace ui
+
+namespace views {
+class ImageView;
+class Widget;
+}  // namespace views
+
 namespace ash {
 
 class HoverHighlightView;
@@ -34,7 +43,7 @@
   ~ProjectorAnnotationTray() override;
 
   // TrayBackgroundView:
-  bool PerformAction(const ui::Event& event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
   void ClickedOutsideBubble() override;
   std::u16string GetAccessibleNameForTray() override;
   void HandleLocaleChange() override;
@@ -43,8 +52,6 @@
   void ShowBubble() override;
   TrayBubbleView* GetBubbleView() override;
   views::Widget* GetBubbleWidget() const override;
-  void OnMouseEvent(ui::MouseEvent* event) override;
-  void OnGestureEvent(ui::GestureEvent* event) override;
   void OnThemeChanged() override;
 
   // SessionObserver:
diff --git a/ash/projector/projector_ui_controller_unittest.cc b/ash/projector/projector_ui_controller_unittest.cc
index 13ed3159..1e440fb 100644
--- a/ash/projector/projector_ui_controller_unittest.cc
+++ b/ash/projector/projector_ui_controller_unittest.cc
@@ -24,6 +24,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_observer.h"
@@ -206,6 +207,77 @@
                                       /*count=*/1);
 }
 
+// Tests that right clicking the ProjectorAnnotationTray shows a bubble.
+TEST_F(ProjectorUiControllerTest, RightClickShowsBubble) {
+  controller_->ShowAnnotationTray(Shell::GetPrimaryRootWindow());
+  controller_->OnCanvasInitialized(true);
+
+  auto* projector_annotation_tray = Shell::GetPrimaryRootWindowController()
+                                        ->GetStatusAreaWidget()
+                                        ->projector_annotation_tray();
+
+  // Right click the tray item, it should show a bubble.
+  RightClickOn(projector_annotation_tray);
+  EXPECT_TRUE(projector_annotation_tray->GetBubbleWidget());
+}
+
+// Tests that long pressing the ProjectorAnnotationTray shows a bubble.
+TEST_F(ProjectorUiControllerTest, LongPressShowsBubble) {
+  controller_->ShowAnnotationTray(Shell::GetPrimaryRootWindow());
+  controller_->OnCanvasInitialized(true);
+
+  auto* projector_annotation_tray = Shell::GetPrimaryRootWindowController()
+                                        ->GetStatusAreaWidget()
+                                        ->projector_annotation_tray();
+
+  // Long press the tray item, it should show a bubble.
+  gfx::Point location =
+      projector_annotation_tray->GetBoundsInScreen().CenterPoint();
+
+  // Temporarily reconfigure gestures so that the long press takes 2
+  // milliseconds.
+  ui::GestureConfiguration* gesture_config =
+      ui::GestureConfiguration::GetInstance();
+  const int old_long_press_time_in_ms = gesture_config->long_press_time_in_ms();
+  const base::TimeDelta old_short_press_time =
+      gesture_config->short_press_time();
+  const int old_show_press_delay_in_ms =
+      gesture_config->show_press_delay_in_ms();
+  gesture_config->set_long_press_time_in_ms(1);
+  gesture_config->set_short_press_time(base::Milliseconds(1));
+  gesture_config->set_show_press_delay_in_ms(1);
+
+  ui::test::EventGenerator* event_generator = GetEventGenerator();
+  event_generator->set_current_screen_location(location);
+  event_generator->PressTouch();
+
+  // Hold the press down for 2 ms, to trigger a long press.
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(2));
+  run_loop.Run();
+
+  gesture_config->set_long_press_time_in_ms(old_long_press_time_in_ms);
+  gesture_config->set_short_press_time(old_short_press_time);
+  gesture_config->set_show_press_delay_in_ms(old_show_press_delay_in_ms);
+
+  event_generator->ReleaseTouch();
+
+  EXPECT_TRUE(projector_annotation_tray->GetBubbleWidget());
+}
+
+// Tests that tapping the ProjectorAnnotationTray enables annotation.
+TEST_F(ProjectorUiControllerTest, TapEnabledAnnotation) {
+  controller_->ShowAnnotationTray(Shell::GetPrimaryRootWindow());
+  controller_->OnCanvasInitialized(true);
+
+  GestureTapOn(Shell::GetPrimaryRootWindowController()
+                   ->GetStatusAreaWidget()
+                   ->projector_annotation_tray());
+
+  EXPECT_TRUE(controller_->is_annotator_enabled());
+}
+
 TEST_F(ProjectorUiControllerTest, ShowFailureNotification) {
   base::HistogramTester histogram_tester;
 
diff --git a/ash/public/cpp/app_list/app_list_color_provider.h b/ash/public/cpp/app_list/app_list_color_provider.h
index 94bd32e6..cc418b8 100644
--- a/ash/public/cpp/app_list/app_list_color_provider.h
+++ b/ash/public/cpp/app_list/app_list_color_provider.h
@@ -65,7 +65,6 @@
       const views::Widget* app_list_widget) const = 0;
   virtual SkColor GetGridBackgroundCardInactiveColor(
       const views::Widget* app_list_widget) const = 0;
-  virtual ui::ColorId GetSeparatorColorId() const = 0;
   virtual SkColor GetFocusRingColor(
       const views::Widget* app_list_widget) const = 0;
   virtual SkColor GetInkDropBaseColor(
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index 3d42d8e..65462e6 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -237,14 +237,11 @@
 }  // namespace
 
 SharedAppListConfig& SharedAppListConfig::instance() {
-  static base::NoDestructor<SharedAppListConfig> shared_config;
-  return *shared_config;
+  static SharedAppListConfig shared_config;
+  return shared_config;
 }
 
-SharedAppListConfig::SharedAppListConfig()
-    : search_result_title_font_style_(ui::ResourceBundle::BaseFont),
-      search_result_recommendation_title_font_(
-          ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(1)) {}
+SharedAppListConfig::SharedAppListConfig() = default;
 
 int SharedAppListConfig::GetMaxNumOfItemsPerPage() const {
   return 20;
diff --git a/ash/public/cpp/app_list/app_list_config.h b/ash/public/cpp/app_list/app_list_config.h
index b9e9e79..62e175e 100644
--- a/ash/public/cpp/app_list/app_list_config.h
+++ b/ash/public/cpp/app_list/app_list_config.h
@@ -33,8 +33,6 @@
 
   size_t max_search_results() const { return max_search_results_; }
 
-  size_t max_search_result_tiles() const { return max_search_result_tiles_; }
-
   size_t max_search_result_list_items() const {
     return max_search_result_list_items_;
   }
@@ -85,14 +83,6 @@
     return suggestion_chip_icon_dimension_;
   }
 
-  ui::ResourceBundle::FontStyle search_result_title_font_style() const {
-    return search_result_title_font_style_;
-  }
-
-  gfx::FontList search_result_recommendation_title_font() const {
-    return search_result_recommendation_title_font_;
-  }
-
   int search_tile_height() const { return search_tile_height_; }
 
   // Returns the maximum number of items allowed in a page in the apps grid.
@@ -102,7 +92,7 @@
   int GetPreferredIconDimension(SearchResultDisplayType display_type) const;
 
  private:
-  friend class base::NoDestructor<SharedAppListConfig>;
+  friend class SharedAppListConfig;
   SharedAppListConfig();
 
   // The icon dimension of tile views in apps grid view.
@@ -111,9 +101,6 @@
   // Maximum number of results to show in the launcher Search UI.
   const size_t max_search_results_ = 6;
 
-  // Max number of search result tiles in the launcher suggestion window.
-  const size_t max_search_result_tiles_ = 6;
-
   // Max number of search result list items in the launcher suggestion window.
   const size_t max_search_result_list_items_ = 5;
 
@@ -143,14 +130,6 @@
   // The suggestion chip icon dimension.
   const int suggestion_chip_icon_dimension_ = 20;
 
-  // Font style for AppListSearchResultItemViews that are not suggested
-  // apps.
-  const ui::ResourceBundle::FontStyle search_result_title_font_style_;
-
-  // Font style for AppListSearchResultTileItemViews that are suggested
-  // apps.
-  const gfx::FontList search_result_recommendation_title_font_;
-
   // The height of tiles in search result.
   const int search_tile_height_ = 92;
 };
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index 7fa114c..62b594d 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -50,6 +50,9 @@
 BASE_FEATURE(kLauncherPlayStoreSearch,
              "LauncherPlayStoreSearch",
              base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kAnimateScaleOnTabletModeTransition,
+             "AnimateScaleOnTabletModeTransition",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsAppRankerEnabled() {
   return base::FeatureList::IsEnabled(kEnableAppRanker);
@@ -129,4 +132,8 @@
          base::FeatureList::IsEnabled(kLauncherPlayStoreSearch);
 }
 
+bool IsAnimateScaleOnTabletModeTransitionEnabled() {
+  return base::FeatureList::IsEnabled(kAnimateScaleOnTabletModeTransition);
+}
+
 }  // namespace app_list_features
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h
index a2696c56..97de35ee 100644
--- a/ash/public/cpp/app_list/app_list_features.h
+++ b/ash/public/cpp/app_list/app_list_features.h
@@ -63,6 +63,10 @@
 // Enables Play Store search in the launcher.
 ASH_PUBLIC_EXPORT BASE_DECLARE_FEATURE(kLauncherPlayStoreSearch);
 
+// Enables new tablet <-> clamshell mode transition animation (scale + opacity
+// instead of slide up/down).
+ASH_PUBLIC_EXPORT BASE_DECLARE_FEATURE(kAnimateScaleOnTabletModeTransition);
+
 ASH_PUBLIC_EXPORT bool IsAppRankerEnabled();
 ASH_PUBLIC_EXPORT bool IsZeroStateAppsRankerEnabled();
 ASH_PUBLIC_EXPORT bool IsZeroStateMixedTypesRankerEnabled();
@@ -79,6 +83,7 @@
 ASH_PUBLIC_EXPORT base::TimeDelta DynamicSearchUpdateAnimationDuration();
 ASH_PUBLIC_EXPORT bool IsCompactBubbleLauncherEnabled();
 ASH_PUBLIC_EXPORT bool IsLauncherPlayStoreSearchEnabled();
+ASH_PUBLIC_EXPORT bool IsAnimateScaleOnTabletModeTransitionEnabled();
 
 ASH_PUBLIC_EXPORT std::string AppSearchResultRankerPredictorName();
 ASH_PUBLIC_EXPORT std::string CategoricalSearchType();
diff --git a/ash/public/cpp/test/test_app_list_color_provider.cc b/ash/public/cpp/test/test_app_list_color_provider.cc
index 545886b..cbddd35f 100644
--- a/ash/public/cpp/test/test_app_list_color_provider.cc
+++ b/ash/public/cpp/test/test_app_list_color_provider.cc
@@ -104,10 +104,6 @@
   return SkColorSetA(SK_ColorWHITE, 41 /* 16% */);
 }
 
-ui::ColorId TestAppListColorProvider::GetSeparatorColorId() const {
-  return ui::kColorAshSystemUIMenuSeparator;
-}
-
 SkColor TestAppListColorProvider::GetFocusRingColor(
     const views::Widget* app_list_widget) const {
   return gfx::kGoogleBlue600;
diff --git a/ash/public/cpp/test/test_app_list_color_provider.h b/ash/public/cpp/test/test_app_list_color_provider.h
index 2ff5c222..7a002052 100644
--- a/ash/public/cpp/test/test_app_list_color_provider.h
+++ b/ash/public/cpp/test/test_app_list_color_provider.h
@@ -58,7 +58,6 @@
       const views::Widget* app_list_widget) const override;
   SkColor GetGridBackgroundCardInactiveColor(
       const views::Widget* app_list_widget) const override;
-  ui::ColorId GetSeparatorColorId() const override;
   SkColor GetFocusRingColor(
       const views::Widget* app_list_widget) const override;
   SkColor GetInkDropBaseColor(
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 5ddea72..18df6440f 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -10,7 +10,6 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_switches.h"
-#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -19,7 +18,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/shelf/hotseat_widget.h"
 #include "ash/shelf/login_shelf_widget.h"
-#include "ash/shelf/scrollable_shelf_view.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_focus_cycler.h"
 #include "ash/shelf/shelf_layout_manager.h"
@@ -408,8 +406,6 @@
   hotseat_transition_metrics_reporter_ =
       std::make_unique<HotseatWidgetAnimationMetricsReporter>(
           HotseatWidgetAnimationMetricsReporter::HotseatElementType::kWidget);
-  Shell::Get()->login_unlock_throughput_recorder()->SetShelfViewIfNotSet(
-      hotseat_widget_->scrollable_shelf_view()->shelf_view());
 }
 
 void Shelf::CreateStatusAreaWidget(aura::Window* shelf_container) {
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 696ab55..c417f718 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -1213,6 +1213,8 @@
   drag_icon_bounds_in_screen_ = gfx::Rect();
   drag_and_drop_shelf_id_ = ShelfID();
   is_active_drag_and_drop_host_ = false;
+
+  HandleShelfParty();
 }
 
 void ShelfView::SwapButtons(views::View* button_to_swap, bool with_next) {
@@ -1985,15 +1987,6 @@
   return drag_icon_proxy_->GetBoundsInScreen();
 }
 
-void ShelfView::AddAnimationObserver(views::BoundsAnimatorObserver* observer) {
-  bounds_animator_->AddObserver(observer);
-}
-
-void ShelfView::RemoveAnimationObserver(
-    views::BoundsAnimatorObserver* observer) {
-  bounds_animator_->RemoveObserver(observer);
-}
-
 void ShelfView::AnnounceShelfAutohideBehavior() {
   std::u16string announcement;
   switch (shelf_->auto_hide_behavior()) {
@@ -2225,6 +2218,8 @@
     AnnouncePinUnpinEvent(old_item, /*pinned=*/false);
     RecordPinUnpinUserAction(/*pinned=*/false);
   }
+
+  party_.erase(old_item.id);
 }
 
 void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) {
@@ -2679,6 +2674,8 @@
     }
     DCHECK(IsItemPinned(item));
     DCHECK(!IsItemVisible(item));
+    if (item.image.isNull() || item.id == drag_and_drop_shelf_id_)
+      continue;
     // Add the item if it is not already partying.
     const auto insertion_results = party_.try_emplace(item.id);
     if (insertion_results.second) {
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index c75b823..3cdf669 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -326,9 +326,6 @@
     return current_ghost_view_index_;
   }
 
-  void AddAnimationObserver(views::BoundsAnimatorObserver* observer);
-  void RemoveAnimationObserver(views::BoundsAnimatorObserver* observer);
-
  private:
   friend class ShelfViewTestAPI;
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 007817a..b87835c 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -2333,39 +2333,6 @@
   EXPECT_EQ(0, GetHapticTickEventsCount());
 }
 
-// Verifies that partying items are hidden from the shelf.
-// TODO(crbug/1372295): This test consistently times out.
-TEST_P(LtrRtlShelfViewTest, DISABLED_PartyingItemsHiddenFromShelf) {
-  AddAppShortcut();
-  AddAppShortcut();
-  AddApp();
-  ShelfItem item = model_->items()[1u];
-  item.status = STATUS_RUNNING;
-  model_->Set(1, item);
-  const gfx::Rect initial_bounds0 = test_api_->GetBoundsByIndex(0);
-  const gfx::Rect initial_bounds2 = test_api_->GetBoundsByIndex(2);
-
-  // Start shelf party.
-  model_->ToggleShelfParty();
-  {
-    const std::vector<size_t> not_partying = {1, 3};
-    EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
-  }
-  test_api_->RunMessageLoopUntilAnimationsDone();
-  EXPECT_TRUE(test_api_->GetBoundsByIndex(0).IsEmpty());
-  EXPECT_TRUE(test_api_->GetBoundsByIndex(2).IsEmpty());
-
-  // End shelf party.
-  model_->ToggleShelfParty();
-  {
-    const std::vector<size_t> not_partying = {0, 1, 2, 3};
-    EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
-  }
-  test_api_->RunMessageLoopUntilAnimationsDone();
-  EXPECT_EQ(initial_bounds0, test_api_->GetBoundsByIndex(0));
-  EXPECT_EQ(initial_bounds2, test_api_->GetBoundsByIndex(2));
-}
-
 // Test class that tests both context and application menus.
 class ShelfViewMenuTest : public ShelfViewTest,
                           public testing::WithParamInterface<bool> {
@@ -3665,4 +3632,36 @@
   test_api_->RunMessageLoopUntilAnimationsDone();
 }
 
+// Verifies that partying items are hidden from the shelf.
+TEST_P(ShelfPartyTest, PartyingItemsHiddenFromShelf) {
+  AddAppShortcut();
+  AddAppShortcut();
+  AddApp();
+  ShelfItem item = model_->items()[1u];
+  item.status = STATUS_RUNNING;
+  model_->Set(1, item);
+  const gfx::Rect initial_bounds0 = test_api_->GetBoundsByIndex(0);
+  const gfx::Rect initial_bounds2 = test_api_->GetBoundsByIndex(2);
+
+  // Start shelf party.
+  model_->ToggleShelfParty();
+  {
+    const std::vector<size_t> not_partying = {1, 3};
+    EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
+  }
+  task_environment()->FastForwardBy(base::Seconds(1));
+  EXPECT_TRUE(test_api_->GetBoundsByIndex(0).IsEmpty());
+  EXPECT_TRUE(test_api_->GetBoundsByIndex(2).IsEmpty());
+
+  // End shelf party.
+  model_->ToggleShelfParty();
+  {
+    const std::vector<size_t> not_partying = {0, 1, 2, 3};
+    EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
+  }
+  test_api_->RunMessageLoopUntilAnimationsDone();
+  EXPECT_EQ(initial_bounds0, test_api_->GetBoundsByIndex(0));
+  EXPECT_EQ(initial_bounds2, test_api_->GetBoundsByIndex(2));
+}
+
 }  // namespace ash
diff --git a/ash/shell.h b/ash/shell.h
index 51dfdb29..fd54b4bf 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -738,10 +738,6 @@
   void NotifyShelfAlignmentChanged(aura::Window* root_window,
                                    ShelfAlignment old_alignment);
 
-  LoginUnlockThroughputRecorder* login_unlock_throughput_recorder() {
-    return login_unlock_throughput_recorder_.get();
-  }
-
  private:
   FRIEND_TEST_ALL_PREFIXES(ExtendedDesktopTest, TestCursor);
   FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, MouseEventCursors);
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index aa3eb7d..8a140794 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -74,9 +74,6 @@
 // The size of the icons appearing in the material design system tray.
 constexpr int kTrayIconSize = 16;
 
-// The padding on top of the time tray icon when vertically aligned.
-constexpr int kTrayTimeIconTopPadding = 2;
-
 // The padding around network tray icon in dip.
 constexpr int kTrayNetworkIconPadding = 2;
 constexpr int kUnifiedTrayNetworkIconPadding = 4;
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 7723a95..c4e048e 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -222,18 +222,14 @@
   notification_icons_controller_->AddNotificationTrayItems(tray_container());
   for (TrayItemView* tray_item : notification_icons_controller_->tray_items()) {
     tray_items_.push_back(tray_item);
-    AddObservedTrayItem(tray_item);
   }
 
   AddTrayItemToContainer(screen_capture_view_);
 
   tray_items_.push_back(
       notification_icons_controller_->notification_counter_view());
-  AddObservedTrayItem(
-      notification_icons_controller_->notification_counter_view());
 
   tray_items_.push_back(notification_icons_controller_->quiet_mode_view());
-  AddObservedTrayItem(notification_icons_controller_->quiet_mode_view());
 
   if (features::IsSnoopingProtectionEnabled())
     AddTrayItemToContainer(snooping_protection_view_);
@@ -267,12 +263,6 @@
     AddTrayItemToContainer(channel_indicator_view_);
   }
 
-  auto vertical_clock_padding = std::make_unique<views::View>();
-  vertical_clock_padding->SetPreferredSize(gfx::Size(
-      0, features::IsCalendarViewEnabled() ? 0 : kTrayTimeIconTopPadding));
-  vertical_clock_padding_ =
-      tray_container()->AddChildView(std::move(vertical_clock_padding));
-
   if (!features::IsCalendarViewEnabled()) {
     AddTrayItemToContainer(time_view_);
   }
@@ -284,12 +274,10 @@
   set_use_bounce_in_animation(false);
 
   ShelfConfig::Get()->AddObserver(this);
-  Shell::Get()->AddShellObserver(this);
 }
 
 UnifiedSystemTray::~UnifiedSystemTray() {
   ShelfConfig::Get()->RemoveObserver(this);
-  Shell::Get()->RemoveShellObserver(this);
 
   DestroyBubbles();
 
@@ -308,38 +296,6 @@
     observers_.RemoveObserver(observer);
 }
 
-bool UnifiedSystemTray::MoreThanOneVisibleTrayItem() const {
-  bool one_visible_item = false;
-  for (TrayItemView* item : tray_items_) {
-    if (!item->GetVisible())
-      continue;
-    if (one_visible_item)
-      return true;
-    one_visible_item = true;
-  }
-  return false;
-}
-
-void UnifiedSystemTray::MaybeUpdateVerticalClockPadding() {
-  const bool padding_is_visible = vertical_clock_padding_->GetVisible();
-
-  if (shelf()->IsHorizontalAlignment()) {
-    if (padding_is_visible)
-      vertical_clock_padding_->SetVisible(false);
-    return;
-  }
-
-  // Padding is shown when an icon besides TimeView is visible.
-  const bool should_show_padding = MoreThanOneVisibleTrayItem();
-  if (padding_is_visible != should_show_padding)
-    vertical_clock_padding_->SetVisible(should_show_padding);
-}
-
-void UnifiedSystemTray::OnViewVisibilityChanged(views::View* observed_view,
-                                                views::View* starting_view) {
-  MaybeUpdateVerticalClockPadding();
-}
-
 bool UnifiedSystemTray::IsBubbleShown() const {
   return !!bubble_;
 }
@@ -496,11 +452,6 @@
   return absl::make_optional(TOGGLE_SYSTEM_TRAY_BUBBLE);
 }
 
-void UnifiedSystemTray::OnShelfAlignmentChanged(aura::Window* root_window,
-                                                ShelfAlignment old_alignment) {
-  MaybeUpdateVerticalClockPadding();
-}
-
 void UnifiedSystemTray::OnShelfConfigUpdated() {
   // Ensure the margin is updated correctly depending on whether dense shelf
   // is currently shown or not.
@@ -777,11 +728,6 @@
 void UnifiedSystemTray::AddTrayItemToContainer(TrayItemView* tray_item) {
   tray_items_.push_back(tray_item);
   tray_container()->AddChildView(tray_item);
-  AddObservedTrayItem(tray_item);
-}
-
-void UnifiedSystemTray::AddObservedTrayItem(TrayItemView* tray_item) {
-  tray_items_observations_.AddObservation(tray_item);
 }
 
 void UnifiedSystemTray::DestroyBubbles() {
diff --git a/ash/system/unified/unified_system_tray.h b/ash/system/unified/unified_system_tray.h
index 04aef94..fbfd8fc 100644
--- a/ash/system/unified/unified_system_tray.h
+++ b/ash/system/unified/unified_system_tray.h
@@ -11,7 +11,6 @@
 #include "ash/ash_export.h"
 #include "ash/public/cpp/accelerators.h"
 #include "ash/public/cpp/shelf_config.h"
-#include "ash/shell_observer.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/time/time_view.h"
 #include "ash/system/tray/tray_background_view.h"
@@ -19,7 +18,6 @@
 #include "ash/system/unified/unified_system_tray_model.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/scoped_multi_source_observation.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 
@@ -64,7 +62,6 @@
 class ASH_EXPORT UnifiedSystemTray
     : public TrayBackgroundView,
       public ShelfConfig::Observer,
-      public ShellObserver,
       public UnifiedSystemTrayController::Observer {
  public:
   class Observer : public base::CheckedObserver {
@@ -86,14 +83,6 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // Adds a padding on top of the vertical clock if there are other visible
-  // icons in the tray, removes it if the clock is the only visible icon.
-  void MaybeUpdateVerticalClockPadding();
-
-  // views::ViewObserver:
-  void OnViewVisibilityChanged(views::View* observed_view,
-                               views::View* starting_view) override;
-
   // True if the bubble is shown. It does not include slider bubbles, and when
   // they're shown it still returns false.
   bool IsBubbleShown() const;
@@ -200,10 +189,6 @@
   const char* GetClassName() const override;
   absl::optional<AcceleratorAction> GetAcceleratorAction() const override;
 
-  // ShellObserver:
-  void OnShelfAlignmentChanged(aura::Window* root_window,
-                               ShelfAlignment old_alignment) override;
-
   // ShelfConfig::Observer:
   void OnShelfConfigUpdated() override;
 
@@ -265,12 +250,6 @@
   // The container takes the ownership of |tray_item|.
   void AddTrayItemToContainer(TrayItemView* tray_item);
 
-  // Returns true if there is two or more tray items that are visible.
-  bool MoreThanOneVisibleTrayItem() const;
-
-  // Add observed tray item views.
-  void AddObservedTrayItem(TrayItemView* tray_item);
-
   // Destroys the `bubble_` and the `message_center_bubble_`, also handles
   // removing bubble related observers.
   void DestroyBubbles();
@@ -312,13 +291,6 @@
   // Contains all tray items views added to tray_container().
   std::list<TrayItemView*> tray_items_;
 
-  base::ScopedMultiSourceObservation<views::View, views::ViewObserver>
-      tray_items_observations_{this};
-
-  // Padding owned by the view hierarchy used to separate vertical
-  // clock from other tray icons.
-  views::View* vertical_clock_padding_ = nullptr;
-
   base::OneShotTimer timer_;
 
   bool first_interaction_recorded_ = false;
diff --git a/ash/system/unified/unified_system_tray_unittest.cc b/ash/system/unified/unified_system_tray_unittest.cc
index d04a346c..4ce2392 100644
--- a/ash/system/unified/unified_system_tray_unittest.cc
+++ b/ash/system/unified/unified_system_tray_unittest.cc
@@ -87,10 +87,6 @@
         ->slider_bubble_controller_->bubble_widget_;
   }
 
-  bool MoreThanOneVisibleTrayItem() const {
-    return GetPrimaryUnifiedSystemTray()->MoreThanOneVisibleTrayItem();
-  }
-
   UnifiedSliderBubbleController::SliderType GetSliderBubbleType() {
     return GetPrimaryUnifiedSystemTray()
         ->slider_bubble_controller_->slider_type_;
@@ -124,14 +120,6 @@
     return GetPrimaryUnifiedSystemTray()->ime_mode_view_;
   }
 
-  std::list<TrayItemView*> tray_items() {
-    return GetPrimaryUnifiedSystemTray()->tray_items_;
-  }
-
-  views::View* vertical_clock_padding() {
-    return GetPrimaryUnifiedSystemTray()->vertical_clock_padding_;
-  }
-
  private:
   int id_ = 0;
   base::test::ScopedFeatureList feature_list_;
@@ -280,42 +268,6 @@
   EXPECT_EQ(time_bounds.height(), ime_bounds.height());
 }
 
-TEST_P(UnifiedSystemTrayTest, VerticalClockPadding) {
-  // Padding can only be visible if shelf is vertically aligned.
-  GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
-
-  // Sets all tray items' visibility to false except TimeView.
-  for (TrayItemView* item : tray_items()) {
-    item->SetVisible(item == time_view());
-  }
-
-  // Only one visible tray item, padding should not be visible.
-  EXPECT_FALSE(vertical_clock_padding()->GetVisible());
-
-  // Sets another tray item visibility to true.
-  ime_mode_view()->SetVisible(true);
-
-  // Two visible tray items, padding should be visible.
-  EXPECT_TRUE(vertical_clock_padding()->GetVisible());
-}
-
-TEST_P(UnifiedSystemTrayTest, VerticalClockPaddingAfterAlignmentChange) {
-  auto* shelf = GetPrimaryShelf();
-
-  // Padding can only be visible if shelf is vertically aligned.
-  shelf->SetAlignment(ShelfAlignment::kLeft);
-
-  // Ensure two tray items are visible, padding should be visible.
-  time_view()->SetVisible(true);
-  ime_mode_view()->SetVisible(true);
-
-  EXPECT_TRUE(vertical_clock_padding()->GetVisible());
-
-  // Padding should not be visible when shelf is horizontal.
-  shelf->SetAlignment(ShelfAlignment::kBottom);
-  EXPECT_FALSE(vertical_clock_padding()->GetVisible());
-}
-
 TEST_P(UnifiedSystemTrayTest, FocusMessageCenter) {
   if (IsQsRevampEnabled())
     return;
diff --git a/ash/webui/os_feedback_ui/resources/confirmation_page.js b/ash/webui/os_feedback_ui/resources/confirmation_page.js
index 927a7628..c980a05 100644
--- a/ash/webui/os_feedback_ui/resources/confirmation_page.js
+++ b/ash/webui/os_feedback_ui/resources/confirmation_page.js
@@ -134,7 +134,7 @@
   handleLinkClicked_(e) {
     e.stopPropagation();
 
-    switch (e.target.id) {
+    switch (e.currentTarget.id) {
       case 'diagnostics':
         this.feedbackServiceProvider_.openDiagnosticsApp();
         this.handleEmitMetrics_(
@@ -154,7 +154,7 @@
             FeedbackAppPostSubmitAction.kOpenChromebookCommunity);
         break;
       default:
-        console.warn('unexpected caller id: ', e.target.id);
+        console.warn('unexpected caller id: ', e.currentTarget.id);
     }
   }
 
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom
index 9a67853..77c1f2c1 100644
--- a/ash/webui/personalization_app/mojom/personalization_app.mojom
+++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -167,9 +167,6 @@
 
 // Represents the currently selected wallpaper image.
 struct CurrentWallpaper {
-  // URL of the currently selected wallpaper image in data scheme.
-  url.mojom.Url url;
-
   // Attribution text such as "Photo by John Doe" or the file name of the local
   // image.
   array<string> attribution;
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 0a15295..0cba04ec 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -6,6 +6,7 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
+#include "ash/public/cpp/wallpaper/wallpaper_controller.h"
 #include "ash/rgb_keyboard/rgb_keyboard_manager.h"
 #include "ash/shell.h"
 #include "ash/webui/grit/ash_personalization_app_resources.h"
@@ -17,9 +18,12 @@
 #include "ash/webui/personalization_app/personalization_app_user_provider.h"
 #include "ash/webui/personalization_app/personalization_app_wallpaper_provider.h"
 #include "base/check.h"
+#include "base/containers/contains.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/url_constants.h"
@@ -259,6 +263,10 @@
   source->EnableReplaceI18nInJS();
 }
 
+bool ShouldHandleWebUIRequest(const std::string& path) {
+  return base::StartsWith(path, "wallpaper.png");
+}
+
 }  // namespace
 
 PersonalizationAppUI::PersonalizationAppUI(
@@ -281,6 +289,12 @@
       web_ui->GetWebContents()->GetBrowserContext(),
       kChromeUIPersonalizationAppHost);
 
+  // Supply a custom wallpaper image.
+  source->SetRequestFilter(
+      base::BindRepeating(&ShouldHandleWebUIRequest),
+      base::BindRepeating(&PersonalizationAppUI::HandleWebUIRequest,
+                          weak_ptr_factory_.GetWeakPtr()));
+
   source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::ScriptSrc,
       "script-src chrome://resources chrome://test chrome://webui-test "
@@ -358,6 +372,14 @@
   source->AddBoolean("isJellyEnabled", features::IsJellyEnabled());
 }
 
+void PersonalizationAppUI::HandleWebUIRequest(
+    const std::string& path,
+    content::WebUIDataSource::GotDataCallback callback) {
+  DCHECK(base::Contains(path, "?key="))
+      << "wallpaper key must be provided to prevent browser cache collisions";
+  wallpaper_provider_->GetWallpaperAsPngBytes(std::move(callback));
+}
+
 WEB_UI_CONTROLLER_TYPE_IMPL(PersonalizationAppUI)
 
 }  // namespace ash::personalization_app
diff --git a/ash/webui/personalization_app/personalization_app_ui.h b/ash/webui/personalization_app/personalization_app_ui.h
index 71f9e91..378525d 100644
--- a/ash/webui/personalization_app/personalization_app_ui.h
+++ b/ash/webui/personalization_app/personalization_app_ui.h
@@ -8,6 +8,8 @@
 #include <memory>
 
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom-forward.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 #include "ui/webui/resources/cr_components/color_change_listener/color_change_listener.mojom.h"
@@ -69,6 +71,10 @@
 
  private:
   void AddBooleans(content::WebUIDataSource* source);
+
+  void HandleWebUIRequest(const std::string& path,
+                          content::WebUIDataSource::GotDataCallback callback);
+
   std::unique_ptr<PersonalizationAppAmbientProvider> ambient_provider_;
   std::unique_ptr<PersonalizationAppKeyboardBacklightProvider>
       keyboard_backlight_provider_;
@@ -79,6 +85,8 @@
   // changes.
   std::unique_ptr<ui::ColorChangeHandler> color_provider_handler_;
 
+  base::WeakPtrFactory<PersonalizationAppUI> weak_ptr_factory_{this};
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/ash/webui/personalization_app/personalization_app_wallpaper_provider.h b/ash/webui/personalization_app/personalization_app_wallpaper_provider.h
index 1517aef..66e6863 100644
--- a/ash/webui/personalization_app/personalization_app_wallpaper_provider.h
+++ b/ash/webui/personalization_app/personalization_app_wallpaper_provider.h
@@ -6,6 +6,7 @@
 #define ASH_WEBUI_PERSONALIZATION_APP_PERSONALIZATION_APP_WALLPAPER_PROVIDER_H_
 
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace ash::personalization_app {
@@ -17,6 +18,9 @@
   virtual void BindInterface(
       mojo::PendingReceiver<mojom::WallpaperProvider> receiver) = 0;
 
+  virtual void GetWallpaperAsPngBytes(
+      content::WebUIDataSource::GotDataCallback callback) = 0;
+
   // Not all users that can view the personalization app can also see google
   // photos. Users without a gaia account cannot use the photos APIs.
   virtual bool IsEligibleForGooglePhotos() = 0;
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/utils.ts b/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
index e502133..4ae5566 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/utils.ts
@@ -121,3 +121,19 @@
   }
   return attribution;
 }
+
+/**
+ * Get a url to download a high quality preview of the current wallpaper.
+ * Responds with null in case |image| is invalid or null.
+ */
+export function getWallpaperSrc(image: CurrentWallpaper|null): string|null {
+  if (!image) {
+    return null;
+  }
+  if (typeof image.key !== 'string' || !image.key) {
+    console.warn('Invalid image key received');
+    return null;
+  }
+  // Add a key query parameter to cache bust when the image changes.
+  return `/wallpaper.png?key=${encodeURIComponent(image.key)}`;
+}
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_actions.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_actions.ts
index 8d3192a..d3216693 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_actions.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_actions.ts
@@ -8,7 +8,6 @@
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {CurrentWallpaper, GooglePhotosAlbum, GooglePhotosEnablementState, GooglePhotosPhoto, WallpaperCollection, WallpaperImage} from '../personalization_app.mojom-webui.js';
-import {isPngDataUrl} from '../utils.js';
 
 import {DisplayableImage} from './constants.js';
 
@@ -449,9 +448,6 @@
  */
 export function setSelectedImageAction(image: CurrentWallpaper|
                                        null): SetSelectedImageAction {
-  assert(
-      image === null || isPngDataUrl(image.url),
-      'only png data urls are supported');
   return {
     image,
     name: WallpaperActionName.SET_SELECTED_IMAGE,
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.html b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.html
index 893ce431..45b0696 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.html
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.html
@@ -84,16 +84,16 @@
       <div id="imageContainer" class="photo-images-container clickable"
           on-click="onClickWallpaper_" on-keypress="onClickWallpaper_">
         <div class="photo-images-border"></div>
-        <img src$="[[image_.url.url]]"
-            alt$="[[getImageAltDescription_(image_)]]">
+        <img alt$="[[getImageAltDescription_(image_)]]"
+            src$="[[getWallpaperSrc_(image_)]]">
       </div>
     </template>
     <template is="dom-if" if="[[isPolicyControlled_(image_)]]">
       <div id="imageContainer" class="photo-images-container">
         <div class="photo-images-border"></div>
-        <img src$="[[image_.url.url]]"
+        <img alt$="[[getImageAltDescription_(image_)]]"
             aria-description="$i18n{managedSetting}"
-            alt$="[[getImageAltDescription_(image_)]]">
+            src$="[[getWallpaperSrc_(image_)]]">
       </div>
     </template>
   </template>
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.ts
index 5fa4c3e..f77a5f3 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_preview_element.ts
@@ -21,7 +21,7 @@
 import {WithPersonalizationStore} from '../personalization_store.js';
 import {isNonEmptyArray} from '../utils.js';
 
-import {getLocalStorageAttribution} from './utils.js';
+import {getLocalStorageAttribution, getWallpaperSrc} from './utils.js';
 import {WallpaperObserver} from './wallpaper_observer.js';
 import {getTemplate} from './wallpaper_preview_element.html.js';
 
@@ -67,6 +67,10 @@
     PersonalizationRouter.instance().goToRoute(Paths.COLLECTIONS);
   }
 
+  private getWallpaperSrc_(image: CurrentWallpaper|null): string|null {
+    return getWallpaperSrc(image);
+  }
+
   private getImageAltDescription_(image: CurrentWallpaper|null): string {
     if (!image) {
       return `${this.i18n('currentlySet')} ${
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html
index c51805e..e5ac3eff 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.html
@@ -72,7 +72,9 @@
   <template is="dom-if" if="[[showImage_]]">
     <div id="imageContainer" class="preview-image-container">
       <div class="preview-image-border"></div>
-      <img class="preview-image" src$="[[image_.url.url]]" aria-hidden="true">
+      <img aria-hidden="true"
+          class="preview-image"
+          src$="[[getWallpaperSrc_(image_)]]">
     </div>
     <h2 id="textContainer" class="preview-text-container" aria-live="polite" aria-label$="[[getAriaLabel_(image_, dailyRefreshState_)]]">
       <span id="currentlySet" aria-hidden="true">$i18n{currentlySet}</span>
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
index b5c52a4..b05cc8e 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_selected_element.ts
@@ -21,7 +21,7 @@
 import {WithPersonalizationStore} from '../personalization_store.js';
 import {isNonEmptyArray} from '../utils.js';
 
-import {getLocalStorageAttribution, getWallpaperLayoutEnum} from './utils.js';
+import {getLocalStorageAttribution, getWallpaperLayoutEnum, getWallpaperSrc} from './utils.js';
 import {getDailyRefreshState, selectGooglePhotosAlbum, setCurrentWallpaperLayout, setDailyRefreshCollectionId, updateDailyRefreshWallpaper} from './wallpaper_controller.js';
 import {getWallpaperProvider} from './wallpaper_interface_provider.js';
 import {WallpaperObserver} from './wallpaper_observer.js';
@@ -252,6 +252,10 @@
             collectionId! || googlePhotosAlbumId!, dailyRefreshState);
   }
 
+  private getWallpaperSrc_(image: CurrentWallpaper|null): string|null {
+    return getWallpaperSrc(image);
+  }
+
   private getCenterAriaPressed_(image: CurrentWallpaper): string {
     return (!!image && image.layout === WallpaperLayout.kCenter).toString();
   }
diff --git a/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.cc b/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.cc
index 38cd583..f3b26e0c 100644
--- a/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.cc
+++ b/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.cc
@@ -12,6 +12,8 @@
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
 #include "ash/webui/personalization_app/proto/backdrop_wallpaper.pb.h"
 #include "base/check_op.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/unguessable_token.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -35,6 +37,11 @@
   wallpaper_receiver_.Bind(std::move(receiver));
 }
 
+void FakePersonalizationAppWallpaperProvider::GetWallpaperAsPngBytes(
+    content::WebUIDataSource::GotDataCallback callback) {
+  std::move(callback).Run(base::MakeRefCounted<base::RefCountedBytes>());
+}
+
 bool FakePersonalizationAppWallpaperProvider::IsEligibleForGooglePhotos() {
   return true;
 }
diff --git a/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.h b/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.h
index 911fad6..11d658783 100644
--- a/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.h
+++ b/ash/webui/personalization_app/test/fake_personalization_app_wallpaper_provider.h
@@ -12,6 +12,7 @@
 #include "ash/public/cpp/wallpaper/wallpaper_types.h"
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
 #include "base/unguessable_token.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -37,6 +38,10 @@
   void BindInterface(
       mojo::PendingReceiver<ash::personalization_app::mojom::WallpaperProvider>
           receiver) override;
+
+  void GetWallpaperAsPngBytes(
+      content::WebUIDataSource::GotDataCallback callback) override;
+
   bool IsEligibleForGooglePhotos() override;
 
   // ash::personalization_app::mojom::WallpaperProvider:
diff --git a/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc b/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
index fcc9808..e8ebe1e 100644
--- a/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
+++ b/ash/webui/personalization_app/test/personalization_app_mojom_banned_browsertest_fixture.cc
@@ -12,6 +12,7 @@
 #include "ash/webui/personalization_app/personalization_app_url_constants.h"
 #include "ash/webui/personalization_app/personalization_app_user_provider.h"
 #include "ash/webui/personalization_app/personalization_app_wallpaper_provider.h"
+#include "base/memory/scoped_refptr.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -118,6 +119,10 @@
                   ash::personalization_app::mojom::WallpaperProvider> receiver),
               (override));
   bool IsEligibleForGooglePhotos() override { return true; }
+  void GetWallpaperAsPngBytes(
+      content::WebUIDataSource::GotDataCallback callback) override {
+    std::move(callback).Run(base::MakeRefCounted<base::RefCountedBytes>());
+  }
   MOCK_METHOD(void, MakeTransparent, (), (override));
   MOCK_METHOD(void, MakeOpaque, (), (override));
   MOCK_METHOD(void,
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 71a26a0a..3b50636e 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -1991,7 +1991,7 @@
 void DesksController::ReportClosedWindowsCountPerSourceHistogram(
     DesksCreationRemovalSource source,
     int windows_closed) const {
-  std::string desk_removal_source_histogram;
+  const char* desk_removal_source_histogram = nullptr;
   switch (source) {
     case DesksCreationRemovalSource::kButton:
       desk_removal_source_histogram = kNumberOfWindowsClosedByButton;
@@ -2011,9 +2011,9 @@
     case DesksCreationRemovalSource::kDesksRestore:
     case DesksCreationRemovalSource::kEnsureDefaultDesk:
       break;
-      NOTREACHED();
   }
-  base::UmaHistogramCounts100(desk_removal_source_histogram, windows_closed);
+  if (desk_removal_source_histogram)
+    base::UmaHistogramCounts100(desk_removal_source_histogram, windows_closed);
 }
 
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a56c5fc8..d2df03e 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -4486,7 +4486,6 @@
       "test/android/javatests/src/org/chromium/base/test/util/Feature.java",
       "test/android/javatests/src/org/chromium/base/test/util/Features.java",
       "test/android/javatests/src/org/chromium/base/test/util/FeaturesBase.java",
-      "test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java",
       "test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java",
       "test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferencesContext.java",
       "test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java",
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java
deleted file mode 100644
index 73d88328..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.base.test.util;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @deprecated Use "@DisabledTest" instead which has identical behavior.
- *
- * This annotation is for flaky tests.
- * <p>
- * Tests with this annotation will not be run on any of the normal bots.
- * Please note that they might eventually run on a special bot.
- */
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-@Deprecated
-public @interface FlakyTest {
-    String message() default "";
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
index 95d9f46d..774ce60 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
@@ -110,8 +110,31 @@
     @LargeTest
     @Feature("RenderTest")
     @DisableFeatures({ChromeFeatureList.SYNC_ANDROID_PROMOS_WITH_TITLE})
+    @EnableFeatures({ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ERROR_MESSAGES})
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
-    public void testSyncErrorCardForAuthErrorWithTitleFeatureDisabled(boolean nightModeEnabled)
+    public void testSyncErrorCardForAuthErrorWithTitleFeatureDisabledUpmEnabled(
+            boolean nightModeEnabled) throws Exception {
+        mFakeSyncServiceImpl.setAuthError(GoogleServiceAuthError.State.INVALID_GAIA_CREDENTIALS);
+        mSigninTestRule.addTestAccountThenSigninAndEnableSync(mFakeSyncServiceImpl);
+        TestThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> Assert.assertEquals("AUTH_ERROR SyncError should be set",
+                                SyncSettingsUtils.SyncError.AUTH_ERROR,
+                                SyncSettingsUtils.getSyncError()));
+
+        mSettingsActivityTestRule.startSettingsActivity();
+        mRenderTestRule.render(
+                getPersonalizedSyncPromoView(), "sync_error_card_auth_error_with_upm");
+    }
+
+    @Test
+    @LargeTest
+    @Feature("RenderTest")
+    @DisableFeatures({ChromeFeatureList.SYNC_ANDROID_PROMOS_WITH_TITLE,
+            ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ERROR_MESSAGES})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void
+    testSyncErrorCardForAuthErrorWithTitleFeatureDisabledUpmDisabled(boolean nightModeEnabled)
             throws Exception {
         mFakeSyncServiceImpl.setAuthError(GoogleServiceAuthError.State.INVALID_GAIA_CREDENTIALS);
         mSigninTestRule.addTestAccountThenSigninAndEnableSync(mFakeSyncServiceImpl);
@@ -128,9 +151,11 @@
     @Test
     @LargeTest
     @Feature("RenderTest")
-    @EnableFeatures({ChromeFeatureList.SYNC_ANDROID_PROMOS_WITH_TITLE})
+    @EnableFeatures({ChromeFeatureList.SYNC_ANDROID_PROMOS_WITH_TITLE,
+            ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ERROR_MESSAGES})
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
-    public void testSyncErrorCardForAuthErrorWithTitleFeatureEnabled(boolean nightModeEnabled)
+    public void
+    testSyncErrorCardForAuthErrorWithTitleFeatureEnabledUpmEnabled(boolean nightModeEnabled)
             throws Exception {
         mFakeSyncServiceImpl.setAuthError(GoogleServiceAuthError.State.INVALID_GAIA_CREDENTIALS);
         mSigninTestRule.addTestAccountThenSigninAndEnableSync(mFakeSyncServiceImpl);
@@ -141,6 +166,27 @@
                                 SyncSettingsUtils.getSyncError()));
 
         mSettingsActivityTestRule.startSettingsActivity();
+        mRenderTestRule.render(getPersonalizedSyncPromoView(),
+                "sync_error_card_auth_error_with_new_title_and_upm");
+    }
+
+    @Test
+    @LargeTest
+    @Feature("RenderTest")
+    @EnableFeatures({ChromeFeatureList.SYNC_ANDROID_PROMOS_WITH_TITLE})
+    @DisableFeatures({ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ERROR_MESSAGES})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testSyncErrorCardForAuthErrorWithTitleFeatureEnabledUpmDisabled(
+            boolean nightModeEnabled) throws Exception {
+        mFakeSyncServiceImpl.setAuthError(GoogleServiceAuthError.State.INVALID_GAIA_CREDENTIALS);
+        mSigninTestRule.addTestAccountThenSigninAndEnableSync(mFakeSyncServiceImpl);
+        TestThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> Assert.assertEquals("AUTH_ERROR SyncError should be set",
+                                SyncSettingsUtils.SyncError.AUTH_ERROR,
+                                SyncSettingsUtils.getSyncError()));
+
+        mSettingsActivityTestRule.startSettingsActivity();
         mRenderTestRule.render(
                 getPersonalizedSyncPromoView(), "sync_error_card_auth_error_with_new_title");
     }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4761e2d..9326ff0 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -6925,6 +6925,13 @@
         "//chrome/services/printing/public/mojom",
         "//components/crash/core/common",
       ]
+      if (is_win) {
+        sources += [
+          "printing/printer_xml_parser_impl.cc",
+          "printing/printer_xml_parser_impl.h",
+        ]
+        deps += [ "//printing:printing_base" ]
+      }
     }
     if (is_win || enable_print_preview) {
       deps += [ "//chrome/services/printing/public/mojom" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 3d061b0..708b17e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3352,10 +3352,10 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
 const FeatureEntry::FeatureParam kUnthrottledNestedTimeout_NestingLevel = {
-    "nesting", "100"};
+    "nesting", "15"};
 
 const FeatureEntry::FeatureVariation kUnthrottledNestedTimeout_Variations[] = {
-    {"100", &kUnthrottledNestedTimeout_NestingLevel, 1, nullptr},
+    {"15", &kUnthrottledNestedTimeout_NestingLevel, 1, nullptr},
 };
 
 constexpr FeatureEntry::FeatureParam kLensStandaloneWithSidePanel[] = {
@@ -5016,6 +5016,9 @@
     {"web-feed-sort", flag_descriptions::kWebFeedSortName,
      flag_descriptions::kWebFeedSortDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(feed::kWebFeedSort)},
+    {"feed-header-stick-to-top", flag_descriptions::kFeedHeaderStickToTopName,
+     flag_descriptions::kFeedHeaderStickToTopDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(feed::kFeedHeaderStickToTop)},
     {"xsurface-metrics-reporting",
      flag_descriptions::kXsurfaceMetricsReportingName,
      flag_descriptions::kXsurfaceMetricsReportingDescription, kOsAndroid,
@@ -8514,6 +8517,11 @@
          kLensInstructionChipVariations,
          "LensInstructionChipImprovements")},
 
+    {"enable-lens-region-search-static-page",
+     flag_descriptions::kLensRegionSearchStaticPageName,
+     flag_descriptions::kLensRegionSearchStaticPageDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(lens::features::kLensRegionSearchStaticPage)},
+
     {"enable-region-search-on-pdf-viewer",
      flag_descriptions::kEnableRegionSearchOnPdfViewerName,
      flag_descriptions::kEnableRegionSearchOnPdfViewerDescription, kOsDesktop,
@@ -9202,7 +9210,7 @@
      flag_descriptions::kIsolatedSandboxedIframesName,
      flag_descriptions::kIsolatedSandboxedIframesDescription, kOsDesktop,
      FEATURE_WITH_PARAMS_VALUE_TYPE(
-         features::kIsolateSandboxedIframes,
+         blink::features::kIsolateSandboxedIframes,
          kIsolateSandboxedIframesGroupingVariations,
          "IsolateSandboxedIframes" /* trial name */)},
 #endif
diff --git a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
index 940fb42..72b6edc5 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api_chromeos.cc
@@ -267,9 +267,14 @@
           ::features::IsExperimentalAccessibilityDictationWithPumpkinEnabled();
       break;
     case accessibility_private::AccessibilityFeature::
+        ACCESSIBILITY_FEATURE_DICTATIONMORECOMMANDS:
+      enabled =
+          ::features::IsExperimentalAccessibilityDictationMoreCommandsEnabled();
+      break;
+    case accessibility_private::
         ACCESSIBILITY_FEATURE_SELECTTOSPEAKVOICESWITCHING:
-      enabled = ::features::
-          IsExperimentalAccessibilitySelectToSpeakVoiceSwitchingEnabled();
+      enabled = 
+        ::features::IsExperimentalAccessibilitySelectToSpeakVoiceSwitchingEnabled();
       break;
     case accessibility_private::AccessibilityFeature::
         ACCESSIBILITY_FEATURE_NONE:
diff --git a/chrome/browser/android/chrome_backup_agent.cc b/chrome/browser/android/chrome_backup_agent.cc
index a77391d..8c845a2b 100644
--- a/chrome/browser/android/chrome_backup_agent.cc
+++ b/chrome/browser/android/chrome_backup_agent.cc
@@ -20,7 +20,7 @@
 
 // TODO(crbug.com/1305213): The data type toggles shouldn't be individually
 // listed here.
-static_assert(42 == syncer::GetNumModelTypes(),
+static_assert(43 == syncer::GetNumModelTypes(),
               "If the new type has a corresponding pref, add it here");
 const char* backed_up_preferences_[] = {
     autofill::prefs::kAutofillWalletImportEnabled,
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc
index 70310bf..cee6d93 100644
--- a/chrome/browser/ash/accessibility/dictation_browsertest.cc
+++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -954,6 +954,12 @@
   DictationCommandsTest(const DictationCommandsTest&) = delete;
   DictationCommandsTest& operator=(const DictationCommandsTest&) = delete;
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    DictationTest::SetUpCommandLine(command_line);
+    scoped_feature_list_.InitAndEnableFeature(
+        ::features::kExperimentalAccessibilityDictationMoreCommands);
+  }
+
   void SetUpOnMainThread() override {
     DictationTest::SetUpOnMainThread();
     ToggleDictationWithKeystroke();
@@ -972,6 +978,9 @@
         ui::ClipboardBuffer::kCopyPaste, /*data_dst=*/nullptr, &text);
     return base::UTF16ToUTF8(text);
   }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1153,6 +1162,22 @@
                                          "This is a t.");
 }
 
+IN_PROC_BROWSER_TEST_P(DictationCommandsTest, DeleteAllTextSimple) {
+  SendFinalResultAndWaitForTextAreaValue("Hello, world.", "Hello, world.");
+  SendFinalResultAndWaitForTextAreaValue("delete all", "");
+}
+
+IN_PROC_BROWSER_TEST_P(DictationCommandsTest, DeleteAllTextMultiLineString) {
+  std::string text = " Hello, world. \n Hello, world. \n Hello, world. \n";
+  SendFinalResultAndWaitForTextAreaValue(text, text);
+  SendFinalResultAndWaitForTextAreaValue("delete all", "");
+}
+
+// TODO(crbug.com/1362842) Add a test where
+// you disable the MoreCommands Feature Flag
+// and ensure that you can't run the Dictation
+// Commands under that feature flag
+
 IN_PROC_BROWSER_TEST_P(DictationCommandsTest, DeletePrevSentSimple) {
   SendFinalResultAndWaitForTextAreaValue("Hello, world.", "Hello, world.");
   SendFinalResultAndWaitForTextAreaValue("delete the previous sentence", "");
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
index 2616970..7e67100 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler.cc
@@ -8,8 +8,6 @@
 #include <utility>
 
 #include "ash/constants/ash_switches.h"
-#include "ash/metrics/login_unlock_throughput_recorder.h"
-#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram_functions.h"
@@ -451,10 +449,6 @@
     return;
   }
 
-  LoginUnlockThroughputRecorder* throughput_recorder =
-      Shell::HasInstance() ? Shell::Get()->login_unlock_throughput_recorder()
-                           : nullptr;
-
   int arc_app_count = 0;
   int other_app_count = 0;
   for (const auto& it : restore_data()->app_id_to_launch_list()) {
@@ -466,12 +460,6 @@
       continue;
     }
 
-    if (throughput_recorder) {
-      for (const auto& window : it.second) {
-        throughput_recorder->AddScheduledRestoreWindow(
-            window.first, it.first, LoginUnlockThroughputRecorder::kBrowser);
-      }
-    }
     ++other_app_count;
   }
   VLOG(1) << "There is restore data: Browser("
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_util.h b/chrome/browser/ash/crosapi/browser_data_migrator_util.h
index fed99c7..ef6b1c8 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_util.h
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_util.h
@@ -302,7 +302,7 @@
 };
 
 // List of data types in Sync Data that have to stay in Ash and Ash only.
-static_assert(42 == syncer::GetNumModelTypes(),
+static_assert(43 == syncer::GetNumModelTypes(),
               "If adding a new sync data type, update the lists below if"
               " you want to keep the new data type in Ash only.");
 constexpr syncer::ModelType kAshOnlySyncDataTypes[] = {
diff --git a/chrome/browser/ash/net/network_diagnostics/network_diagnostics_util_unittest.cc b/chrome/browser/ash/net/network_diagnostics/network_diagnostics_util_unittest.cc
index d2691e0..137d318 100644
--- a/chrome/browser/ash/net/network_diagnostics/network_diagnostics_util_unittest.cc
+++ b/chrome/browser/ash/net/network_diagnostics/network_diagnostics_util_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -37,8 +38,7 @@
       util::GetRandomHosts(num_hosts, prefix_length);
   // Ensure |random_hosts| has unique entries.
   std::sort(random_hosts.begin(), random_hosts.end());
-  EXPECT_TRUE(std::adjacent_find(random_hosts.begin(), random_hosts.end()) ==
-              random_hosts.end());
+  EXPECT_TRUE(base::ranges::adjacent_find(random_hosts) == random_hosts.end());
 }
 
 TEST(NetworkDiagnosticsUtilTest, TestGetRandomHostsWithScheme) {
@@ -48,8 +48,7 @@
       util::GetRandomHostsWithScheme(num_hosts, prefix_length, kHttpsScheme);
   // Ensure |random_hosts| has unique entries.
   std::sort(random_hosts.begin(), random_hosts.end());
-  EXPECT_TRUE(std::adjacent_find(random_hosts.begin(), random_hosts.end()) ==
-              random_hosts.end());
+  EXPECT_TRUE(base::ranges::adjacent_find(random_hosts) == random_hosts.end());
   // Ensure hosts in |random_hosts| start with |kHttpsScheme|.
   for (const auto& host : random_hosts) {
     EXPECT_TRUE(host.rfind(kHttpsScheme, 0) == 0);
@@ -65,8 +64,7 @@
                                                        kHttpsScheme);
   // Ensure |random_hosts| has unique entries.
   std::sort(random_hosts.begin(), random_hosts.end());
-  EXPECT_TRUE(std::adjacent_find(random_hosts.begin(), random_hosts.end()) ==
-              random_hosts.end());
+  EXPECT_TRUE(base::ranges::adjacent_find(random_hosts) == random_hosts.end());
   // Ensure:
   // (1) hosts in |random_hosts| start with |kHttpsScheme|.
   // (2) hosts in |random_hosts| end with |kGenerate204Path|.
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
index 80b0b1b..0080e20 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.cc
@@ -26,9 +26,12 @@
 #include "ash/webui/personalization_app/proto/backdrop_wallpaper.pb.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted_memory.h"
 #include "base/notreached.h"
 #include "base/rand_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "base/unguessable_token.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/wallpaper/wallpaper_enumerator.h"
@@ -47,6 +50,7 @@
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -59,6 +63,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "url/gurl.h"
@@ -72,7 +77,7 @@
 using ash::personalization_app::GetUser;
 
 constexpr int kLocalImageThumbnailSizeDip = 256;
-constexpr int kCurrentWallpaperThumbnailSizeDip = 512;
+constexpr int kCurrentWallpaperThumbnailSizeDip = 1024;
 
 const gfx::ImageSkia GetResizedImage(const gfx::ImageSkia& image) {
   // Resize the image maintaining our aspect ratio.
@@ -96,6 +101,19 @@
              : base::UnguessableToken::Create().ToString();
 }
 
+scoped_refptr<base::RefCountedMemory> ResizeAndEncodeWallpaperImage() {
+  auto* wallpaper_controller = ash::WallpaperController::Get();
+  // Get wallpaper image on worker thread for performance reasons. This avoids
+  // having to call |image.MakeThreadSafe| in a performance critical path while
+  // changing wallpaper, and instead calling it in the thread pool.
+  auto image = wallpaper_controller->GetWallpaperImage();
+  image.MakeThreadSafe();
+  auto resized = GetResizedImage(image);
+  scoped_refptr<base::RefCountedMemory> png_bytes =
+      gfx::Image(resized).As1xPNGBytes();
+  return png_bytes;
+}
+
 }  // namespace
 
 PersonalizationAppWallpaperProviderImpl::
@@ -125,6 +143,19 @@
   wallpaper_receiver_.Bind(std::move(receiver));
 }
 
+void PersonalizationAppWallpaperProviderImpl::GetWallpaperAsPngBytes(
+    content::WebUIDataSource::GotDataCallback callback) {
+  // |GetWallpaperAsPngBytes| is called in the hot path of switching wallpaper
+  // on the UI thread right after user makes a new selection. Make sure to do
+  // resizing and encoding on a task runner to avoid locking up the UI as the
+  // user's wallpaper is being set.
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&ResizeAndEncodeWallpaperImage), std::move(callback));
+}
+
 bool PersonalizationAppWallpaperProviderImpl::IsEligibleForGooglePhotos() {
   return GetUser(profile_)->HasGaiaAccount();
 }
@@ -353,7 +384,6 @@
   wallpaper_attribution_info_fetcher_.reset();
   attribution_weak_ptr_factory_.InvalidateWeakPtrs();
 
-  auto* controller = WallpaperController::Get();
   auto* client = WallpaperControllerClientImpl::Get();
 
   absl::optional<ash::WallpaperInfo> info =
@@ -365,12 +395,6 @@
     return;
   }
 
-  const gfx::ImageSkia& current_wallpaper = controller->GetWallpaperImage();
-  const gfx::ImageSkia& current_wallpaper_resized =
-      GetResizedImage(current_wallpaper);
-  const GURL& wallpaper_data_url =
-      GURL(webui::GetBitmapDataUrl(*current_wallpaper_resized.bitmap()));
-
   switch (info->type) {
     case ash::WallpaperType::kDaily:
     case ash::WallpaperType::kOnline: {
@@ -380,15 +404,13 @@
         // look up all collections and match URL.
         FetchCollections(base::BindOnce(
             &PersonalizationAppWallpaperProviderImpl::FindAttribution,
-            attribution_weak_ptr_factory_.GetWeakPtr(), *info,
-            wallpaper_data_url));
+            attribution_weak_ptr_factory_.GetWeakPtr(), *info));
         return;
       }
 
       backdrop::Collection collection;
       collection.set_collection_id(info->collection_id);
-      FindAttribution(*info, wallpaper_data_url,
-                      std::vector<backdrop::Collection>{collection});
+      FindAttribution(*info, std::vector<backdrop::Collection>{collection});
       return;
     }
     case ash::WallpaperType::kCustomized: {
@@ -405,8 +427,7 @@
 
       NotifyWallpaperChanged(
           ash::personalization_app::mojom::CurrentWallpaper::New(
-              wallpaper_data_url, std::move(attribution), info->layout,
-              info->type, key));
+              std::move(attribution), info->layout, info->type, key));
 
       return;
     }
@@ -416,8 +437,7 @@
           GetAccountId(profile_), info->location,
           base::BindOnce(&PersonalizationAppWallpaperProviderImpl::
                              SendGooglePhotosAttribution,
-                         weak_ptr_factory_.GetWeakPtr(), *info,
-                         wallpaper_data_url));
+                         weak_ptr_factory_.GetWeakPtr(), *info));
       return;
     case ash::WallpaperType::kDefault:
     case ash::WallpaperType::kDevice:
@@ -426,8 +446,8 @@
     case ash::WallpaperType::kThirdParty:
       NotifyWallpaperChanged(
           ash::personalization_app::mojom::CurrentWallpaper::New(
-              wallpaper_data_url, /*attribution=*/std::vector<std::string>(),
-              info->layout, info->type,
+              /*attribution=*/std::vector<std::string>(), info->layout,
+              info->type,
               /*key=*/base::UnguessableToken::Create().ToString()));
       return;
     case ash::WallpaperType::kCount:
@@ -789,14 +809,13 @@
 
 void PersonalizationAppWallpaperProviderImpl::FindAttribution(
     const ash::WallpaperInfo& info,
-    const GURL& wallpaper_data_url,
     const absl::optional<std::vector<backdrop::Collection>>& collections) {
   DCHECK(!wallpaper_attribution_info_fetcher_);
   if (!collections.has_value() || collections->empty()) {
     NotifyWallpaperChanged(
         ash::personalization_app::mojom::CurrentWallpaper::New(
-            wallpaper_data_url, /*attribution=*/std::vector<std::string>(),
-            info.layout, info.type, GetOnlineWallpaperKey(info)));
+            /*attribution=*/std::vector<std::string>(), info.layout, info.type,
+            GetOnlineWallpaperKey(info)));
 
     return;
   }
@@ -808,13 +827,12 @@
 
   wallpaper_attribution_info_fetcher_->Start(base::BindOnce(
       &PersonalizationAppWallpaperProviderImpl::FindAttributionInCollection,
-      attribution_weak_ptr_factory_.GetWeakPtr(), info, wallpaper_data_url,
-      current_index, collections));
+      attribution_weak_ptr_factory_.GetWeakPtr(), info, current_index,
+      collections));
 }
 
 void PersonalizationAppWallpaperProviderImpl::FindAttributionInCollection(
     const ash::WallpaperInfo& info,
-    const GURL& wallpaper_data_url,
     std::size_t current_index,
     const absl::optional<std::vector<backdrop::Collection>>& collections,
     bool success,
@@ -843,7 +861,7 @@
       attributions.push_back(attr.text());
     NotifyWallpaperChanged(
         ash::personalization_app::mojom::CurrentWallpaper::New(
-            wallpaper_data_url, attributions, info.layout, info.type,
+            attributions, info.layout, info.type,
             /*key=*/base::NumberToString(backend_image->asset_id())));
     wallpaper_attribution_info_fetcher_.reset();
     return;
@@ -854,8 +872,8 @@
   if (current_index >= collections->size()) {
     NotifyWallpaperChanged(
         ash::personalization_app::mojom::CurrentWallpaper::New(
-            wallpaper_data_url, /*attribution=*/std::vector<std::string>(),
-            info.layout, info.type, GetOnlineWallpaperKey(info)));
+            /*attribution=*/std::vector<std::string>(), info.layout, info.type,
+            GetOnlineWallpaperKey(info)));
     wallpaper_attribution_info_fetcher_.reset();
     return;
   }
@@ -864,8 +882,8 @@
       collections->at(current_index).collection_id());
   fetcher->Start(base::BindOnce(
       &PersonalizationAppWallpaperProviderImpl::FindAttributionInCollection,
-      attribution_weak_ptr_factory_.GetWeakPtr(), info, wallpaper_data_url,
-      current_index, collections));
+      attribution_weak_ptr_factory_.GetWeakPtr(), info, current_index,
+      collections));
   // resetting the previous fetcher last because the current method is bound
   // to a callback owned by the previous fetcher.
   wallpaper_attribution_info_fetcher_ = std::move(fetcher);
@@ -873,7 +891,6 @@
 
 void PersonalizationAppWallpaperProviderImpl::SendGooglePhotosAttribution(
     const ash::WallpaperInfo& info,
-    const GURL& wallpaper_data_url,
     mojo::StructPtr<ash::personalization_app::mojom::GooglePhotosPhoto> photo,
     bool success) {
   // If the fetch for |photo| succeeded but |photo| does not exist, that means
@@ -900,7 +917,7 @@
   // NOTE: Old clients may not support |dedup_key| when setting Google Photos
   // wallpaper, so use |location| in such cases for backwards compatibility.
   NotifyWallpaperChanged(ash::personalization_app::mojom::CurrentWallpaper::New(
-      wallpaper_data_url, attribution, info.layout, info.type,
+      attribution, info.layout, info.type,
       /*key=*/info.dedup_key.value_or(info.location)));
 }
 
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.h
index e1324f63..689d6566 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.h
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl.h
@@ -23,6 +23,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "components/account_id/account_id.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -77,6 +78,9 @@
       mojo::PendingReceiver<ash::personalization_app::mojom::WallpaperProvider>
           receiver) override;
 
+  void GetWallpaperAsPngBytes(
+      content::WebUIDataSource::GotDataCallback callback) override;
+
   // Not all users can see google photos. Requires a gaia account to be able to
   // fetch photos.
   bool IsEligibleForGooglePhotos() override;
@@ -232,12 +236,10 @@
 
   void FindAttribution(
       const ash::WallpaperInfo& info,
-      const GURL& wallpaper_data_url,
       const absl::optional<std::vector<backdrop::Collection>>& collections);
 
   void FindAttributionInCollection(
       const ash::WallpaperInfo& info,
-      const GURL& wallpaper_data_url,
       std::size_t current_index,
       const absl::optional<std::vector<backdrop::Collection>>& collections,
       bool success,
@@ -246,7 +248,6 @@
 
   void SendGooglePhotosAttribution(
       const ash::WallpaperInfo& info,
-      const GURL& wallpaper_data_url,
       mojo::StructPtr<ash::personalization_app::mojom::GooglePhotosPhoto> photo,
       bool success);
 
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
index cdf4efd..8e544e7 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
@@ -19,6 +19,9 @@
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h"
 #include "base/callback_helpers.h"
 #include "base/json/json_reader.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/values.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
@@ -55,6 +58,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/webui/web_ui_util.h"
+#include "ui/gfx/codec/png_codec.h"
 
 namespace ash::personalization_app {
 
@@ -413,7 +417,6 @@
 
 TEST_P(PersonalizationAppWallpaperProviderImplTest,
        ObserveWallpaperFiresWhenBound) {
-  // This will create the data url referenced below in expectation.
   test_wallpaper_controller()->ShowWallpaperImage(
       CreateSolidImageSkia(/*width=*/1, /*height=*/1, SK_ColorBLACK));
 
@@ -443,10 +446,6 @@
   EXPECT_EQ(ash::WallpaperType::kOnline, current->type);
   EXPECT_EQ(ash::WallpaperLayout::WALLPAPER_LAYOUT_CENTER_CROPPED,
             current->layout);
-  // Data url of a solid black image scaled up to 512x512.
-  EXPECT_EQ(webui::GetBitmapDataUrl(
-                *CreateSolidImageSkia(512, 512, SK_ColorBLACK).bitmap()),
-            current->url);
 }
 
 TEST_P(PersonalizationAppWallpaperProviderImplTest, SetCurrentWallpaperLayout) {
@@ -485,6 +484,33 @@
   ResetWallpaperProvider();
 }
 
+TEST_P(PersonalizationAppWallpaperProviderImplTest, GetWallpaperAsPngBytes) {
+  test_wallpaper_controller()->ShowWallpaperImage(
+      CreateSolidImageSkia(/*width=*/1, /*height=*/1, SK_ColorRED));
+
+  scoped_refptr<base::RefCountedMemory> png_bytes;
+
+  base::RunLoop loop;
+  delegate()->GetWallpaperAsPngBytes(base::BindLambdaForTesting(
+      [quit = loop.QuitClosure(),
+       &png_bytes](scoped_refptr<base::RefCountedMemory> bytes) {
+        bytes.swap(png_bytes);
+        std::move(quit).Run();
+      }));
+  loop.Run();
+
+  // Png bytes of a solid black image scaled up to 1024x1024.
+  scoped_refptr<base::RefCountedBytes> expected_png_bytes =
+      base::MakeRefCounted<base::RefCountedBytes>();
+  gfx::PNGCodec::EncodeBGRASkBitmap(
+      CreateSolidImageSkia(1024, 1024, SK_ColorRED)
+          .GetRepresentation(/*scale=*/1)
+          .GetBitmap(),
+      /*discard_transparency=*/false, &expected_png_bytes->data());
+
+  EXPECT_TRUE(expected_png_bytes->Equals(png_bytes));
+}
+
 class PersonalizationAppWallpaperProviderImplGooglePhotosTest
     : public PersonalizationAppWallpaperProviderImplTest {
  protected:
diff --git a/chrome/browser/creator/android/BUILD.gn b/chrome/browser/creator/android/BUILD.gn
index c8afce0..cc84bdb0 100644
--- a/chrome/browser/creator/android/BUILD.gn
+++ b/chrome/browser/creator/android/BUILD.gn
@@ -12,10 +12,16 @@
   deps = [
     ":creator_java_resources",
     "//base:base_java",
+    "//chrome/browser/feed/android:feed_java_resources",
+    "//chrome/browser/feed/android:java",
+    "//chrome/browser/xsurface:java",
+    "//components/browser_ui/styles/android:java",
+    "//components/browser_ui/widget/android:java",
     "//content/public/android:content_main_dex_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
     "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//ui/android:ui_no_recycler_view_java",
     "//url:gurl_java",
   ]
@@ -27,6 +33,8 @@
   sources = [
     "java/res/drawable/profile_background.xml",
     "java/res/layout/creator_activity.xml",
+    "java/res/values/dimens.xml",
+    "java/res/values/ids.xml",
     "java/res/values/styles.xml",
   ]
   deps = [
diff --git a/chrome/browser/creator/android/java/res/values/dimens.xml b/chrome/browser/creator/android/java/res/values/dimens.xml
new file mode 100644
index 0000000..c94fbaf
--- /dev/null
+++ b/chrome/browser/creator/android/java/res/values/dimens.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Content Previews dimensions. -->
+    <dimen name="content_previews_padding">16dp</dimen>
+</resources>
diff --git a/chrome/browser/creator/android/java/res/values/ids.xml b/chrome/browser/creator/android/java/res/values/ids.xml
new file mode 100644
index 0000000..d776e90
--- /dev/null
+++ b/chrome/browser/creator/android/java/res/values/ids.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Copyright 2022 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources>
+  <!-- Id to use for Content Previews RecyclerView. -->
+  <item type="id" name="creator_feed_stream_recycler_view" />
+</resources>
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
index 291441da..f9f158f 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorCoordinator.java
@@ -6,27 +6,95 @@
 
 import android.app.Activity;
 import android.view.LayoutInflater;
-import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.chromium.chrome.browser.feed.FeedSurfaceScopeDependencyProvider;
+import org.chromium.chrome.browser.feed.FeedSurfaceTracker;
+import org.chromium.chrome.browser.feed.NativeViewListRenderer;
+import org.chromium.chrome.browser.feed.NtpListContentManager;
+import org.chromium.chrome.browser.xsurface.HybridListRenderer;
+import org.chromium.chrome.browser.xsurface.ProcessScope;
+import org.chromium.chrome.browser.xsurface.SurfaceScope;
+import org.chromium.components.browser_ui.styles.SemanticColorUtils;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Sets up the Coordinator for Cormorant Creator surface.  It is based on the doc at
  * https://chromium.googlesource.com/chromium/src/+/HEAD/docs/ui/android/mvc_simple_list_tutorial.md
  */
 public class CreatorCoordinator {
+    private static final String NATIVE_CONTENT_ID = "0";
+
     private CreatorMediator mMediator;
     private Activity mActivity;
-    private final View mView;
+    private NtpListContentManager mContentManager;
+    private RecyclerView mRecyclerView;
+    private HybridListRenderer mHybridListRenderer;
+    private SurfaceScope mSurfaceScope;
+    private FeedSurfaceScopeDependencyProvider mDependencyProvider;
+
+    private final ViewGroup mViewGroup;
 
     public CreatorCoordinator(Activity activity) {
         mActivity = activity;
+        mRecyclerView = setUpView();
+        List<NtpListContentManager.FeedContent> contentPreviewsList = new ArrayList<>();
+
+        // Add empty state to Content Manager
+        contentPreviewsList.add(new NtpListContentManager.NativeViewContent(
+                getLateralPaddingsPx(), NATIVE_CONTENT_ID, R.layout.no_content_v2));
+        mContentManager.addContents(0, contentPreviewsList);
 
         // Inflate the XML.
-        mView = LayoutInflater.from(mActivity).inflate(R.layout.creator_activity, null);
+        mViewGroup =
+                (ViewGroup) LayoutInflater.from(mActivity).inflate(R.layout.creator_activity, null);
+        mViewGroup.addView(mRecyclerView);
 
         mMediator = new CreatorMediator(mActivity);
     }
 
-    public View getView() {
-        return mView;
+    public ViewGroup getView() {
+        return mViewGroup;
+    }
+
+    private RecyclerView setUpView() {
+        // TODO(crbug.com/1374744): Refactor NTP naming out of the general Feed code.
+        mContentManager = new NtpListContentManager();
+        ProcessScope processScope = FeedSurfaceTracker.getInstance().getXSurfaceProcessScope();
+
+        if (processScope != null) {
+            mDependencyProvider =
+                    new FeedSurfaceScopeDependencyProvider(mActivity, mActivity, false);
+            mSurfaceScope = processScope.obtainSurfaceScope(mDependencyProvider);
+        } else {
+            mDependencyProvider = null;
+            mSurfaceScope = null;
+        }
+
+        if (mSurfaceScope != null) {
+            mHybridListRenderer = mSurfaceScope.provideListRenderer();
+        } else {
+            mHybridListRenderer = new NativeViewListRenderer(mActivity);
+        }
+
+        RecyclerView view;
+        if (mHybridListRenderer != null) {
+            view = (RecyclerView) mHybridListRenderer.bind(
+                    mContentManager, /* mViewportView */ null, /* useStaggeredLayout */ false);
+            view.setId(R.id.creator_feed_stream_recycler_view);
+            view.setClipToPadding(false);
+            view.setBackgroundColor(SemanticColorUtils.getDefaultBgColor(mActivity));
+        } else {
+            view = null;
+        }
+        return view;
+    }
+
+    private int getLateralPaddingsPx() {
+        return mActivity.getResources().getDimensionPixelSize(R.dimen.content_previews_padding);
     }
 }
diff --git a/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.cc b/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.cc
index b5c8450..e85586e1 100644
--- a/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.cc
+++ b/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.cc
@@ -46,10 +46,3 @@
       address, port);
   return extensions::SocketsManifestData::CheckRequest(extension, param);
 }
-
-bool ChromeDirectSocketsDelegate::ShouldSkipPostResolveChecks(
-    content::RenderFrameHost* frame) const {
-  // chrome.sockets.* doesn't have any restrictions on resolved addresses, so we
-  // may skip these checks.
-  return IsExtensionFrame(frame);
-}
diff --git a/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.h b/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.h
index 3fb4421f..174b2d8 100644
--- a/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.h
+++ b/chrome/browser/direct_sockets/chrome_direct_sockets_delegate.h
@@ -15,7 +15,6 @@
       const std::string& address,
       uint16_t port,
       blink::mojom::DirectSocketProtocolType protocol) const override;
-  bool ShouldSkipPostResolveChecks(content::RenderFrameHost*) const override;
 };
 
 #endif  // CHROME_BROWSER_DIRECT_SOCKETS_CHROME_DIRECT_SOCKETS_DELEGATE_H_
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
index 564887d..c1f38013 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedSurfaceScopeDependencyProvider.java
@@ -20,7 +20,8 @@
 /**
  * Provides activity, darkmode and logging context for a single surface.
  */
-class FeedSurfaceScopeDependencyProvider implements SurfaceScopeDependencyProvider, ScrollListener {
+public class FeedSurfaceScopeDependencyProvider
+        implements SurfaceScopeDependencyProvider, ScrollListener {
     private static final String TAG = "Feed";
     private final Activity mActivity;
     private final Context mActivityContext;
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
index d2404db..bce556a 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
@@ -51,29 +51,17 @@
     : browser_context_(browser_context) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(browser_context);
-  Init([](PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-    content::FirstPartySetsHandler::GetInstance()->GetContextConfigForPolicy(
-        GetOverridesPolicyForProfile(prefs), std::move(callback));
-  });
+  Init();
 }
 
 FirstPartySetsPolicyService::~FirstPartySetsPolicyService() = default;
 
-void FirstPartySetsPolicyService::InitForTesting(
-    base::FunctionRef<
-        void(PrefService*,
-             base::OnceCallback<void(net::FirstPartySetsContextConfig)>)>
-        get_config) {
+void FirstPartySetsPolicyService::InitForTesting() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  Init(get_config);
+  Init();
 }
 
-void FirstPartySetsPolicyService::Init(
-    base::FunctionRef<
-        void(PrefService*,
-             base::OnceCallback<void(net::FirstPartySetsContextConfig)>)>
-        get_config) {
+void FirstPartySetsPolicyService::Init() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!base::FeatureList::IsEnabled(features::kFirstPartySets)) {
     OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig(),
@@ -98,14 +86,15 @@
   // dynamically refresh, and all the delegates for `context` will have the same
   // policy and thus the same config.
   PrefService* prefs = profile->GetPrefs();
-  get_config(prefs, base::BindOnce(
-                        &FirstPartySetsPolicyService::OnProfileConfigReady,
-                        weak_factory_.GetWeakPtr(),
-                        // We should only clear site data if First-Party Sets is
-                        // enabled when the service is created, to allow users
-                        // to play with the FPS enabled setting without
-                        // affecting user experience during the browser session.
-                        GetEnabledPolicyForProfile(prefs)));
+  content::FirstPartySetsHandler::GetInstance()->GetContextConfigForPolicy(
+      GetOverridesPolicyForProfile(prefs),
+      base::BindOnce(&FirstPartySetsPolicyService::OnProfileConfigReady,
+                     weak_factory_.GetWeakPtr(),
+                     // We should only clear site data if First-Party Sets is
+                     // enabled when the service is created, to allow users
+                     // to play with the FPS enabled setting without
+                     // affecting user experience during the browser session.
+                     GetEnabledPolicyForProfile(prefs)));
 }
 
 void FirstPartySetsPolicyService::AddRemoteAccessDelegate(
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.h b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
index 2d995457..8ab0653 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.h
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
@@ -14,8 +14,6 @@
 #include "mojo/public/cpp/bindings/remote_set.h"
 #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
 
-class PrefService;
-
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -76,16 +74,11 @@
   // factory for FirstPartySetsPolicyService instances in tests, so every
   // instance calls into the prod logic to eagerly initialize itself. This
   // method allows tests to wait for that eager initialization to complete, then
-  // reset state, and re-run initialization via `InitForTesting`.
+  // reset state, and re-run initialization via `Init`.
   void WaitForFirstInitCompleteForTesting(base::OnceClosure callback);
 
-  // Testing-only method that allows injecting different logic to get the
-  // config.
-  void InitForTesting(
-      base::FunctionRef<
-          void(PrefService*,
-               base::OnceCallback<void(net::FirstPartySetsContextConfig)>)>
-          get_config);
+  // Exposes `Init` for use in tests.
+  void InitForTesting();
 
   // Returns true when this instance has received the config thus has been fully
   // initialized.
@@ -122,11 +115,8 @@
   }
 
  private:
-  // Initialize this instance by getting the config via `get_config` if needed.
-  void Init(base::FunctionRef<
-            void(PrefService*,
-                 base::OnceCallback<void(net::FirstPartySetsContextConfig)>)>
-                get_config);
+  // Initialize this instance by getting the config if needed.
+  void Init();
 
   // Sets the `config_` member and provides it to all delegates via NotifyReady.
   void OnReadyToNotifyDelegates(net::FirstPartySetsContextConfig config,
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
index 81278fe..02cd1fe 100644
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service_unittest.cc
@@ -19,6 +19,7 @@
 #include "net/base/schemeful_site.h"
 #include "net/first_party_sets/first_party_set_entry.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
+#include "net/first_party_sets/global_first_party_sets.h"
 #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -146,8 +147,11 @@
 
   void SetUp() override {
     DefaultFirstPartySetsPolicyServiceTest::SetUp();
-    content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
-    content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting({});
+    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
+        &first_party_sets_handler_);
+    first_party_sets_handler_.SetGlobalSets({});
+    SetContextConfig(net::FirstPartySetsContextConfig());
+    SetCacheFilter(net::FirstPartySetsCacheFilter());
 
     profile_manager_ = std::make_unique<TestingProfileManager>(
         TestingBrowserProcess::GetGlobal());
@@ -175,15 +179,30 @@
     // tests if the factory has already created a service for the testing
     // profile being used.
     service_->ResetForTesting();
+    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
+        nullptr);
     profile_manager_->DeleteAllTestingProfiles();
     profile_manager_.reset();
   }
 
+  void SetContextConfig(net::FirstPartySetsContextConfig config) {
+    first_party_sets_handler_.SetContextConfig(std::move(config));
+  }
+
+  void SetCacheFilter(net::FirstPartySetsCacheFilter cache_filter) {
+    first_party_sets_handler_.SetCacheFilter(std::move(cache_filter));
+  }
+
+  void SetGlobalSets(net::GlobalFirstPartySets global_sets) {
+    first_party_sets_handler_.SetGlobalSets(std::move(global_sets));
+  }
+
  protected:
   Profile* profile() { return profile_; }
   FirstPartySetsPolicyService* service() { return service_; }
 
  private:
+  MockFirstPartySetsHandler first_party_sets_handler_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   Profile* profile_;
   base::test::ScopedFeatureList features_;
@@ -196,15 +215,12 @@
 }
 
 TEST_F(FirstPartySetsPolicyServiceTest, IsSiteInManagedSet_SiteNotInConfig) {
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig(
-            {{net::SchemefulSite(GURL("https://example.test")),
-              {net::FirstPartySetEntry(
-                  net::SchemefulSite(GURL("https://primary.test")),
-                  net::SiteType::kAssociated, absl::nullopt)}}}));
-      });
+  SetContextConfig(net::FirstPartySetsContextConfig(
+      {{net::SchemefulSite(GURL("https://example.test")),
+        {net::FirstPartySetEntry(
+            net::SchemefulSite(GURL("https://primary.test")),
+            net::SiteType::kAssociated, absl::nullopt)}}}));
+  service()->InitForTesting();
 
   EXPECT_FALSE(service()->IsSiteInManagedSet(
       net::SchemefulSite(GURL("https://not-example.test"))));
@@ -215,13 +231,9 @@
        IsSiteInManagedSet_SiteInConfig_AsDeletion) {
   net::SchemefulSite example_site =
       net::SchemefulSite(GURL("https://example.test"));
-  service()->InitForTesting(
-      [example_site](
-          PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig(
-            {{example_site, {absl::nullopt}}}));
-      });
+  SetContextConfig(
+      net::FirstPartySetsContextConfig({{example_site, {absl::nullopt}}}));
+  service()->InitForTesting();
   EXPECT_FALSE(service()->IsSiteInManagedSet(example_site));
   env().RunUntilIdle();
 }
@@ -230,16 +242,12 @@
        IsSiteInManagedSet_SiteInConfig_AsModification) {
   net::SchemefulSite example_site =
       net::SchemefulSite(GURL("https://example.test"));
-  service()->InitForTesting(
-      [example_site](
-          PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig(
-            {{example_site,
-              {net::FirstPartySetEntry(
-                  net::SchemefulSite(GURL("https://primary.test")),
-                  net::SiteType::kAssociated, absl::nullopt)}}}));
-      });
+  SetContextConfig(net::FirstPartySetsContextConfig(
+      {{example_site,
+        {net::FirstPartySetEntry(
+            net::SchemefulSite(GURL("https://primary.test")),
+            net::SiteType::kAssociated, absl::nullopt)}}}));
+  service()->InitForTesting();
   EXPECT_TRUE(service()->IsSiteInManagedSet(example_site));
   env().RunUntilIdle();
 }
@@ -253,18 +261,13 @@
   // Create Global First-Party Sets with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate1.test"}
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      net::GlobalFirstPartySets(
-          {{associate1_site,
-            {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
-                                     0)}}},
-          {}));
+  SetGlobalSets(net::GlobalFirstPartySets(
+      {{associate1_site,
+        {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
+                                 0)}}},
+      {}));
   // Simulate the profile set overrides are empty.
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   // Simulate First-Party Sets disabled by the feature.
   features.InitAndDisableFeature(features::kFirstPartySets);
@@ -286,18 +289,13 @@
   // Create Global First-Party Sets with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate1.test"}
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      net::GlobalFirstPartySets(
-          {{associate1_site,
-            {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
-                                     0)}}},
-          {}));
+  SetGlobalSets(net::GlobalFirstPartySets(
+      {{associate1_site,
+        {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
+                                 0)}}},
+      {}));
   // Simulate the profile set overrides are empty.
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   // Simulate First-Party Sets disabled by the preference.
   features.InitAndEnableFeature(features::kFirstPartySets);
@@ -330,7 +328,7 @@
   // Simulate the global First-Party Sets with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate1.test"}
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
+  SetGlobalSets(
       net::GlobalFirstPartySets({{associate1_site, {associate1_entry}}}, {}));
 
   // Verify that FindEntry returns empty if both sources of sets aren't ready
@@ -338,11 +336,7 @@
   EXPECT_FALSE(service()->FindEntry(associate1_site));
 
   // Simulate the profile set overrides are empty.
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   // Verify that FindEntry finally returns associate1's entry.
   EXPECT_EQ(service()->FindEntry(associate1_site).value(), associate1_entry);
@@ -372,15 +366,11 @@
   // Simulate the global First-Party Sets with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate.test"}
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
+  SetGlobalSets(
       net::GlobalFirstPartySets({{associate_site, {associate_entry}}}, {}));
 
   // Simulate the profile set overrides are empty.
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   // The queries that occur before global sets are ready should be
   // counted in our metric.
@@ -416,15 +406,11 @@
   // Simulate the global First-Party Sets with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate.test"}
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
+  SetGlobalSets(
       net::GlobalFirstPartySets({{associate_site, {associate_entry}}}, {}));
 
   // Simulate the profile set overrides are empty.
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   // Simulate 3 FindEntry queries which all are answered successfully.
   EXPECT_EQ(service()->FindEntry(associate_site).value(), associate_entry);
@@ -456,12 +442,9 @@
   net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary,
                                      absl::nullopt);
   net::FirstPartySetsContextConfig test_config({{test_primary, {test_entry}}});
+  SetContextConfig(test_config.Clone());
 
-  service()->InitForTesting(
-      [&](PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(test_config.Clone());
-      });
+  service()->InitForTesting();
 
   EXPECT_CALL(mock_delegate, NotifyReady(CarryingConfig(std::ref(test_config))))
       .Times(1);
@@ -471,11 +454,7 @@
 
 TEST_F(FirstPartySetsPolicyServicePrefObserverTest,
        OnFirstPartySetsEnabledChanged_Default_WithConfig) {
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
 
   EXPECT_CALL(mock_delegate, SetEnabled(_)).Times(0);
   EXPECT_CALL(mock_delegate, NotifyReady(_)).Times(1);
@@ -493,11 +472,7 @@
 
 TEST_F(FirstPartySetsPolicyServicePrefObserverTest,
        OnFirstPartySetsEnabledChanged_Disables_WithConfig) {
-  service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
   service()->OnFirstPartySetsEnabledChanged(false);
 
   EXPECT_CALL(mock_delegate, SetEnabled(false)).Times(1);
@@ -522,12 +497,9 @@
   net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary,
                                      absl::nullopt);
   net::FirstPartySetsContextConfig test_config({{test_primary, {test_entry}}});
+  SetContextConfig(test_config.Clone());
 
-  service()->InitForTesting(
-      [&](PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(test_config.Clone());
-      });
+  service()->InitForTesting();
   service()->OnFirstPartySetsEnabledChanged(true);
 
   // Ensure access delegate is called with SetEnabled(true) and NotifyReady is
@@ -551,39 +523,7 @@
   env().RunUntilIdle();
 }
 
-class FirstPartySetsPolicyServiceWithMockHandlerTest
-    : public FirstPartySetsPolicyServiceTest {
- public:
-  FirstPartySetsPolicyServiceWithMockHandlerTest() = default;
-
-  void SetUp() override {
-    FirstPartySetsPolicyServiceTest::SetUp();
-
-    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
-        &first_party_sets_handler_);
-  }
-
-  void TearDown() override {
-    FirstPartySetsPolicyServiceTest::TearDown();
-    first_party_sets_handler_.ResetForTesting();
-    content::FirstPartySetsHandler::GetInstance()->SetInstanceForTesting(
-        nullptr);
-  }
-
-  void SetContextConfig(net::FirstPartySetsContextConfig config) {
-    first_party_sets_handler_.SetContextConfig(std::move(config));
-  }
-  void SetCacheFilter(net::FirstPartySetsCacheFilter cache_filter) {
-    first_party_sets_handler_.SetCacheFilter(std::move(cache_filter));
-  }
-
- private:
-  MockFirstPartySetsHandler first_party_sets_handler_;
-  base::test::ScopedFeatureList features_;
-};
-
-TEST_F(FirstPartySetsPolicyServiceWithMockHandlerTest,
-       NotifiesReadyWithConfigAndCacheFilter) {
+TEST_F(FirstPartySetsPolicyServiceTest, NotifiesReadyWithConfigAndCacheFilter) {
   net::SchemefulSite test_primary(GURL("https://a.test"));
   net::FirstPartySetEntry test_entry(test_primary, net::SiteType::kPrimary,
                                      absl::nullopt);
@@ -592,11 +532,7 @@
                                                    /*browser_run_id=*/1);
   SetContextConfig(test_config.Clone());
   SetCacheFilter(test_cache_filter.Clone());
-  service()->InitForTesting(
-      [&](PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(test_config.Clone());
-      });
+  service()->InitForTesting();
 
   EXPECT_CALL(mock_delegate,
               NotifyReady(CarryingConfigAndCacheFilter(
@@ -644,11 +580,7 @@
                                     IsPrefEnabled());
   base::RunLoop run_loop;
   service()->RegisterThrottleResumeCallback(run_loop.QuitClosure());
-  service()->InitForTesting(
-      [&](PrefService* prefs,
-          base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  service()->InitForTesting();
   run_loop.Run();
 }
 
diff --git a/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc b/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc
index 2139a94e..06674c1 100644
--- a/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc
+++ b/chrome/browser/first_party_sets/mock_first_party_sets_handler.cc
@@ -7,7 +7,9 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/types/optional_util.h"
+#include "content/public/common/content_features.h"
 #include "net/first_party_sets/first_party_sets_cache_filter.h"
 #include "net/first_party_sets/first_party_sets_context_config.h"
 #include "net/first_party_sets/global_first_party_sets.h"
@@ -26,15 +28,11 @@
     const base::Version& version,
     base::File sets_file) {}
 
-void MockFirstPartySetsHandler::SetGlobalSetsForTesting(
-    net::GlobalFirstPartySets global_sets) {
-  global_sets_ = std::move(global_sets);
-}
-
 absl::optional<net::FirstPartySetEntry> MockFirstPartySetsHandler::FindEntry(
     const net::SchemefulSite& site,
     const net::FirstPartySetsContextConfig& config) const {
-  if (!global_sets_.has_value()) {
+  if (!global_sets_.has_value() ||
+      !base::FeatureList::IsEnabled(features::kFirstPartySets)) {
     return absl::nullopt;
   }
   return global_sets_->FindEntry(site, config);
@@ -68,9 +66,15 @@
     net::FirstPartySetsContextConfig config) {
   config_ = std::move(config);
 }
+
 void MockFirstPartySetsHandler::SetCacheFilter(
     net::FirstPartySetsCacheFilter cache_filter) {
   cache_filter_ = std::move(cache_filter);
 }
 
+void MockFirstPartySetsHandler::SetGlobalSets(
+    net::GlobalFirstPartySets global_sets) {
+  global_sets_ = std::move(global_sets);
+}
+
 }  // namespace first_party_sets
diff --git a/chrome/browser/first_party_sets/mock_first_party_sets_handler.h b/chrome/browser/first_party_sets/mock_first_party_sets_handler.h
index a452bff..80d30c0 100644
--- a/chrome/browser/first_party_sets/mock_first_party_sets_handler.h
+++ b/chrome/browser/first_party_sets/mock_first_party_sets_handler.h
@@ -40,7 +40,6 @@
   void SetPublicFirstPartySets(const base::Version& version,
                                base::File sets_file) override;
   void ResetForTesting() override;
-  void SetGlobalSetsForTesting(net::GlobalFirstPartySets global_sets) override;
   absl::optional<net::FirstPartySetEntry> FindEntry(
       const net::SchemefulSite& site,
       const net::FirstPartySetsContextConfig& config) const override;
@@ -59,8 +58,11 @@
 
   // Helper functions for tests to set up context.
   void SetContextConfig(net::FirstPartySetsContextConfig config);
+
   void SetCacheFilter(net::FirstPartySetsCacheFilter cache_filter);
 
+  void SetGlobalSets(net::GlobalFirstPartySets global_sets);
+
  private:
   absl::optional<net::GlobalFirstPartySets> global_sets_;
   absl::optional<net::FirstPartySetsContextConfig> config_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 60256f3..75c5e56 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2604,6 +2604,11 @@
     "expiry_milestone": 110
   },
   {
+    "name": "enable-lens-region-search-static-page",
+    "owners": ["juanmojica@google.com", "stanfield@google.com", "lens-chrome@google.com"],
+    "expiry_milestone": 110
+  },
+  {
     "name": "enable-lens-standalone",
     "owners": [ "stanfield@google.com", "benwgold@google.com", "juanmojica@google.com" ],
     "expiry_milestone": 107
@@ -3637,6 +3642,11 @@
     "expiry_milestone": 115
   },
   {
+    "name": "feed-header-stick-to-top",
+    "owners": [ "//chrome/android/feed/OWNERS", "chili@chromium.org" ],
+    "expiry_milestone": 115
+  },
+  {
     "name": "feed-interactive-refresh",
     "owners": [ "//chrome/android/feed/OWNERS", "jianli@chromium.org" ],
     "expiry_milestone": 99
@@ -3831,7 +3841,7 @@
   {
     "name": "forced-colors",
     "owners": [ "almaher@microsoft.com" ],
-    "expiry_milestone": 108
+    "expiry_milestone": 111
   },
   {
     "name": "fractional-scroll-offsets",
@@ -4448,7 +4458,7 @@
   {
     "name": "lightweight-reactions-android",
     "owners": [ "gujen", "sophey", "chrome-with-friends-robots@google.com" ],
-    "expiry_milestone": 108
+    "expiry_milestone": 110
   },
   {
     "name": "link-capturing-auto-display-intent-picker",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6c64833c..2da78cd 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1850,6 +1850,12 @@
     "Enable an entry point to Google Lens to allow users to search what they "
     "see using their mobile camera.";
 
+const char kLensRegionSearchStaticPageName[] =
+    "Use a static page with the Lens region search feature.";
+const char kLensRegionSearchStaticPageDescription[] =
+    "Enables use of a static page in a new tab when using the Lens region "
+    "search feature.";
+
 const char kLensOnQuickActionSearchWidgetName[] =
     "Google Lens in Chrome's Quick Action Search Widget";
 const char kLensOnQuickActionSearchWidgetDescription[] =
@@ -3713,6 +3719,10 @@
     "Enables showing a callout to help users return to the top of the feeds "
     "quickly.";
 
+const char kFeedHeaderStickToTopName[] = "Feed header stick to top";
+const char kFeedHeaderStickToTopDescription[] =
+    "Stick feed header to top on scroll.";
+
 const char kFeedInteractiveRefreshName[] = "Refresh feeds";
 const char kFeedInteractiveRefreshDescription[] =
     "Enables refreshing feeds triggered by the users.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index fbcb38f..3ca7adc9 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1035,6 +1035,9 @@
 extern const char kLensCameraAssistedSearchName[];
 extern const char kLensCameraAssistedSearchDescription[];
 
+extern const char kLensRegionSearchStaticPageName[];
+extern const char kLensRegionSearchStaticPageDescription[];
+
 extern const char kLensOnQuickActionSearchWidgetName[];
 extern const char kLensOnQuickActionSearchWidgetDescription[];
 
@@ -2096,6 +2099,9 @@
 extern const char kFeedBackToTopName[];
 extern const char kFeedBackToTopDescription[];
 
+extern const char kFeedHeaderStickToTopName[];
+extern const char kFeedHeaderStickToTopDescription[];
+
 extern const char kFeedInteractiveRefreshName[];
 extern const char kFeedInteractiveRefreshDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index eba24e5..aa9beec 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -142,6 +142,7 @@
     &feature_guide::features::kSkipCheckForLowEngagedUsers,
     &feed::kFeedBackToTop,
     &feed::kFeedClearImageMemoryCache,
+    &feed::kFeedHeaderStickToTop,
     &feed::kFeedImageMemoryCacheSizePercentage,
     &feed::kFeedInteractiveRefresh,
     &feed::kFeedLoadingPlaceholder,
@@ -804,7 +805,7 @@
 
 BASE_FEATURE(kIsVoiceSearchEnabledCache,
              "IsVoiceSearchEnabledCache",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kKitKatSupported,
              "KitKatSupported",
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index c50054a..0f29b42 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -359,6 +359,7 @@
     public static final String FEATURE_NOTIFICATION_GUIDE = "FeatureNotificationGuide";
     public static final String FEED_BACK_TO_TOP = "FeedBackToTop";
     public static final String FEED_CLEAR_IMAGE_MEMORY_CACHE = "FeedClearImageMemoryCache";
+    public static final String FEED_HEADER_STICK_TO_TOP = "FeedHeaderStickToTop";
     public static final String FEED_IMAGE_MEMORY_CACHE_SIZE_PERCENTAGE =
             "FeedImageMemoryCacheSizePercentage";
     public static final String FEED_INTERACTIVE_REFRESH = "FeedInteractiveRefresh";
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index ebd1e9b..9793082 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -259,7 +259,7 @@
     absl::optional<std::vector<MediaRoute>> cached_route_list_;
 
     // Per-MRP lists of routes for the query.
-    // TODO(crbug.com/761493): Consider making MRP ID an attribute of
+    // TODO(crbug.com/1374496): Consider making MRP ID an attribute of
     // MediaRoute, so that we can simplify these into vectors.
     base::flat_map<mojom::MediaRouteProviderId, std::vector<MediaRoute>>
         providers_to_routes_;
diff --git a/chrome/browser/performance_manager/metrics/page_timeline_monitor.cc b/chrome/browser/performance_manager/metrics/page_timeline_monitor.cc
index 62f443c..cfbb1629f 100644
--- a/chrome/browser/performance_manager/metrics/page_timeline_monitor.cc
+++ b/chrome/browser/performance_manager/metrics/page_timeline_monitor.cc
@@ -13,12 +13,18 @@
 #include "base/rand_util.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
 #include "components/performance_manager/public/features.h"
 #include "components/performance_manager/public/graph/page_node.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 namespace performance_manager::metrics {
 
 PageTimelineMonitor::PageTimelineMonitor()
@@ -93,8 +99,39 @@
       curr_info->time_of_last_foreground_millisecond_update = now;
     }
 
+    bool is_active_tab = false;
+    bool has_notification_permission = false;
+    bool is_capturing_media = false;
+    bool is_connected_to_device = false;
+
+    const auto* page_live_state_data =
+        PageLiveStateDecorator::Data::FromPageNode(page_node);
+    if (page_live_state_data) {
+      is_active_tab = page_live_state_data->IsActiveTab();
+      has_notification_permission =
+          page_live_state_data->IsContentSettingTypeAllowed(
+              ContentSettingsType::NOTIFICATIONS);
+      is_capturing_media = page_live_state_data->IsCapturingVideo() ||
+                           page_live_state_data->IsCapturingAudio() ||
+                           page_live_state_data->IsBeingMirrored() ||
+                           page_live_state_data->IsCapturingWindow() ||
+                           page_live_state_data->IsCapturingDisplay();
+      is_connected_to_device =
+          page_live_state_data->IsConnectedToUSBDevice() ||
+          page_live_state_data->IsConnectedToBluetoothDevice();
+    }
+
     ukm::builders::PerformanceManager_PageTimelineState(source_id)
         .SetSliceId(slice_id)
+#if !BUILDFLAG(IS_ANDROID)
+        .SetHighEfficiencyMode(
+            user_tuning::UserPerformanceTuningManager::GetInstance()
+                ->IsHighEfficiencyModeActive())
+        .SetBatterySaverMode(
+            user_tuning::UserPerformanceTuningManager::GetInstance()
+                ->IsBatterySaverActive())
+#endif  // !BUILDFLAG(IS_ANDROID)
+        .SetIsActiveTab(is_active_tab)
         .SetTimeSinceLastSlice(ukm::GetSemanticBucketMinForDurationTiming(
             time_since_last_slice.InMilliseconds()))
         .SetTimeSinceCreation(ukm::GetSemanticBucketMinForDurationTiming(
@@ -107,6 +144,11 @@
             curr_info->total_foreground_milliseconds))
         .SetChangedFaviconOrTitleInBackground(
             curr_info->updated_title_or_favicon_in_background)
+        .SetHasNotificationPermission(has_notification_permission)
+        .SetIsCapturingMedia(is_capturing_media)
+        .SetIsConnectedToDevice(is_connected_to_device)
+        .SetIsPlayingAudio(page_node->IsAudible())
+        .SetResidentSetSize(page_node->EstimateResidentSetSize())
         .Record(ukm::UkmRecorder::Get());
   }
 }
diff --git a/chrome/browser/performance_manager/metrics/page_timeline_monitor.h b/chrome/browser/performance_manager/metrics/page_timeline_monitor.h
index 6d5bc1e..87b9266 100644
--- a/chrome/browser/performance_manager/metrics/page_timeline_monitor.h
+++ b/chrome/browser/performance_manager/metrics/page_timeline_monitor.h
@@ -19,9 +19,6 @@
 
 // Periodically reports tab state via UKM, to enable analysis of usage patterns
 // over time.
-//
-// TODO(crbug.com/1367052): Report whether high-efficiency mode and/or
-// battery-saver mode are enabled.
 class PageTimelineMonitor : public PageNode::ObserverDefaultImpl,
                             public GraphOwned {
  public:
diff --git a/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc b/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
index 7d4d956..9ab9d643 100644
--- a/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
+++ b/chrome/browser/performance_manager/metrics/page_timeline_monitor_unittest.cc
@@ -8,14 +8,22 @@
 #include "base/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "build/build_config.h"
+#include "chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.h"
+#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
 #include "components/performance_manager/public/mojom/lifecycle.mojom-shared.h"
+#include "components/performance_manager/public/user_tuning/prefs.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
 #include "components/performance_manager/test_support/mock_graphs.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/performance_manager/test_support/test_user_performance_tuning_manager_environment.h"
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 namespace performance_manager::metrics {
 
 class PageTimelineMonitorUnitTest : public GraphTestHarness {
@@ -35,9 +43,17 @@
     monitor_ = monitor.get();
     graph()->PassToGraph(std::move(monitor));
     test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+#if !BUILDFLAG(IS_ANDROID)
+    performance_manager::user_tuning::prefs::RegisterLocalStatePrefs(
+        local_state_.registry());
+    environment_.SetUp(&local_state_);
+#endif  // !BUILDFLAG(IS_ANDROID)
   }
 
   void TearDown() override {
+#if !BUILDFLAG(IS_ANDROID)
+    environment_.TearDown();
+#endif  // !BUILDFLAG(IS_ANDROID)
     test_ukm_recorder_.reset();
     GraphTestHarness::TearDown();
   }
@@ -53,6 +69,13 @@
 
  private:
   std::unique_ptr<ukm::TestUkmRecorder> test_ukm_recorder_;
+
+#if !BUILDFLAG(IS_ANDROID)
+  // The UserPerformanceTuningManager doesn't exist on Android
+  TestingPrefServiceSimple local_state_;
+  performance_manager::user_tuning::TestUserPerformanceTuningManagerEnvironment
+      environment_;
+#endif  // !BUILDFLAG(IS_ANDROID)
 };
 
 TEST_F(PageTimelineMonitorUnitTest, TestPageTimeline) {
@@ -162,4 +185,157 @@
       mojom::LifecycleState::kFrozen);
 }
 
+TEST_F(PageTimelineMonitorUnitTest, TestHasNotificationsPermission) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+
+  PageLiveStateDecorator::Data* data =
+      PageLiveStateDecorator::Data::GetOrCreateForPageNode(
+          mock_graph.page.get());
+  data->SetContentSettingsForTesting(
+      {{ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW}});
+
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0],
+                                         "HasNotificationPermission", 1);
+
+  data->SetContentSettingsForTesting(
+      {{ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_BLOCK}});
+
+  TriggerCollectSlice();
+  entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 2UL);
+
+  test_ukm_recorder()->ExpectEntryMetric(entries[1],
+                                         "HasNotificationPermission", 0);
+}
+
+TEST_F(PageTimelineMonitorUnitTest, TestCapturingMedia) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+
+  PageLiveStateDecorator::Data* data =
+      PageLiveStateDecorator::Data::GetOrCreateForPageNode(
+          mock_graph.page.get());
+  data->SetIsCapturingVideoForTesting(false);
+
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0], "IsCapturingMedia", 0);
+
+  data->SetIsCapturingVideoForTesting(true);
+  TriggerCollectSlice();
+  entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 2UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[1], "IsCapturingMedia", 1);
+}
+
+TEST_F(PageTimelineMonitorUnitTest, TestConnectedToDevice) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+
+  PageLiveStateDecorator::Data* data =
+      PageLiveStateDecorator::Data::GetOrCreateForPageNode(
+          mock_graph.page.get());
+  data->SetIsConnectedToUSBDeviceForTesting(false);
+
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0], "IsConnectedToDevice", 0);
+
+  data->SetIsConnectedToUSBDeviceForTesting(true);
+  TriggerCollectSlice();
+  entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 2UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[1], "IsConnectedToDevice", 1);
+}
+
+TEST_F(PageTimelineMonitorUnitTest, TestAudible) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+
+  mock_graph.page->SetIsAudible(false);
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0], "IsPlayingAudio", 0);
+
+  mock_graph.page->SetIsAudible(true);
+  TriggerCollectSlice();
+  entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 2UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[1], "IsPlayingAudio", 1);
+}
+
+TEST_F(PageTimelineMonitorUnitTest, TestIsActiveTab) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+
+  PageLiveStateDecorator::Data* data =
+      PageLiveStateDecorator::Data::GetOrCreateForPageNode(
+          mock_graph.page.get());
+  data->SetIsActiveTabForTesting(false);
+
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0], "IsActiveTab", 0);
+
+  data->SetIsActiveTabForTesting(true);
+  TriggerCollectSlice();
+  entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 2UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[1], "IsActiveTab", 1);
+}
+
+TEST_F(PageTimelineMonitorUnitTest, TestResidentSetSize) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  ukm::SourceId mock_source_id = ukm::NoURLSourceId();
+  mock_graph.page->SetType(performance_manager::PageType::kTab);
+  mock_graph.page->SetUkmSourceId(mock_source_id);
+  mock_graph.page->SetIsVisible(true);
+  mock_graph.page->SetLifecycleStateForTesting(mojom::LifecycleState::kRunning);
+  mock_graph.frame->SetResidentSetKbEstimate(123);
+
+  TriggerCollectSlice();
+  auto entries = test_ukm_recorder()->GetEntriesByName(
+      ukm::builders::PerformanceManager_PageTimelineState::kEntryName);
+  EXPECT_EQ(entries.size(), 1UL);
+  test_ukm_recorder()->ExpectEntryMetric(entries[0], "ResidentSetSize", 123);
+}
+
 }  // namespace performance_manager::metrics
diff --git a/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h b/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
index 4945450..cf90cb37 100644
--- a/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
+++ b/chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h
@@ -133,6 +133,9 @@
   void SetTemporaryBatterySaverDisabledForSession(bool disabled);
   bool IsBatterySaverModeDisabledForSession() const;
 
+  // Returns true if High Efficiency mode is currently enabled.
+  bool IsHighEfficiencyModeActive() const;
+
   // Returns true if Battery Saver Mode interventions are active. If any state
   // transitions cause an observer notification, this is guaranteed to reflect
   // the *new* value when the observers are notified so the UI layer can make
diff --git a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
index 50e432e..6965bea5 100644
--- a/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_performance_tuning_manager.cc
@@ -113,6 +113,11 @@
   return battery_saver_mode_disabled_for_session_;
 }
 
+bool UserPerformanceTuningManager::IsHighEfficiencyModeActive() const {
+  return pref_change_registrar_.prefs()->GetBoolean(
+      performance_manager::user_tuning::prefs::kHighEfficiencyModeEnabled);
+}
+
 bool UserPerformanceTuningManager::IsBatterySaverActive() const {
   return battery_saver_mode_enabled_;
 }
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc
index bf35239a..2f590a66 100644
--- a/chrome/browser/printing/print_backend_service_manager.cc
+++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
@@ -29,6 +30,9 @@
 
 #if BUILDFLAG(IS_WIN)
 #include "base/win/win_util.h"
+#include "chrome/browser/printing/printer_xml_parser_impl.h"
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "printing/backend/win_helper.h"
 #include "printing/printed_page_win.h"
 #include "ui/views/win/hwnd_util.h"
@@ -152,6 +156,13 @@
                                                      remote_id);
   if (new_timeout.has_value())
     UpdateServiceIdleTimeoutByRemoteId(remote_id, new_timeout.value());
+
+#if BUILDFLAG(IS_WIN)
+  if (base::FeatureList::IsEnabled(features::kReadPrinterCapabilitiesWithXps) &&
+      query_clients_.empty()) {
+    xml_parser_.reset();
+  }
+#endif  // BUILDFLAG(IS_WIN)
 }
 
 void PrintBackendServiceManager::EnumeratePrinters(
@@ -648,6 +659,17 @@
 
     // Initialize the new service for the desired locale.
     service->Init(g_browser_process->GetApplicationLocale());
+
+#if BUILDFLAG(IS_WIN)
+    // Bind PrintBackendService with a Remote that allows pass-through requests
+    // to an XML parser.
+    if (base::FeatureList::IsEnabled(
+            features::kReadPrinterCapabilitiesWithXps)) {
+      if (!xml_parser_)
+        xml_parser_ = std::make_unique<PrinterXmlParserImpl>();
+      service->BindPrinterXmlParser(xml_parser_->GetRemote());
+    }
+#endif  // BUILDFLAG(IS_WIN)
   }
 
   return service;
diff --git a/chrome/browser/printing/print_backend_service_manager.h b/chrome/browser/printing/print_backend_service_manager.h
index 69a55088..68861abf 100644
--- a/chrome/browser/printing/print_backend_service_manager.h
+++ b/chrome/browser/printing/print_backend_service_manager.h
@@ -35,6 +35,10 @@
 
 namespace printing {
 
+#if BUILDFLAG(IS_WIN)
+class PrinterXmlParserImpl;
+#endif  // BUILDFLAG(IS_WIN)
+
 class PrintedPage;
 
 class PrintBackendServiceManager {
@@ -427,6 +431,12 @@
       const ClientsSet& query_with_ui_clients,
       const PrintClientsMap& print_document_clients);
 
+#if BUILDFLAG(IS_WIN)
+  // Printer XML Parser implementation used to allow Print Backend Service to
+  // send XML parse requests to the browser process.
+  std::unique_ptr<PrinterXmlParserImpl> xml_parser_;
+#endif  // BUILDFLAG(IS_WIN)
+
   // Bundles of remotes for the Print Backend Service and their corresponding
   // wrapping hosts, to manage these sets until they disconnect.  The sandboxed
   // and unsandboxed services are kept separate.
diff --git a/chrome/browser/printing/print_backend_service_test_impl.cc b/chrome/browser/printing/print_backend_service_test_impl.cc
index 9bd6d02..65286269 100644
--- a/chrome/browser/printing/print_backend_service_test_impl.cc
+++ b/chrome/browser/printing/print_backend_service_test_impl.cc
@@ -14,6 +14,14 @@
 #include "chrome/browser/printing/print_backend_service_manager.h"
 #include "printing/backend/test_print_backend.h"
 
+#if BUILDFLAG(IS_WIN)
+#include <memory>
+
+#include "chrome/browser/printing/printer_xml_parser_impl.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "printing/printing_features.h"
+#endif  // BUILDFLAG(IS_WIN)
+
 namespace printing {
 
 #if BUILDFLAG(IS_WIN)
@@ -169,6 +177,15 @@
   receiver_.reset();
 }
 
+#if BUILDFLAG(IS_WIN)
+mojo::PendingRemote<mojom::PrinterXmlParser>
+PrintBackendServiceTestImpl::GetPrinterXmlParserRemote() {
+  if (!xml_parser_)
+    xml_parser_ = std::make_unique<PrinterXmlParserImpl>();
+  return xml_parser_->GetRemote();
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 // static
 std::unique_ptr<PrintBackendServiceTestImpl>
 PrintBackendServiceTestImpl::LaunchForTesting(
@@ -183,6 +200,11 @@
       new PrintBackendServiceTestImpl(std::move(receiver), std::move(backend)));
   service->Init(/*locale=*/std::string());
 
+#if BUILDFLAG(IS_WIN)
+  if (base::FeatureList::IsEnabled(features::kReadPrinterCapabilitiesWithXps))
+    service->BindPrinterXmlParser(service->GetPrinterXmlParserRemote());
+#endif  // BUILDFLAG(IS_WIN)
+
   // Register this test version of print backend service to be used instead of
   // launching instances out-of-process on-demand.
   if (sandboxed) {
diff --git a/chrome/browser/printing/print_backend_service_test_impl.h b/chrome/browser/printing/print_backend_service_test_impl.h
index 807a8f3..da877410 100644
--- a/chrome/browser/printing/print_backend_service_test_impl.h
+++ b/chrome/browser/printing/print_backend_service_test_impl.h
@@ -20,6 +20,8 @@
 #if BUILDFLAG(IS_WIN)
 #include "base/containers/queue.h"
 #include "base/memory/read_only_shared_memory_region.h"
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom-forward.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "printing/mojom/print.mojom.h"
 #endif
 
@@ -33,6 +35,7 @@
 namespace printing {
 
 #if BUILDFLAG(IS_WIN)
+class PrinterXmlParserImpl;
 struct RenderPrintedPageData;
 #endif
 
@@ -98,6 +101,8 @@
   void set_rendering_delayed_until_page(uint32_t page_number) {
     rendering_delayed_until_page_number_ = page_number;
   }
+
+  mojo::PendingRemote<mojom::PrinterXmlParser> GetPrinterXmlParserRemote();
 #endif
 
  private:
@@ -127,6 +132,9 @@
 
   // The queue of pages whose rendering processing is being delayed.
   base::queue<std::unique_ptr<RenderPrintedPageData>> delayed_rendering_pages_;
+
+  // Used to parse XPS XML capabilities.
+  std::unique_ptr<PrinterXmlParserImpl> xml_parser_;
 #endif
 
   scoped_refptr<TestPrintBackend> test_print_backend_;
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 47fcd1e..a70cd643 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -271,7 +271,7 @@
     fail_on_use_default_settings_ = true;
   }
 
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   void SetCancelErrorOnAskUserForSettings() {
     cancel_on_ask_user_for_settings_ = true;
   }
@@ -291,7 +291,7 @@
   bool access_denied_errors_for_render_document_ = false;
   bool access_denied_errors_for_document_done_ = false;
   bool fail_on_use_default_settings_ = false;
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   bool cancel_on_ask_user_for_settings_ = false;
 #endif
   int new_document_called_count_ = 0;
@@ -2741,7 +2741,7 @@
     test_printing_context_factory()->SetFailErrorOnUseDefaultSettings();
   }
 
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   void PrimeForCancelInAskUserForSettings() {
     test_printing_context_factory()->SetCancelErrorOnAskUserForSettings();
   }
@@ -2789,7 +2789,7 @@
     return use_default_settings_result_;
   }
 
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   mojom::ResultCode ask_user_for_settings_result() const {
     return ask_user_for_settings_result_;
   }
@@ -2874,7 +2874,7 @@
     CheckForQuit();
   }
 
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   void OnDidAskUserForSettings(mojom::ResultCode result) {
     ask_user_for_settings_result_ = result;
     CheckForQuit();
@@ -2945,7 +2945,7 @@
   raw_ptr<PrintJob> print_job_ = nullptr;
   bool reset_errors_after_check_ = true;
   mojom::ResultCode use_default_settings_result_ = mojom::ResultCode::kFailed;
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
   mojom::ResultCode ask_user_for_settings_result_ = mojom::ResultCode::kFailed;
 #endif
   mojom::ResultCode start_printing_result_ = mojom::ResultCode::kFailed;
@@ -3386,9 +3386,7 @@
   EXPECT_EQ(print_job_destruction_count(), 1);
 }
 
-// TODO(crbug.com/809738)  Extend to Linux once Wayland can be made to support
-// a system be modal against an application window in the browser process.
-#if BUILDFLAG(IS_WIN)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
 IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest,
                        StartBasicPrint) {
   AddPrinter("printer1");
@@ -3403,24 +3401,53 @@
   ASSERT_TRUE(web_contents);
   SetUpPrintViewManager(web_contents);
 
+#if BUILDFLAG(IS_WIN)
   // The test will get the default settings followed by asking the user for
   // settings.  After that a print job will be started, with a page getting
   // rendered, and finally the document done notification.  Wait for the one
   // print job to be destroyed to ensure printing finished cleanly before
   // completing the test.  This results in a total of 6 calls.
   SetNumExpectedMessages(/*num=*/6);
+#else
+  // The test sequence for this is:
+  // - Get the default settings.
+  // - Ask the user for settings.  Due to issues with displaying a system dialog
+  //   from the utility process, there is no callback to capture the request for
+  //   user supplied settings.
+  // - A print job is started.
+  // - The document is rendered.
+  // - Receive document done notification.
+  // - Wait for the one print job to be destroyed, to ensure printing finished
+  //   cleanly before completing the test.
+  // This results in a total of 5 calls.
+  // TODO(crbug.com/1374188)  Update this expectation once
+  // `AskUserForSettings()` is able to be pushed OOP for Linux.
+  SetNumExpectedMessages(/*num=*/5);
+#endif
 
   StartBasicPrint(web_contents);
 
   WaitUntilCallbackReceived();
 
   EXPECT_EQ(use_default_settings_result(), mojom::ResultCode::kSuccess);
+  // macOS and Linux currently have to invoke a system dialog from within the
+  // browser process.  There is not a callback to capture the result in these
+  // cases.
+  // TODO(crbug.com/1374188)  Re-enable this check against
+  // `ask_user_for_settings_result()` once `AskForUserSettings()` is able to be
+  // pushed OOP for Linux.
+#if BUILDFLAG(IS_WIN)
   EXPECT_EQ(ask_user_for_settings_result(), mojom::ResultCode::kSuccess);
+#endif
   EXPECT_EQ(start_printing_result(), mojom::ResultCode::kSuccess);
+#if BUILDFLAG(IS_WIN)
   // TODO(crbug.com/1008222)  Include Windows coverage of
   // RenderPrintedDocument() once XPS print pipeline is added.
   EXPECT_EQ(render_printed_page_result(), mojom::ResultCode::kSuccess);
   EXPECT_EQ(render_printed_page_count(), 1);
+#else
+  EXPECT_EQ(render_printed_document_result(), mojom::ResultCode::kSuccess);
+#endif
   EXPECT_EQ(document_done_result(), mojom::ResultCode::kSuccess);
   EXPECT_EQ(print_job_destruction_count(), 1);
 }
@@ -3459,8 +3486,18 @@
   EXPECT_FALSE(print_backend_service_use_detected());
 }
 
+// macOS and Linux currently have to invoke a system dialog from within the
+// browser process.  There is not a callback to capture the result in these
+// cases.
+// TODO(crbug.com/1374188)  Re-enable for Linux once `AskForUserSettings()` is
+// able to be pushed OOP for Linux.
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#define MAYBE_StartBasicPrintCancel DISABLED_StartBasicPrintCancel
+#else
+#define MAYBE_StartBasicPrintCancel StartBasicPrintCancel
+#endif
 IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest,
-                       StartBasicPrintCancel) {
+                       MAYBE_StartBasicPrintCancel) {
   AddPrinter("printer1");
   SetPrinterNameForSubsequentContexts("printer1");
   PrimeForCancelInAskUserForSettings();
@@ -3510,17 +3547,18 @@
   // Now initiate a system print that would exist concurrently with that.
   StartBasicPrint(web_contents);
 
-  // On Windows, concurrent system print is not allowed.
-  // TODO(crbug.com/809738):  Demonstrate that Linux allows multiple system
-  // prints at a time.
   const absl::optional<bool>& result = print_view_manager->print_now_result();
   ASSERT_TRUE(result.has_value());
+  // With the exception of Linux, concurrent system print is not allowed.
+#if BUILDFLAG(IS_LINUX)
+  EXPECT_TRUE(*result);
+#else
   EXPECT_FALSE(*result);
+#endif
 
   // Cleanup before test shutdown.
   PrintBackendServiceManager::GetInstance().UnregisterClient(*client_id);
 }
-#endif  // BUILDFLAG(IS_WIN)
 
 // https://crbug.com/1320681 flaky.
 IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest,
@@ -3549,6 +3587,7 @@
   EXPECT_EQ(use_default_settings_result(), mojom::ResultCode::kFailed);
   EXPECT_EQ(print_job_construction_count(), 1);
 }
+#endif  // BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
 
 #endif  //  BUILDFLAG(ENABLE_OOP_PRINTING)
 
@@ -3757,13 +3796,11 @@
 
 INSTANTIATE_TEST_SUITE_P(All, ContentAnalysisPrintBrowserTest, testing::Bool());
 
-// This test suite doesn't run on CrOS since it doesn't support non-print
-// preview scripted printing.
-#if !BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
 INSTANTIATE_TEST_SUITE_P(All,
                          ContentAnalysisScriptedPreviewlessPrintBrowserTest,
                          testing::Bool());
-#endif  // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(ENABLE_BASIC_PRINT_DIALOG)
 
 #endif  // BUILDFLAG(ENABLE_PRINT_SCANNING)
 
diff --git a/chrome/browser/printing/printer_xml_parser_impl.cc b/chrome/browser/printing/printer_xml_parser_impl.cc
new file mode 100644
index 0000000..de0efa8b
--- /dev/null
+++ b/chrome/browser/printing/printer_xml_parser_impl.cc
@@ -0,0 +1,60 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/printing/printer_xml_parser_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/values.h"
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "printing/mojom/print.mojom.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+namespace printing {
+
+namespace {
+
+void XmlPrinterCapabilitiesParsed(
+    PrinterXmlParserImpl::ParseXmlCallback callback,
+    data_decoder::DataDecoder::ValueOrError value_or_error) {
+  if (!value_or_error.has_value()) {
+    std::move(callback).Run(
+        mojom::PrinterCapabilitiesValueResult::NewResultCode(
+            mojom::ResultCode::kFailed));
+    return;
+  }
+  std::move(callback).Run(
+      mojom::PrinterCapabilitiesValueResult::NewCapabilities(
+          std::move(value_or_error.value())));
+}
+
+}  // namespace
+
+PrinterXmlParserImpl::PrinterXmlParserImpl() = default;
+
+PrinterXmlParserImpl::~PrinterXmlParserImpl() = default;
+
+void PrinterXmlParserImpl::ParseXmlForPrinterCapabilities(
+    const std::string& capabilities_xml,
+    ParseXmlCallback callback) {
+  if (!decoder_)
+    decoder_ = std::make_unique<data_decoder::DataDecoder>();
+  decoder_->ParseXml(
+      capabilities_xml,
+      data_decoder::mojom::XmlParser::WhitespaceBehavior::kIgnore,
+      base::BindOnce(&XmlPrinterCapabilitiesParsed, std::move(callback)));
+}
+
+mojo::PendingRemote<mojom::PrinterXmlParser> PrinterXmlParserImpl::GetRemote() {
+  mojo::PendingRemote<mojom::PrinterXmlParser> pending_remote;
+  receivers_.Add(this, pending_remote.InitWithNewPipeAndPassReceiver());
+  return pending_remote;
+}
+
+}  // namespace printing
diff --git a/chrome/browser/printing/printer_xml_parser_impl.h b/chrome/browser/printing/printer_xml_parser_impl.h
new file mode 100644
index 0000000..a31055be
--- /dev/null
+++ b/chrome/browser/printing/printer_xml_parser_impl.h
@@ -0,0 +1,40 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PRINTING_PRINTER_XML_PARSER_IMPL_H_
+#define CHROME_BROWSER_PRINTING_PRINTER_XML_PARSER_IMPL_H_
+
+#include <memory>
+
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "printing/mojom/print.mojom.h"
+#include "services/data_decoder/public/cpp/data_decoder.h"
+
+namespace printing {
+
+class PrinterXmlParserImpl : public mojom::PrinterXmlParser {
+ public:
+  using ParseXmlCallback =
+      base::OnceCallback<void(mojom::PrinterCapabilitiesValueResultPtr)>;
+
+  PrinterXmlParserImpl();
+  PrinterXmlParserImpl(const PrinterXmlParserImpl&) = delete;
+  PrinterXmlParserImpl& operator=(const PrinterXmlParserImpl&) = delete;
+  ~PrinterXmlParserImpl() override;
+
+  void ParseXmlForPrinterCapabilities(const std::string& capabilities_xml,
+                                      ParseXmlCallback callback) override;
+
+  mojo::PendingRemote<mojom::PrinterXmlParser> GetRemote();
+
+ private:
+  mojo::ReceiverSet<mojom::PrinterXmlParser> receivers_;
+  std::unique_ptr<data_decoder::DataDecoder> decoder_;
+};
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINTER_XML_PARSER_IMPL_H_
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
index a992b690..e8c5c966 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/first_party_sets/first_party_sets_policy_service.h"
+#include "chrome/browser/first_party_sets/mock_first_party_sets_handler.h"
 #include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/chrome_features.h"
@@ -683,9 +684,19 @@
 
   void SetUp() override {
     CreateService();
+    content::FirstPartySetsHandler::SetInstanceForTesting(
+        &mock_first_party_sets_handler_);
+    mock_first_party_sets_handler().SetCacheFilter(
+        net::FirstPartySetsCacheFilter());
+    mock_first_party_sets_handler().SetContextConfig(
+        net::FirstPartySetsContextConfig());
     SetGlobalFirstPartySetsAndWait();
   }
 
+  void TearDown() override {
+    content::FirstPartySetsHandler::SetInstanceForTesting(nullptr);
+  }
+
   virtual std::unique_ptr<
       privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>
   GetMockDelegate() {
@@ -752,6 +763,9 @@
   browsing_topics::MockBrowsingTopicsService* mock_browsing_topics_service() {
     return &mock_browsing_topics_service_;
   }
+  first_party_sets::MockFirstPartySetsHandler& mock_first_party_sets_handler() {
+    return mock_first_party_sets_handler_;
+  }
   first_party_sets::FirstPartySetsPolicyService*
   first_party_sets_policy_service() {
     return &first_party_sets_policy_service_;
@@ -763,8 +777,7 @@
 #endif
 
   void SetGlobalFirstPartySetsAndWait() {
-    content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
-    content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting({});
+    mock_first_party_sets_handler_.SetGlobalSets({});
     base::RunLoop run_loop;
     first_party_sets_policy_service_.WaitForFirstInitCompleteForTesting(
         run_loop.QuitClosure());
@@ -779,6 +792,7 @@
   base::test::ScopedFeatureList feature_list_;
   TestInterestGroupManager test_interest_group_manager_;
   browsing_topics::MockBrowsingTopicsService mock_browsing_topics_service_;
+  first_party_sets::MockFirstPartySetsHandler mock_first_party_sets_handler_;
   first_party_sets::FirstPartySetsPolicyService
       first_party_sets_policy_service_ =
           first_party_sets::FirstPartySetsPolicyService(
@@ -2129,16 +2143,10 @@
                            content_settings::CookieControlsMode::kOff)));
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
 
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      global_sets.Clone());
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
+
+  first_party_sets_policy_service()->InitForTesting();
   // We shouldn't get associate1's owner since FPS is disabled.
   EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl),
             absl::nullopt);
@@ -2177,16 +2185,9 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
+  mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
 
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      global_sets.Clone());
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  first_party_sets_policy_service()->InitForTesting();
   // We shouldn't get associate1's owner since FPS is disabled.
   EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl),
             absl::nullopt);
@@ -2227,16 +2228,9 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
+  mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
 
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      global_sets.Clone());
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  first_party_sets_policy_service()->InitForTesting();
 
   // We shouldn't get associate1's owner since FPS is disabled.
   EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl),
@@ -2278,16 +2272,8 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
-
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      global_sets.Clone());
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
+  first_party_sets_policy_service()->InitForTesting();
 
   // We shouldn't get associate1's owner since FPS is disabled.
   EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl),
@@ -2330,16 +2316,9 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(false));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
+  mock_first_party_sets_handler().SetGlobalSets(global_sets.Clone());
 
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      global_sets.Clone());
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig());
-      });
+  first_party_sets_policy_service()->InitForTesting();
 
   // We shouldn't get associate1's owner since FPS is disabled.
   EXPECT_EQ(privacy_sandbox_service()->GetFirstPartySetOwner(associate1_gurl),
@@ -2413,32 +2392,26 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
-
   // Simulate that the Global First-Party Sets are ready with the following set:
   // { primary: "https://primary.test",
   // associatedSites: ["https://associate1.test", "https://associate2.test"] }
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      net::GlobalFirstPartySets(
-          {{associate1_site,
-            {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
-                                     0)}},
-           {associate2_site,
-            {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
-                                     1)}}},
-          {}));
+  mock_first_party_sets_handler().SetGlobalSets(net::GlobalFirstPartySets(
+      {{associate1_site,
+        {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated, 0)}},
+       {associate2_site,
+        {net::FirstPartySetEntry(primary_site, net::SiteType::kAssociated,
+                                 1)}}},
+      {}));
 
   // Simulate that associate2 is removed from the Global First-Party Sets for
   // this profile.
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(net::FirstPartySetsContextConfig(
-            net::FirstPartySetsContextConfig::OverrideSets{
-                {net::SchemefulSite(GURL("https://associate2.test")),
-                 {absl::nullopt}}}));
-      });
+  mock_first_party_sets_handler().SetContextConfig(
+      net::FirstPartySetsContextConfig(
+          net::FirstPartySetsContextConfig::OverrideSets{
+              {net::SchemefulSite(GURL("https://associate2.test")),
+               {absl::nullopt}}}));
+
+  first_party_sets_policy_service()->InitForTesting();
 
   // Verify that primary owns associate1, but no longer owns associate2.
   EXPECT_EQ(
@@ -2539,9 +2512,6 @@
   prefs()->SetUserPref(prefs::kPrivacySandboxFirstPartySetsEnabled,
                        std::make_unique<base::Value>(true));
 
-  // Reset test state to reflect required state above.
-  content::FirstPartySetsHandler::GetInstance()->ResetForTesting();
-
   // Simulate that the Global First-Party Sets are ready with the following
   // set:
   // { primary: "https://youtube-primary.test",
@@ -2551,26 +2521,23 @@
   GURL youtube_gurl("https://youtube.com");
   net::SchemefulSite youtube_site(youtube_gurl);
 
-  content::FirstPartySetsHandler::GetInstance()->SetGlobalSetsForTesting(
-      net::GlobalFirstPartySets(
-          {{youtube_site,
-            {net::FirstPartySetEntry(youtube_primary_site,
-                                     net::SiteType::kAssociated, 0)}}},
-          {}));
+  mock_first_party_sets_handler().SetGlobalSets(net::GlobalFirstPartySets(
+      {{youtube_site,
+        {net::FirstPartySetEntry(youtube_primary_site,
+                                 net::SiteType::kAssociated, 0)}}},
+      {}));
 
   // Simulate that https://google.de is moved into a new First-Party Set for
   // this profile.
-  first_party_sets_policy_service()->InitForTesting(
-      [](PrefService* prefs,
-         base::OnceCallback<void(net::FirstPartySetsContextConfig)> callback) {
-        std::move(callback).Run(
-            net::FirstPartySetsContextConfig(net::FirstPartySetsContextConfig(
-                net::FirstPartySetsContextConfig::OverrideSets{
-                    {net::SchemefulSite(GURL("https://google.de")),
-                     {net::FirstPartySetEntry(
-                         net::SchemefulSite(GURL("https://new-primary.test")),
-                         net::SiteType::kAssociated, 0)}}})));
-      });
+  mock_first_party_sets_handler().SetContextConfig(
+      net::FirstPartySetsContextConfig(
+          net::FirstPartySetsContextConfig::OverrideSets{
+              {net::SchemefulSite(GURL("https://google.de")),
+               {net::FirstPartySetEntry(
+                   net::SchemefulSite(GURL("https://new-primary.test")),
+                   net::SiteType::kAssociated, 0)}}}));
+
+  first_party_sets_policy_service()->InitForTesting();
 
   // Expect queries to be resolved based on the FPS sample sets.
   EXPECT_GT(privacy_sandbox_service()->GetSampleFirstPartySets().size(), 0u);
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index a4c41a8..6760b10 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -247,6 +247,7 @@
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/lens/region_search/lens_region_search_controller.h"
+#include "chrome/browser/ui/lens/lens_side_panel_helper.h"
 #include "chrome/grit/theme_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #endif
@@ -3638,9 +3639,14 @@
     int event_flags,
     bool is_google_default_search_provider) {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  Browser* browser = GetBrowser();
+  CHECK(browser);
+  if (lens::features::IsLensRegionSearchStaticPageEnabled()) {
+    lens::OpenLensStaticPage(browser);
+    return;
+  }
+
   if (!lens_region_search_controller_) {
-    Browser* browser = GetBrowser();
-    CHECK(browser);
     WebContents* web_contents = source_web_contents_;
     if (base::FeatureList::IsEnabled(
             lens::features::kEnableRegionSearchOnPdfViewer)) {
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index f185ec8..e3fdecd2 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -53,7 +53,10 @@
       "whats_new:resources",
     ]
     if (is_chrome_branded) {
-      public_deps += [ "media_router/cast_feedback:resources" ]
+      public_deps += [
+        "lens:resources",
+        "media_router/cast_feedback:resources",
+      ]
     }
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/macro_names.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/macro_names.js
index b6ffdee..3696654 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/macro_names.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/macro_names.js
@@ -100,5 +100,8 @@
   // Move the cursor to the previous sentence.
   NAV_PREV_SENT: 26,
 
+  // Deletes all text in the input box.
+  DELETE_ALL_TEXT: 27,
+
   // Any new actions should match with Voice Access's semantic tags.
 };
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/repeatable_key_press_macro.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/repeatable_key_press_macro.js
index 9722f96..73e06f97 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/repeatable_key_press_macro.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/macros/repeatable_key_press_macro.js
@@ -247,3 +247,16 @@
         LocaleInfo.isRTLLocale() ? KeyCode.RIGHT : KeyCode.LEFT, {ctrl: true});
   }
 }
+
+/** Macro to delete all text in input field. */
+export class DeleteAllText extends RepeatableKeyPressMacro {
+  constructor() {
+    super(MacroName.DELETE_ALL_TEXT, 1);
+  }
+
+  /** @override */
+  doKeyPress() {
+    EventGenerator.sendKeyPress(KeyCode.A, {ctrl: true});
+    EventGenerator.sendKeyPress(KeyCode.BACK);
+  }
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin_parse_strategy.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin_parse_strategy.js
index e5854b2f..a3e63cf 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin_parse_strategy.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin_parse_strategy.js
@@ -200,6 +200,8 @@
         text = argument.value;
       }
     }
+    // TODO(crbug.com/1362842) Add all macros under the DictationMoreCommands
+    // to this switch statement.
     switch (tag) {
       case MacroName.INPUT_TEXT_VIEW:
         return new InputTextViewMacro(text, this.getInputController());
@@ -255,6 +257,9 @@
       // Try to get results from Pumpkin.
       // TODO(crbug.com/1264544): Could increase the hypotheses count from 1
       // when we are ready to implement disambiguation.
+      // TODO(crbug.com/1362842) Add logic to check whether
+      // DictationMoreCommands is enabled or not before
+      // running the macros hidden within that flag.
       const taggerResults =
           this.pumpkinTagger_.tagAndGetNBestHypotheses(text, 1);
       if (taggerResults && taggerResults.hypothesisList.length > 0) {
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/simple_parse_strategy.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/simple_parse_strategy.js
index eaa1a5d0..2dabfbc 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/simple_parse_strategy.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/simple_parse_strategy.js
@@ -237,9 +237,17 @@
         messageId: 'dictation_command_nav_prev_sent',
         build: NavPrevSentMacro,
       },
+      [MacroName.DELETE_ALL_TEXT]: {
+        messageId: 'dictation_command_delete_all_text',
+        build: RepeatableKeyPress.DeleteAllText,
+      },
     };
   }
 }
+// TODO(crbug.com/1362842) Do not release any Macros
+// hidden under the DictationMoreCommands Flag
+// using the simple_parse_strategy, rather
+// move them over to the pumpkin_parse_strategy
 
 /** A parsing strategy that utilizes SimpleMacroFactory. */
 export class SimpleParseStrategy extends ParseStrategy {
@@ -252,6 +260,13 @@
      * @private {!Map<MacroName, !SimpleMacroFactory>}
      */
     this.macroFactoryMap_ = new Map();
+
+    /** @private {boolean} */
+    this.isMoreCommandsFeatureEnabled_ = false;
+
+    /** @private {!Array<!MacroName>}*/
+    this.moreCommandsSet_ = [MacroName.DELETE_ALL_TEXT];
+
     this.initialize_();
   }
 
@@ -267,6 +282,13 @@
       this.macroFactoryMap_.set(
           name, new SimpleMacroFactory(name, this.getInputController()));
     }
+
+    const moreCommandsFeature = chrome.accessibilityPrivate.AccessibilityFeature
+                                    .DICTATION_MORE_COMMANDS;
+    chrome.accessibilityPrivate.isFeatureEnabled(
+        moreCommandsFeature, enabled => {
+          this.isMoreCommandsFeatureEnabled_ = enabled;
+        });
   }
 
   /** @override */
@@ -280,12 +302,30 @@
     this.initialize_();
   }
 
+  /**
+   * @param {Macro} macro
+   * @return {boolean}
+   * @private
+   */
+  shouldAddMacro_(macro) {
+    if (!macro) {
+      return false;
+    }
+
+    const isNewCommand = this.moreCommandsSet_.includes(macro.getMacroName());
+    if (!isNewCommand) {
+      return true;
+    }
+
+    return this.isMoreCommandsFeatureEnabled_;
+  }
+
   /** @override */
   async parse(text) {
     const macros = [];
     for (const [name, factory] of this.macroFactoryMap_) {
       const macro = factory.createMacro(text);
-      if (macro) {
+      if (this.shouldAddMacro_(macro)) {
         macros.push(macro);
       }
     }
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/dictation_strings.grdp b/chrome/browser/resources/chromeos/accessibility/strings/dictation_strings.grdp
index 9b5ccab..6fb98ded 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/dictation_strings.grdp
+++ b/chrome/browser/resources/chromeos/accessibility/strings/dictation_strings.grdp
@@ -78,4 +78,7 @@
   <message name="DICTATION_COMMAND_NAV_PREV_SENT" desc="A spoken command to move the cursor to the previous sentence." is_accessibility_with_no_ui="true">
     move to the previous sentence
   </message>
+  <message name="DICTATION_COMMAND_DELETE_ALL_TEXT" desc="A spoken command to delete all text in the input field." is_accessibility_with_no_ui="true">
+    delete all
+  </message>
 </grit-part>
diff --git a/chrome/browser/resources/lens/BUILD.gn b/chrome/browser/resources/lens/BUILD.gn
new file mode 100644
index 0000000..8ae57c93
--- /dev/null
+++ b/chrome/browser/resources/lens/BUILD.gn
@@ -0,0 +1,15 @@
+# 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("//build/config/chrome_build.gni")
+import("//chrome/browser/resources/tools/build_webui.gni")
+
+assert(toolkit_views)
+assert(is_chrome_branded)
+
+build_webui("build") {
+  grd_prefix = "lens"
+  static_files = [ "lens.html" ]
+  non_web_component_files = [ "app.ts" ]
+  ts_use_local_config = false
+}
diff --git a/chrome/browser/resources/lens/DIR_METADATA b/chrome/browser/resources/lens/DIR_METADATA
new file mode 100644
index 0000000..749bdad
--- /dev/null
+++ b/chrome/browser/resources/lens/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser"
+}
+team_email: "lens-chrome-eng+bugs@google.com"
diff --git a/chrome/browser/resources/lens/OWNERS b/chrome/browser/resources/lens/OWNERS
new file mode 100644
index 0000000..f6009d23
--- /dev/null
+++ b/chrome/browser/resources/lens/OWNERS
@@ -0,0 +1 @@
+file://components/lens/OWNERS
diff --git a/chrome/browser/resources/lens/app.ts b/chrome/browser/resources/lens/app.ts
new file mode 100644
index 0000000..d2e09d1
--- /dev/null
+++ b/chrome/browser/resources/lens/app.ts
@@ -0,0 +1,7 @@
+// 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.
+
+document.addEventListener('DOMContentLoaded', function() {
+  console.info('Content loaded.');
+});
diff --git a/chrome/browser/resources/lens/lens.html b/chrome/browser/resources/lens/lens.html
new file mode 100644
index 0000000..339a59e
--- /dev/null
+++ b/chrome/browser/resources/lens/lens.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+  <meta charset="utf-8">
+</head>
+<body>
+  <pre>
+    Placeholder text
+  </pre>
+  <script type="module" src="app.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 6785c150..4a27d27 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -405,6 +405,7 @@
     ":deep_linking_behavior",
     ":find_shortcut_behavior",
     ":global_scroll_target_behavior",
+    ":icon",
     ":lazy_load",
     ":metrics_recorder",
     ":os_icons",
@@ -526,6 +527,9 @@
   ]
 }
 
+js_library("icon") {
+}
+
 js_library("personalization_search_handler") {
   deps = [ "//ash/webui/personalization_app/search:mojo_bindings_webui_js" ]
 }
diff --git a/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts b/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
index 5585ffe..8ca94560 100644
--- a/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
+++ b/chrome/browser/resources/settings/chromeos/date_time_page/date_time_page.ts
@@ -24,11 +24,10 @@
 
 import {loadTimeData} from '../../i18n_setup.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './date_time_page.html.js';
 import {TimeZoneBrowserProxy, TimeZoneBrowserProxyImpl} from './timezone_browser_proxy.js';
@@ -38,11 +37,10 @@
         [
           DeepLinkingBehavior,
           PrefsBehavior,
-          RouteObserverBehavior,
         ],
-        I18nMixin(WebUIListenerMixin(PolymerElement))) as {
+        RouteObserverMixin(I18nMixin(WebUIListenerMixin(PolymerElement)))) as {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
-          PrefsBehaviorInterface & RouteObserverBehaviorInterface &
+          PrefsBehaviorInterface & RouteObserverMixinInterface &
           I18nMixinInterface & WebUIListenerMixinInterface,
     };
 
diff --git a/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts b/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
index 01f2e46..0f55cf5 100644
--- a/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/date_time_page/timezone_subpage.ts
@@ -19,11 +19,10 @@
 
 import {SettingsDropdownMenuElement} from '../../controls/settings_dropdown_menu.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {TimeZoneAutoDetectMethod} from './date_time_types.js';
 import {TimeZoneBrowserProxy, TimeZoneBrowserProxyImpl} from './timezone_browser_proxy.js';
@@ -37,17 +36,17 @@
   };
 }
 
-const TimezoneSubpageElementBase = mixinBehaviors(
-                                       [
-                                         DeepLinkingBehavior,
-                                         PrefsBehavior,
-                                         RouteObserverBehavior,
-                                       ],
-                                       WebUIListenerMixin(PolymerElement)) as {
-  new (): PolymerElement & DeepLinkingBehaviorInterface &
-      PrefsBehaviorInterface & RouteObserverBehaviorInterface &
-      WebUIListenerMixinInterface,
-};
+const TimezoneSubpageElementBase =
+    mixinBehaviors(
+        [
+          DeepLinkingBehavior,
+          PrefsBehavior,
+        ],
+        RouteObserverMixin(WebUIListenerMixin(PolymerElement))) as {
+      new (): PolymerElement & DeepLinkingBehaviorInterface &
+          PrefsBehaviorInterface & RouteObserverMixinInterface &
+          WebUIListenerMixinInterface,
+    };
 
 class TimezoneSubpageElement extends TimezoneSubpageElementBase {
   static get is() {
@@ -87,7 +86,7 @@
   }
 
   /**
-   * RouteObserverBehavior
+   * RouteObserverMixin
    * Called when the timezone subpage is hit. Child accounts need parental
    * approval to modify their timezone, this method starts this process on the
    * C++ side, and timezone setting will be disable. Once it is complete the
diff --git a/chrome/browser/resources/settings/chromeos/device_page/device_page.ts b/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
index 1f93fa7..db28856 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/device_page.ts
@@ -24,11 +24,10 @@
 import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {WebUIListenerMixin, WebUIListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Router} from '../../router.js';
+import {RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './device_page.html.js';
 import {DevicePageBrowserProxy, DevicePageBrowserProxyImpl} from './device_page_browser_proxy.js';
@@ -39,12 +38,12 @@
   };
 }
 
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
 const SettingsDevicePageElementBase =
-    mixinBehaviors(
-        [RouteObserverBehavior],
-        I18nMixin(WebUIListenerMixin(PolymerElement))) as {
-      new (): PolymerElement & I18nMixinInterface &
-          WebUIListenerMixinInterface & RouteObserverBehaviorInterface,
+    RouteObserverMixin(I18nMixin(WebUIListenerMixin(PolymerElement))) as {
+      new (): PolymerElement & WebUIListenerMixinInterface &
+          I18nMixinInterface & RouteObserverMixinInterface,
     };
 
 class SettingsDevicePageElement extends SettingsDevicePageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/device_page/pointers.ts b/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
index 6558eabe..47e3ac5 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/pointers.ts
@@ -19,21 +19,19 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './pointers.html.js';
 
-const SettingsPointersElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, PrefsBehavior, RouteObserverBehavior],
-        PolymerElement) as {
-      new (): PolymerElement & DeepLinkingBehaviorInterface &
-          PrefsBehaviorInterface & RouteObserverBehaviorInterface,
-    };
+const SettingsPointersElementBase = mixinBehaviors(
+                                        [DeepLinkingBehavior, PrefsBehavior],
+                                        RouteObserverMixin(PolymerElement)) as {
+  new (): PolymerElement & DeepLinkingBehaviorInterface &
+      PrefsBehaviorInterface & RouteObserverMixinInterface,
+};
 
 class SettingsPointersElement extends SettingsPointersElementBase {
   static get is() {
diff --git a/chrome/browser/resources/settings/chromeos/device_page/stylus.ts b/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
index 8987d02..9495f8f0 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
+++ b/chrome/browser/resources/settings/chromeos/device_page/stylus.ts
@@ -20,12 +20,11 @@
 import {microTask, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {assertExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {DevicePageBrowserProxy, DevicePageBrowserProxyImpl, NoteAppInfo, NoteAppLockScreenSupport} from './device_page_browser_proxy.js';
 import {getTemplate} from './stylus.html.js';
@@ -40,10 +39,10 @@
     'collection/promotion_30023cb_stylus_apps';
 
 const SettingsStylusElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface,
     };
 
 class SettingsStylusElement extends SettingsStylusElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts b/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
index 973e5cd3..9eb716e 100644
--- a/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
+++ b/chrome/browser/resources/settings/chromeos/google_assistant_page/google_assistant_page.ts
@@ -22,13 +22,12 @@
 
 import {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {cast, castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {GoogleAssistantBrowserProxy, GoogleAssistantBrowserProxyImpl} from './google_assistant_browser_proxy.js';
 import {getTemplate} from './google_assistant_page.html.js';
@@ -68,12 +67,11 @@
         [
           DeepLinkingBehavior,
           PrefsBehavior,
-          RouteObserverBehavior,
         ],
-        WebUIListenerMixin(I18nMixin(PolymerElement))) as {
+        RouteObserverMixin(WebUIListenerMixin(I18nMixin(PolymerElement)))) as {
       new (): PolymerElement & I18nMixinInterface &
           WebUIListenerMixinInterface & DeepLinkingBehaviorInterface &
-          PrefsBehaviorInterface & RouteObserverBehaviorInterface,
+          PrefsBehaviorInterface & RouteObserverMixinInterface,
     };
 
 class SettingsGoogleAssistantPageElement extends
diff --git a/chrome/browser/resources/settings/chromeos/icon.js b/chrome/browser/resources/settings/chromeos/icon.js
new file mode 100644
index 0000000..ee53d5e
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/icon.js
@@ -0,0 +1,85 @@
+// 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.
+
+/**
+ * Note: This file is deprecated in favor of the TypeScript version at
+ * ui/webui/resources/js/icon.ts. icon.ts should be used by all TypeScript
+ * files, and can also be used by any JS file that is not using closure
+ * compiler for typechecking.
+ */
+
+/**
+ * @return {!Array<number>} The scale factors supported by this platform for
+ *     webui resources.
+ */
+function getSupportedScaleFactors() {
+  // 1 is supported to match code in ResourceBundle::InitSharedInstance() that
+  // supports SCALE_FACTOR_100P on all non-iOS platforms.
+  // All desktop platforms including Ash support zooming which also updates the
+  // renderer's device scale factors (a.k.a devicePixelRatio), and these
+  // platforms have high DPI assets for 2x.  Let the renderer pick the closest
+  // image for the current device scale factor.
+  return [1, 2];
+}
+
+/**
+ * Generates a CSS url string.
+ * @param {string} s The URL to generate the CSS url for.
+ * @return {string} The CSS url string.
+ */
+export function getUrlForCss(s) {
+  // http://www.w3.org/TR/css3-values/#uris
+  // Parentheses, commas, whitespace characters, single quotes (') and double
+  // quotes (") appearing in a URI must be escaped with a backslash
+  const s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
+  return `url("${s2}")`;
+}
+
+/**
+ * Generates a CSS -webkit-image-set for a chrome:// url.
+ * An entry in the image set is added for each of getSupportedScaleFactors().
+ * The scale-factor-specific url is generated by replacing the first instance
+ * of 'scalefactor' in |path| with the numeric scale factor.
+ *
+ * @param {string} path The URL to generate an image set for.
+ *     'scalefactor' should be a substring of |path|.
+ * @return {string} The CSS -webkit-image-set.
+ */
+function getImageSet(path) {
+  const supportedScaleFactors = getSupportedScaleFactors();
+
+  const replaceStartIndex = path.indexOf('SCALEFACTOR');
+  if (replaceStartIndex < 0) {
+    return getUrlForCss(path);
+  }
+
+  let s = '';
+  for (let i = 0; i < supportedScaleFactors.length; ++i) {
+    const scaleFactor = supportedScaleFactors[i];
+    const pathWithScaleFactor = path.substr(0, replaceStartIndex) +
+        scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
+
+    s += getUrlForCss(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
+
+    if (i !== supportedScaleFactors.length - 1) {
+      s += ', ';
+    }
+  }
+  return '-webkit-image-set(' + s + ')';
+}
+
+/**
+ * Returns the URL of the image, or an image set of URLs for the provided
+ * path.  Resources in chrome://theme have multiple supported scale factors.
+ *
+ * @param {string} path The path of the image.
+ * @return {string} The url, or an image set of URLs.
+ */
+export function getImage(path) {
+  const chromeThemePath = 'chrome://theme';
+  const isChromeThemeUrl =
+      (path.slice(0, chromeThemePath.length) === chromeThemePath);
+  return isChromeThemeUrl ? getImageSet(path + '@SCALEFACTORx') :
+                            getUrlForCss(path);
+}
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/kerberos_page/BUILD.gn
index bd13cbd..8bb804f 100644
--- a/chrome/browser/resources/settings/chromeos/kerberos_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/kerberos_page/BUILD.gn
@@ -21,6 +21,7 @@
   deps = [
     ":kerberos_accounts_browser_proxy",
     "..:deep_linking_behavior",
+    "..:icon",
     "..:metrics_recorder",
     "..:os_route",
     "..:route_observer_behavior",
@@ -30,7 +31,6 @@
     "//ash/webui/common/resources:web_ui_listener_behavior",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js:icon",
   ]
 
   externs_list = [
diff --git a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
index 767cf48..1e4ea58 100644
--- a/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
+++ b/chrome/browser/resources/settings/chromeos/kerberos_page/kerberos_accounts.js
@@ -19,7 +19,6 @@
 import './kerberos_add_account_dialog.js';
 
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
-import {getImage} from 'chrome://resources/js/icon.js';
 import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/ash/common/web_ui_listener_behavior.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -27,6 +26,7 @@
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {Route, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
+import {getImage} from '../icon.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {Account} from '../os_people_page/account_manager_browser_proxy.js';
 import {routes} from '../os_route.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
index 6297a7b..a6d4165b 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.ts
@@ -25,12 +25,11 @@
 
 import {loadTimeData} from '../../i18n_setup.js';
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {AboutPageBrowserProxy, AboutPageBrowserProxyImpl, browserChannelToI18nId, ChannelInfo, VersionInfo} from './about_page_browser_proxy.js';
 import {getTemplate} from './detailed_build_info.html.js';
@@ -48,12 +47,11 @@
         [
           DeepLinkingBehavior,
           PrefsBehavior,
-          RouteObserverBehavior,
         ],
-        I18nMixin(WebUIListenerMixin(PolymerElement))) as {
+        RouteObserverMixin(I18nMixin(WebUIListenerMixin(PolymerElement)))) as {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
           WebUIListenerMixinInterface & I18nMixinInterface &
-          PrefsBehaviorInterface & RouteObserverBehaviorInterface,
+          PrefsBehaviorInterface & RouteObserverMixinInterface,
     };
 
 class SettingsDetailedBuildInfoElement extends SettingsDetailedBuildInfoBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
index 0643230..243b19e0 100644
--- a/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.ts
@@ -16,18 +16,17 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_files_page.html.js';
 
 const OsSettingsFilesPageElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
-      new (): DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface &
-          PolymerElement,
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
+      new (): PolymerElement & DeepLinkingBehaviorInterface &
+          RouteObserverMixinInterface,
     };
 
 class OsSettingsFilesPageElement extends OsSettingsFilesPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
index 7b5a618..9202a6e 100644
--- a/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.ts
@@ -11,18 +11,18 @@
 import '../../settings_shared.css.js';
 import '../../settings_vars.css.js';
 
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './smb_shares_page.html.js';
 
-const SettingsSmbSharesPageElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const SettingsSmbSharesPageElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class SettingsSmbSharesPageElement extends SettingsSmbSharesPageElementBase {
   static get is() {
@@ -51,7 +51,7 @@
   private showAddSmbDialog_: boolean;
 
   /**
-   * Overridden from RouteObserverBehavior.
+   * Overridden from RouteObserverMixin.
    */
   override currentRouteChanged(route: Route) {
     if (route === routes.SMB_SHARES) {
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
index 944d364..6429132 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/BUILD.gn
@@ -36,6 +36,7 @@
   deps = [
     ":account_manager_browser_proxy",
     "..:deep_linking_behavior",
+    "..:icon",
     "..:metrics_recorder",
     "..:os_route",
     "..:route_observer_behavior",
@@ -44,7 +45,6 @@
     "//ash/webui/common/resources:web_ui_listener_behavior",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js:icon",
   ]
 
   externs_list = [
@@ -128,6 +128,7 @@
     ":lock_state_behavior",
     ":os_sync_controls",
     "..:deep_linking_behavior",
+    "..:icon",
     "..:os_page_visibility",
     "..:os_route",
     "..:route_observer_behavior",
@@ -139,7 +140,6 @@
     "//ash/webui/common/resources/quick_unlock:lock_screen_constants",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:assert",
-    "//ui/webui/resources/js:icon",
     "//ui/webui/resources/js:load_time_data.m",
   ]
   externs_list =
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
index 53c5a53..5443be0 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
@@ -18,7 +18,6 @@
 import '../../settings_shared.css.js';
 
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js';
-import {getImage} from 'chrome://resources/js/icon.js';
 import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/ash/common/web_ui_listener_behavior.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -26,6 +25,7 @@
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
 import {Route} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
+import {getImage} from '../icon.js';
 import {recordSettingChange} from '../metrics_recorder.js';
 import {routes} from '../os_route.js';
 import {ParentalControlsBrowserProxy, ParentalControlsBrowserProxyImpl} from '../parental_controls_page/parental_controls_browser_proxy.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
index 1d46ef6..30a3096 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/os_people_page.js
@@ -33,7 +33,6 @@
 import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/ash/common/web_ui_listener_behavior.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
-import {getImage} from 'chrome://resources/js/icon.js';
 import {afterNextRender, flush, html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
@@ -42,6 +41,7 @@
 import {SyncBrowserProxyImpl} from '../../people_page/sync_browser_proxy.js';
 import {Route, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
+import {getImage} from '../icon.js';
 import {OSPageVisibility} from '../os_page_visibility.js';
 import {routes} from '../os_route.js';
 import {SettingsParentalControlsPageElement} from '../parental_controls_page/parental_controls_page.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
index d6248cf..46042da 100644
--- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_page.ts
@@ -16,10 +16,9 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_reset_page.html.js';
 
@@ -30,10 +29,10 @@
 }
 
 const OsSettingsResetPageElementBase =
-    mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior], PolymerElement) as {
+    mixinBehaviors([DeepLinkingBehavior], RouteObserverMixin(PolymerElement)) as
+    {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface,
     };
 
 class OsSettingsResetPageElement extends OsSettingsResetPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
index 4470b02..b06f9569 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.ts
@@ -27,19 +27,18 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_search_page.html.js';
 
 const OsSettingsSearchPageElementBase =
     mixinBehaviors(
-        [DeepLinkingBehavior, RouteObserverBehavior],
-        I18nMixin(PolymerElement)) as {
+        [DeepLinkingBehavior], RouteObserverMixin(I18nMixin(PolymerElement))) as
+    {
       new (): PolymerElement & I18nMixinInterface &
-          DeepLinkingBehaviorInterface & RouteObserverBehaviorInterface,
+          DeepLinkingBehaviorInterface & RouteObserverMixinInterface,
     };
 
 class OsSettingsSearchPageElement extends OsSettingsSearchPageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts b/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
index 414753e8..edef082 100644
--- a/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
+++ b/chrome/browser/resources/settings/chromeos/os_search_page/search_subpage.ts
@@ -25,22 +25,21 @@
 import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {Setting} from '../../mojom-webui/setting.mojom-webui.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js';
 import {routes} from '../os_route.js';
 import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './search_subpage.html.js';
 
 const SettingsSearchSubpageElementBase =
     mixinBehaviors(
-        [DeepLinkingBehavior, PrefsBehavior, RouteObserverBehavior],
-        I18nMixin(PolymerElement)) as {
+        [DeepLinkingBehavior, PrefsBehavior],
+        RouteObserverMixin(I18nMixin(PolymerElement))) as {
       new (): PolymerElement & DeepLinkingBehaviorInterface &
           I18nMixinInterface & PrefsBehaviorInterface &
-          RouteObserverBehaviorInterface,
+          RouteObserverMixinInterface,
     };
 
 class SettingsSearchSubpageElement extends SettingsSearchSubpageElementBase {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni
index 1ad40de8f..dc1b84c 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.gni
+++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -137,6 +137,7 @@
   "chromeos/global_scroll_target_behavior.js",
   "chromeos/google_assistant_page/google_assistant_browser_proxy.ts",
   "chromeos/guest_os/guest_os_browser_proxy.js",
+  "chromeos/icon.js",
   "chromeos/internet_page/cellular_setup_settings_delegate.js",
   "chromeos/internet_page/internet_page_browser_proxy.js",
   "chromeos/kerberos_page/kerberos_accounts_browser_proxy.js",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
index f372cc33..7341116 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.ts
@@ -17,14 +17,13 @@
 import '../../settings_shared.css.js';
 import '../../settings_vars.css.js';
 
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {assertExists} from '../assert_extras.js';
 import {OSPageVisibility} from '../os_page_visibility.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_main.html.js';
 
@@ -39,10 +38,11 @@
   };
 }
 
-const OsSettingsMainElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const OsSettingsMainElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class OsSettingsMainElement extends OsSettingsMainElementBase {
   static get is() {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
index 385b0edc..457a6ef 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.ts
@@ -17,12 +17,11 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
 import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
-import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {routes} from '../os_route.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_menu.html.js';
 
@@ -34,10 +33,11 @@
   };
 }
 
-const OsSettingsMenuElementBase =
-    mixinBehaviors([RouteObserverBehavior], PolymerElement) as {
-      new (): PolymerElement & RouteObserverBehaviorInterface,
-    };
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
+const OsSettingsMenuElementBase = RouteObserverMixin(PolymerElement) as {
+  new (): PolymerElement & RouteObserverMixinInterface,
+};
 
 class OsSettingsMenuElement extends OsSettingsMenuElementBase {
   static get is() {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
index 8ab15d404..ceae6a7 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.ts
@@ -22,23 +22,22 @@
 import '../../prefs/prefs.js';
 import '../../settings_vars.css.js';
 
-import {CrContainerShadowBehavior} from 'chrome://resources/ash/common/cr_container_shadow_behavior.js';
+import {CrContainerShadowMixin, CrContainerShadowMixinInterface} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js';
 import {CrDrawerElement} from 'chrome://resources/cr_elements/cr_drawer/cr_drawer.js';
 import {FindShortcutMixin, FindShortcutMixinInterface} from 'chrome://resources/cr_elements/find_shortcut_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 import {listenOnce} from 'chrome://resources/js/util.js';
-import {Debouncer, DomIf, microTask, mixinBehaviors, PolymerElement, timeOut} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {Debouncer, DomIf, microTask, PolymerElement, timeOut} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../../i18n_setup.js';
 import {SettingsPrefsElement} from '../../prefs/prefs.js';
-import {Route, Router} from '../../router.js';
+import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../../router.js';
 import {castExists} from '../assert_extras.js';
 import {setGlobalScrollTarget} from '../global_scroll_target_behavior.js';
 import {recordClick, recordNavigation, recordPageBlur, recordPageFocus, recordSettingChange} from '../metrics_recorder.js';
 import {OSPageVisibility, osPageVisibility} from '../os_page_visibility.js';
 import {OsToolbarElement} from '../os_toolbar/os_toolbar.js';
 import {PrefToSettingMetricConverter} from '../pref_to_setting_metric_converter.js';
-import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js';
 
 import {getTemplate} from './os_settings_ui.html.js';
 
@@ -72,17 +71,16 @@
   };
 }
 
+// TODO(crbug/1315757) Remove need to typecast and intersect mixin interfaces
+// once RouteObserverMixin is converted to TS
 const OsSettingsUiElementBase =
-    mixinBehaviors(
-        [
-          CrContainerShadowBehavior,
-          // Calls currentRouteChanged() in attached(),so ensure other behaviors
-          // run their attached() first.
-          RouteObserverBehavior,
-        ],
-        FindShortcutMixin(PolymerElement)) as {
-      new (): PolymerElement & CrContainerShadowBehavior &
-          FindShortcutMixinInterface & RouteObserverBehaviorInterface,
+    // RouteObserverMixin calls currentRouteChanged() in
+    // connectedCallback(), so ensure other mixins/behaviors run their
+    // connectedCallback() first.
+    RouteObserverMixin(
+        FindShortcutMixin(CrContainerShadowMixin(PolymerElement))) as {
+      new (): PolymerElement & FindShortcutMixinInterface &
+          CrContainerShadowMixinInterface & RouteObserverMixinInterface,
     };
 
 class OsSettingsUiElement extends OsSettingsUiElementBase {
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 28124e1a..bfda629 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -82,6 +82,10 @@
     }
 
     const element = document.createElement(htmlTag);
+    const direction = chrome.readAnything.getTextDirection(nodeId);
+    if (direction) {
+      element.setAttribute('dir', direction);
+    }
     const url = chrome.readAnything.getUrl(nodeId);
     if (url) {
       element.setAttribute('href', url);
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
index 7a8d604a..04ae40a 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
@@ -38,6 +38,9 @@
     // the selected text.
     function getTextContent(nodeId: number): string;
 
+    // Returns the text direction of the AXNode for the provided AXNodeID.
+    function getTextDirection(nodeId: number): string;
+
     // Returns the url of the AXNode for the provided AXNodeID.
     function getUrl(nodeId: number): string;
 
diff --git a/chrome/browser/resources/tab_strip/drag_manager.ts b/chrome/browser/resources/tab_strip/drag_manager.ts
index 05d7e6e9..06c2ae71 100644
--- a/chrome/browser/resources/tab_strip/drag_manager.ts
+++ b/chrome/browser/resources/tab_strip/drag_manager.ts
@@ -69,7 +69,7 @@
 
   placeTabGroupElement(element: TabGroupElement, index: number): void;
 
-  shouldPreventDrag(): boolean;
+  shouldPreventDrag(isDraggingTab: boolean): boolean;
 }
 
 type DragManagerDelegateElement = DragManagerDelegate&HTMLElement;
@@ -470,7 +470,7 @@
       return;
     }
 
-    if (this.delegate_.shouldPreventDrag()) {
+    if (this.delegate_.shouldPreventDrag(isTabElement(draggedItem))) {
       event.preventDefault();
       return;
     }
diff --git a/chrome/browser/resources/tab_strip/tab_list.ts b/chrome/browser/resources/tab_strip/tab_list.ts
index 7909f39..4b9ce7b 100644
--- a/chrome/browser/resources/tab_strip/tab_list.ts
+++ b/chrome/browser/resources/tab_strip/tab_list.ts
@@ -778,12 +778,17 @@
     this.animateScrollPosition_(scrollBy);
   }
 
-  shouldPreventDrag(): boolean {
-    // Do not allow dragging if there's only 1 tab with no tab group, or only 1
-    // tab group with no other tabs outside of the tab group.
-    return (this.pinnedTabsElement_.childElementCount +
-        this.unpinnedTabsElement_.childElementCount) ===
-        1;
+  shouldPreventDrag(isDraggingTab: boolean): boolean {
+    if (isDraggingTab) {
+      // Do not allow dragging a tab if there's only 1 tab.
+      return this.$all('tabstrip-tab').length === 1;
+    } else {
+      // Do not allow dragging the tab group with no others outside of the tab
+      // group. In this case there is only 1 pinned and unpinned top level
+      // element, which is the dragging tab group itself.
+      return (this.pinnedTabsElement_.childElementCount +
+              this.unpinnedTabsElement_.childElementCount) === 1;
+    }
   }
 
   private tabThumbnailUpdated_(tabId: number, imgData: string) {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 1a5bd4b..0c9daa6 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -962,6 +962,26 @@
     EXPECT_EQ("token2", reuse_lookup.verdict_token()) << t;
     t++;
   }
+
+  {
+    auto response = std::make_unique<LoginReputationClientResponse>();
+    response->set_verdict_token("token3");
+    response->set_verdict_type(LoginReputationClientResponse::PHISHING);
+    service_->MaybeLogPasswordReuseLookupEvent(
+        web_contents(), RequestOutcome::RESPONSE_ALREADY_CACHED,
+        PasswordType::PRIMARY_ACCOUNT_PASSWORD, response.get());
+    ASSERT_EQ(t + 1, GetUserEventService()->GetRecordedUserEvents().size())
+        << t;
+    PasswordReuseLookup reuse_lookup = GetUserEventService()
+                                           ->GetRecordedUserEvents()[t]
+                                           .gaia_password_reuse_event()
+                                           .reuse_lookup();
+    EXPECT_EQ(PasswordReuseLookup::CACHE_HIT, reuse_lookup.lookup_result())
+        << t;
+    EXPECT_EQ(PasswordReuseLookup::PHISHING, reuse_lookup.verdict()) << t;
+    EXPECT_EQ("token3", reuse_lookup.verdict_token()) << t;
+    t++;
+  }
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetDefaultChangePasswordURL) {
diff --git a/chrome/browser/segmentation_platform/segmentation_platform_config_unittest.cc b/chrome/browser/segmentation_platform/segmentation_platform_config_unittest.cc
index 981be8bf..d08dece 100644
--- a/chrome/browser/segmentation_platform/segmentation_platform_config_unittest.cc
+++ b/chrome/browser/segmentation_platform/segmentation_platform_config_unittest.cc
@@ -17,27 +17,14 @@
 
 namespace segmentation_platform {
 
-using ::base::test::ScopedFeatureList;
-
 class SegmentationPlatformConfigTest : public testing::Test {
  public:
   SegmentationPlatformConfigTest() = default;
   ~SegmentationPlatformConfigTest() override = default;
 
-  void SetUp() override {
-    Test::SetUp();
-    scoped_feature_list_ = std::make_unique<ScopedFeatureList>();
-  }
-
-  void TearDown() override {
-    Test::TearDown();
-    scoped_feature_list_.reset();
-  }
-
   void EnableFeaturesWithParams(
-      const std::vector<ScopedFeatureList::FeatureAndParams>&
-          enabled_features) {
-    scoped_feature_list_->InitWithFeaturesAndParameters(enabled_features, {});
+      const std::vector<base::test::FeatureRefAndParams>& enabled_features) {
+    scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
     // Activate each field trial so that these trials are considered as Active
     // groups. the FieldTrialList currently does not consider force enabled
     // trials as "active" by default.
@@ -51,7 +38,7 @@
   }
 
  protected:
-  std::unique_ptr<ScopedFeatureList> scoped_feature_list_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(SegmentationPlatformConfigTest, GetSegmentationPlatformConfig) {
@@ -63,15 +50,14 @@
 }
 
 TEST_F(SegmentationPlatformConfigTest, EmptyFeatures) {
-  ScopedFeatureList scoped_feature_list_;
   std::vector<std::unique_ptr<Config>> configs;
   AppendConfigsFromExperiments(configs);
   EXPECT_TRUE(configs.empty());
 }
 
 TEST_F(SegmentationPlatformConfigTest, BadFormat) {
-  std::vector<ScopedFeatureList::FeatureAndParams> features;
-  features.push_back(ScopedFeatureList::FeatureAndParams(
+  std::vector<base::test::FeatureRefAndParams> features;
+  features.push_back(base::test::FeatureRefAndParams(
       features::kSegmentationPlatformLowEngagementFeature,
       {{"segmentation_platform_add_config_param", "bad_json"}}));
   EnableFeaturesWithParams(features);
@@ -119,14 +105,14 @@
       proto::SegmentId::
           OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS};
 
-  std::vector<ScopedFeatureList::FeatureAndParams> features;
-  features.push_back(ScopedFeatureList::FeatureAndParams(
+  std::vector<base::test::FeatureRefAndParams> features;
+  features.push_back(base::test::FeatureRefAndParams(
       features::kSegmentationPlatformLowEngagementFeature,
       {{"segmentation_platform_add_config_param", "bad_json"}}));
-  features.push_back(ScopedFeatureList::FeatureAndParams(
+  features.push_back(base::test::FeatureRefAndParams(
       features::kSegmentationPlatformFeedSegmentFeature,
       {{"segmentation_platform_add_config_param", kValidConfig1}}));
-  features.push_back(ScopedFeatureList::FeatureAndParams(
+  features.push_back(base::test::FeatureRefAndParams(
       features::kShoppingUserSegmentFeature,
       {{"segmentation_platform_add_config_param", kValidConfig2}}));
   EnableFeaturesWithParams(features);
diff --git a/chrome/browser/sessions/DEPS b/chrome/browser/sessions/DEPS
index ee77d5b..7878abe 100644
--- a/chrome/browser/sessions/DEPS
+++ b/chrome/browser/sessions/DEPS
@@ -8,8 +8,4 @@
     # Tests may depend upon views.
     "+chrome/browser/ui/views",
   ],
-  "session_restore\.cc": [
-    "+ash/shell.h",
-    "+ash/metrics/login_unlock_throughput_recorder.h",
-  ],
 }
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index f49871b..f71a402e 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -92,11 +92,7 @@
 #include "extensions/common/extension_set.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/metrics/login_unlock_throughput_recorder.h"
-#include "ash/shell.h"
 #include "chrome/browser/ash/boot_times_recorder.h"
-#include "components/app_restore/window_properties.h"
-#include "ui/compositor/layer.h"
 #endif
 
 using content::NavigationController;
@@ -118,50 +114,6 @@
 // Pointers to SessionRestoreImpls which are currently restoring the session.
 std::set<SessionRestoreImpl*>* active_session_restorers = nullptr;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-void StartRecordingRestoredWindowsMetrics(
-    const std::vector<std::unique_ptr<sessions::SessionWindow>>& windows) {
-  // Ash is not always initialized in unit tests.
-  if (!ash::Shell::HasInstance())
-    return;
-
-  ash::LoginUnlockThroughputRecorder* throughput_recorder =
-      ash::Shell::Get()->login_unlock_throughput_recorder();
-
-  for (const auto& w : windows) {
-    if (w->type == sessions::SessionWindow::TYPE_NORMAL) {
-      throughput_recorder->AddScheduledRestoreWindow(
-          w->window_id.id(), w->app_name,
-          ash::LoginUnlockThroughputRecorder::kBrowser);
-    }
-  }
-}
-
-void ReportRestoredWindowCreated(aura::Window* window) {
-  // Ash is not always initialized in unit tests.
-  if (!ash::Shell::HasInstance())
-    return;
-
-  const int32_t restore_window_id =
-      window->GetProperty(app_restore::kRestoreWindowIdKey);
-
-  // Restored window IDs are always non-zero.
-  if (restore_window_id == 0)
-    return;
-
-  ash::LoginUnlockThroughputRecorder* throughput_recorder =
-      ash::Shell::Get()->login_unlock_throughput_recorder();
-  throughput_recorder->OnRestoredWindowCreated(restore_window_id);
-  aura::Window* root_window = window->GetRootWindow();
-  if (root_window) {
-    ui::Compositor* compositor = root_window->layer()->GetCompositor();
-    throughput_recorder->OnBeforeRestoredWindowShown(restore_window_id,
-                                                     compositor);
-  }
-}
-
-#endif
-
 }  // namespace
 
 // SessionRestoreImpl ---------------------------------------------------------
@@ -463,11 +415,6 @@
     if (!read_error_)
       read_error_ = read_error;
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    if (!read_error_)
-      StartRecordingRestoredWindowsMetrics(windows);
-#endif
-
     // Copy windows into windows_ so that we can combine both app and browser
     // windows together before doing a one-pass restore.
     std::copy(std::make_move_iterator(windows.begin()),
@@ -629,7 +576,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
         ash::BootTimesRecorder::Get()->AddLoginTimeMarker(
             "SessionRestore-CreateRestoredBrowser-End", false);
-        ReportRestoredWindowCreated(browser->window()->GetNativeWindow());
 #endif
       }
 
diff --git a/chrome/browser/site_isolation/isolated_sandboxed_iframe_browsertest.cc b/chrome/browser/site_isolation/isolated_sandboxed_iframe_browsertest.cc
index ceb6f0c..9244c679 100644
--- a/chrome/browser/site_isolation/isolated_sandboxed_iframe_browsertest.cc
+++ b/chrome/browser/site_isolation/isolated_sandboxed_iframe_browsertest.cc
@@ -20,6 +20,7 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/blink/public/common/features.h"
 #include "url/gurl.h"
 
 class TestMemoryDetails : public MetricsMemoryDetails {
@@ -75,13 +76,13 @@
     // BrowsingInstances.
     if (enable_isolate_sandboxed_iframes_) {
       feature_list_.InitWithFeatures(
-          /* enable_features */ {features::kIsolateSandboxedIframes,
+          /* enable_features */ {blink::features::kIsolateSandboxedIframes,
                                  features::kDisableProcessReuse},
           /* disable_features */ {features::kSpareRendererForSitePerProcess});
     } else {
       feature_list_.InitWithFeatures(
           /* enable_features */ {features::kDisableProcessReuse},
-          /* disable_features */ {features::kIsolateSandboxedIframes,
+          /* disable_features */ {blink::features::kIsolateSandboxedIframes,
                                   features::kSpareRendererForSitePerProcess});
     }
   }
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc
index 7e22ca7b..33714acf 100644
--- a/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -84,7 +84,7 @@
 
   // Returns the collection of default datatypes.
   syncer::ModelTypeSet DefaultDatatypes() {
-    static_assert(42 == syncer::GetNumModelTypes(),
+    static_assert(43 == syncer::GetNumModelTypes(),
                   "When adding a new type, you probably want to add it here as "
                   "well (assuming it is already enabled).");
 
@@ -96,6 +96,9 @@
     // ChromeSyncClient types.
     datatypes.Put(syncer::READING_LIST);
     datatypes.Put(syncer::SECURITY_EVENTS);
+    if (base::FeatureList::IsEnabled(syncer::kSyncSegmentationDataType)) {
+      datatypes.Put(syncer::SEGMENTATION);
+    }
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
     datatypes.Put(syncer::SUPERVISED_USER_SETTINGS);
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index b943f862..01bc140d 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -28,7 +28,7 @@
 namespace {
 
 syncer::ModelTypeSet AllowedTypesInStandaloneTransportMode() {
-  static_assert(42 == syncer::GetNumModelTypes(),
+  static_assert(43 == syncer::GetNumModelTypes(),
                 "Add new types below if they run in transport mode");
   // Only some special allowlisted types (and control types) are allowed in
   // standalone transport mode.
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
index 5770f64..be61137 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
+++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
@@ -171,6 +171,11 @@
             TextView passwordText = view.findViewById(R.id.password);
             passwordText.setText(credential.getPassword());
             passwordText.setTransformationMethod(new PasswordTransformationMethod());
+
+            String contentDescription = view.getContext().getString(
+                    R.string.touch_to_fill_password_credential_accessibility_description,
+                    credential.getFormattedUsername());
+            view.setContentDescription(contentDescription);
         } else if (propertyKey == SHOW_SUBMIT_BUTTON) {
             // Whether Touch To Fill should auto-submit a form doesn't affect the credentials list.
         } else {
@@ -202,6 +207,10 @@
             usernameText.setText(credential.getUsername());
             TextView descriptionText = view.findViewById(R.id.webauthn_credential_context);
             descriptionText.setText(R.string.touch_to_fill_sheet_webauthn_credential_context);
+            String contentDescription = view.getContext().getString(
+                    R.string.touch_to_fill_passkey_credential_accessibility_description,
+                    credential.getUsername());
+            view.setContentDescription(contentDescription);
         } else if (propertyKey == SHOW_WEBAUTHN_SUBMIT_BUTTON) {
             // Ignore.
         } else {
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
index 7de9939f..654e3a8 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
@@ -232,6 +232,12 @@
       <message name="IDS_TOUCH_TO_FILL_SHEET_WEBAUTHN_CREDENTIAL_CONTEXT" desc="Context string for second line of a Passkey on the Touch To Fill sheet, beneath the username.">
         Use your screen lock
       </message>
+      <message name="IDS_TOUCH_TO_FILL_PASSWORD_CREDENTIAL_ACCESSIBILITY_DESCRIPTION" desc="Content description for a password credential item on the sheet list. This is not visually displayed, but is audibly read by screen readers for accessibility purposes.">
+        Password for <ph name="USERNAME">%1$s<ex>John.Doe@example.com</ex></ph>.
+      </message>
+      <message name="IDS_TOUCH_TO_FILL_PASSKEY_CREDENTIAL_ACCESSIBILITY_DESCRIPTION" desc="Content description for a passkey credential item on the sheet list. This is not visually displayed, but is audibly read by screen readers for accessibility purposes.">
+        Passkey for <ph name="USERNAME">%1$s<ex>John.Doe@example.com</ex></ph>, use your screen lock.
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSKEY_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSKEY_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..4cac228
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSKEY_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+dfa6a8d96285248a2f2ffd64dc81dfd446a411d3
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSWORD_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSWORD_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..05e94f0
--- /dev/null
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_PASSWORD_CREDENTIAL_ACCESSIBILITY_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+ebf05b0512c6da1827e834248575e35ef980c870
\ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
index c8c9dce..b4fb53259 100644
--- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
+++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -6,6 +6,7 @@
 
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -26,6 +27,7 @@
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ON_CLICK_MANAGE;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.VISIBLE;
+import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.WebAuthnCredentialProperties.WEBAUTHN_CREDENTIAL;
 
 import static java.util.Arrays.asList;
 
@@ -53,6 +55,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties;
 import org.chromium.chrome.browser.touch_to_fill.data.Credential;
+import org.chromium.chrome.browser.touch_to_fill.data.WebAuthnCredential;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
@@ -81,6 +84,7 @@
             new Credential("", "***", "No Username", "m.example.xyz", true, false, 0);
     private static final Credential BOB =
             new Credential("Bob", "***", "Bob", "mobile.example.xyz", true, false, 0);
+    private static final WebAuthnCredential CAM = new WebAuthnCredential("Cam", "12345");
     private static final Credential NIK =
             new Credential("Nik", "***", "Nik", "group.xyz", false, true, 0);
 
@@ -435,6 +439,41 @@
         verify(mDismissHandler).onResult(BottomSheetController.StateChangeReason.NONE);
     }
 
+    @Test
+    @MediumTest
+    public void testPasswordCredentialAccessibilityDescription() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.get(SHEET_ITEMS).addAll(Collections.singletonList(buildCredentialItem(ANA)));
+            mModel.set(VISIBLE, true);
+        });
+
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertNotNull(getCredentials().getChildAt(0));
+        assertEquals(getCredentials().getChildAt(0).getContentDescription(),
+                getActivity().getString(
+                        R.string.touch_to_fill_password_credential_accessibility_description,
+                        ANA.getFormattedUsername()));
+    }
+
+    @Test
+    @MediumTest
+    public void testPasskeyCredentialAccessibilityDescription() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mModel.get(SHEET_ITEMS)
+                    .addAll(Collections.singletonList(buildWebAuthnCredentialItem(CAM)));
+            mModel.set(VISIBLE, true);
+        });
+
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertNotNull(getCredentials().getChildAt(0));
+        assertEquals(getCredentials().getChildAt(0).getContentDescription(),
+                getActivity().getString(
+                        R.string.touch_to_fill_passkey_credential_accessibility_description,
+                        CAM.getUsername()));
+    }
+
     private ChromeActivity getActivity() {
         return mActivityTestRule.getActivity();
     }
@@ -469,6 +508,14 @@
                 TouchToFillProperties.ItemType.CREDENTIAL, credential, mCredentialCallback, false);
     }
 
+    private MVCListAdapter.ListItem buildWebAuthnCredentialItem(WebAuthnCredential credential) {
+        return new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.WEBAUTHN_CREDENTIAL,
+                new PropertyModel
+                        .Builder(TouchToFillProperties.WebAuthnCredentialProperties.ALL_KEYS)
+                        .with(WEBAUTHN_CREDENTIAL, credential)
+                        .build());
+    }
+
     private MVCListAdapter.ListItem buildConfirmationButton(
             Credential credential, boolean showSubmitButton) {
         return buildSheetItem(TouchToFillProperties.ItemType.FILL_BUTTON, credential,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4a3990d..9ed442c5 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1762,6 +1762,13 @@
       ]
     }
 
+    if (toolkit_views && is_chrome_branded) {
+      sources += [
+        "webui/lens/lens_ui.cc",
+        "webui/lens/lens_ui.h",
+      ]
+    }
+
     deps += [
       "//base",
       "//build:chromeos_buildflags",
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/optional_button_layout.xml b/chrome/browser/ui/android/toolbar/java/res/layout/optional_button_layout.xml
index 8337c5de..14606bf 100644
--- a/chrome/browser/ui/android/toolbar/java/res/layout/optional_button_layout.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/layout/optional_button_layout.xml
@@ -35,6 +35,8 @@
         android:layout_marginStart="40dp"
         android:gravity="center"
         android:visibility="gone"
+        android:maxLines="1"
+        android:ellipsize="end"
         android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
     <org.chromium.ui.widget.ChromeImageView
         android:layout_width="40dp"
diff --git a/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
index 4471383..1a3aa3c 100644
--- a/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
@@ -19,6 +19,7 @@
 
     <!-- Toolbar Phone - padding of the optional button when menu button is present -->
     <dimen name="toolbar_phone_optional_button_padding">12dp</dimen>
+    <dimen name="toolbar_phone_optional_button_action_chip_max_width">175dp</dimen>
 
     <!-- Home Button Menu dimensions-->
     <dimen name="home_button_list_menu_width">222dp</dimen>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BaseButtonDataProvider.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BaseButtonDataProvider.java
index 5877f91e..c97ed1f 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BaseButtonDataProvider.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/BaseButtonDataProvider.java
@@ -36,6 +36,7 @@
     private ModalDialogManagerObserver mModalDialogObserver;
 
     private boolean mShouldShowOnIncognitoTabs;
+    private @StringRes int mActionChipResourceId;
 
     /**
      * Creates a new instance of {@code BaseButtonDataProvider}.
@@ -122,6 +123,16 @@
         mButtonData.updateIPHCommandBuilder(getIphCommandBuilder(tab));
     }
 
+    private void maybeSetActionChipResourceId() {
+        if (!mButtonData.getButtonSpec().isDynamicAction() || !FeatureList.isInitialized()
+                || !AdaptiveToolbarFeatures.shouldShowActionChip()
+                || mButtonData.getButtonSpec().getActionChipLabelResId() != Resources.ID_NULL) {
+            return;
+        }
+
+        mButtonData.updateActionChipResourceId(mActionChipResourceId);
+    }
+
     /**
      * Sets whether the button should be shown on incognito tabs, default is false.
      */
@@ -130,6 +141,15 @@
     }
 
     /**
+     * Sets a string resource ID to be used when the action chip variant is enabled, only used on
+     * dynamic actions.
+     * @param actionChipResourceId A string resource to use as the action chip label.
+     */
+    protected void setActionChipResourceId(@StringRes int actionChipResourceId) {
+        mActionChipResourceId = actionChipResourceId;
+    }
+
+    /**
      * Gets an {@link IPHCommandBuilder} builder instance to use on this button. Only called when
      * native is initialized and when there's no IPHCommandBuilder set.
      * @param tab Current tab.
@@ -155,6 +175,7 @@
     public ButtonData get(Tab tab) {
         mButtonData.setCanShow(shouldShowButton(tab));
         maybeSetIphCommandBuilder(tab);
+        maybeSetActionChipResourceId();
 
         return mButtonData;
     }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
index e1e8544d..11382b94 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsChecker.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import android.os.Handler;
+
 import androidx.annotation.NonNull;
 
 import org.chromium.base.Callback;
@@ -19,15 +21,19 @@
     private final ViewResourceAdapter mViewResourceAdapter;
     @NonNull
     private final ObservableSupplier<Integer> mConstraintsSupplier;
+    @NonNull
+    private final Handler mHandler;
 
     /**
      * @param viewResourceAdapter The target to notify when a capture is needed.
      * @param constraintsSupplier The underlying supplier for the state of constraints.
+     * @param handler Handler to post deferred tasks to.
      */
     public ConstraintsChecker(@NonNull ViewResourceAdapter viewResourceAdapter,
-            @NonNull ObservableSupplier<Integer> constraintsSupplier) {
+            @NonNull ObservableSupplier<Integer> constraintsSupplier, @NonNull Handler handler) {
         mViewResourceAdapter = viewResourceAdapter;
         mConstraintsSupplier = constraintsSupplier;
+        mHandler = handler;
     }
 
     /**
@@ -53,7 +59,7 @@
     public void onResult(Integer result) {
         if (!areControlsLocked()) {
             mConstraintsSupplier.removeObserver(this);
-            mViewResourceAdapter.onResourceRequested();
+            mHandler.post(() -> mViewResourceAdapter.onResourceRequested());
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
index 673ecf8e..ebaa559 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ConstraintsCheckerTest.java
@@ -5,9 +5,13 @@
 package org.chromium.chrome.browser.toolbar;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.os.Handler;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,13 +34,22 @@
 
     @Mock
     private ViewResourceAdapter mViewResourceAdapter;
+    @Mock
+    private Handler mHandler;
 
     private ObservableSupplierImpl mConstraintsSupplier = new ObservableSupplierImpl();
 
     @Test
     public void testScheduleRequestResourceOnUnlock() {
+        doAnswer((invocation) -> {
+            Runnable runnable = (Runnable) invocation.getArguments()[0];
+            runnable.run();
+            return null;
+        })
+                .when(mHandler)
+                .post(any(Runnable.class));
         ConstraintsChecker constraintsChecker =
-                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier);
+                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier, mHandler);
         constraintsChecker.scheduleRequestResourceOnUnlock();
         mConstraintsSupplier.set(BrowserControlsState.SHOWN);
         verify(mViewResourceAdapter, times(0)).onResourceRequested();
@@ -51,7 +64,7 @@
     @Test
     public void testAreControlsLocked() {
         ConstraintsChecker constraintsChecker =
-                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier);
+                new ConstraintsChecker(mViewResourceAdapter, mConstraintsSupplier, mHandler);
         assertEquals(true, constraintsChecker.areControlsLocked());
 
         mConstraintsSupplier.set(BrowserControlsState.SHOWN);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
index 9651936..32f1b93 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewResourceFrameLayout.java
@@ -8,6 +8,8 @@
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.AttributeSet;
 
 import androidx.annotation.NonNull;
@@ -120,6 +122,7 @@
      */
     public void setConstraintsSupplier(ObservableSupplier<Integer> constraintsSupplier) {
         assert mConstraintsChecker == null;
-        mConstraintsChecker = new ConstraintsChecker(getResourceAdapter(), constraintsSupplier);
+        mConstraintsChecker = new ConstraintsChecker(
+                getResourceAdapter(), constraintsSupplier, new Handler(Looper.getMainLooper()));
     }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java
index 3aefd75..3deb1485 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonView.java
@@ -584,12 +584,16 @@
         mActionChipLabel.setVisibility(VISIBLE);
         mBackground.setVisibility(VISIBLE);
 
-        // TODO(salg): Add a check to avoid expanding too much.
         float actionChipLabelTextWidth =
                 mActionChipLabel.getPaint().measureText(mActionChipLabelString);
 
-        int expandedStateWidthPx =
-                (int) (mCollapsedStateWidthPx + actionChipLabelTextWidth + mExpandedStatePaddingPx);
+        int maxExpandedStateWidthPx = getResources().getDimensionPixelSize(
+                R.dimen.toolbar_phone_optional_button_action_chip_max_width);
+
+        int expandedStateWidthPx = Math.min(
+                (int) (mCollapsedStateWidthPx + actionChipLabelTextWidth + mExpandedStatePaddingPx),
+                maxExpandedStateWidthPx);
+
         setWidth(expandedStateWidthPx);
 
         mState = State.RUNNING_ACTION_CHIP_EXPANSION_TRANSITION;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java
index b81bf609..92a7b1f 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonViewTest.java
@@ -36,6 +36,7 @@
 
 import androidx.appcompat.content.res.AppCompatResources;
 
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -666,4 +667,27 @@
         // visibility many times should begin a new animation.
         verify(mMockBeginDelayedTransition, times(2)).onResult(any());
     }
+
+    @Test
+    public void testUpdateButton_actionChipWidthIsRestricted() {
+        ButtonDataImpl buttonData = getDataForPriceTrackingActionChip();
+        // Set a string that's too long as an action chip label. Real code measures the number of
+        // pixels this will take on screen, but robolectric just uses the character count, so use
+        // any string with more than 150 characters.
+        buttonData.updateActionChipResourceId(R.string.sign_in_managed_account_description);
+
+        int maxActionChipWidth = mOptionalButtonView.getResources().getDimensionPixelSize(
+                R.dimen.toolbar_phone_optional_button_action_chip_max_width);
+
+        ViewGroup transitionRoot = mock(ViewGroup.class);
+        mOptionalButtonView.setTransitionRoot(transitionRoot);
+
+        mOptionalButtonView.updateButtonWithAnimation(buttonData);
+        mOptionalButtonView.onTransitionStart(null);
+        mOptionalButtonView.onTransitionEnd(null);
+
+        // Button shouldn't be wider than the established maximum.
+        Assert.assertThat(mOptionalButtonView.getLayoutParams().width,
+                Matchers.lessThanOrEqualTo(maxActionChipWidth));
+    }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
index 876408f..51308db 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainer.java
@@ -11,6 +11,8 @@
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -237,7 +239,8 @@
 
             assert mConstraintsObserver == null;
             if (constraintsSupplier != null) {
-                mConstraintsObserver = new ConstraintsChecker(this, constraintsSupplier);
+                mConstraintsObserver = new ConstraintsChecker(
+                        this, constraintsSupplier, new Handler(Looper.getMainLooper()));
             }
 
             assert mTabSupplier == null;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
index 955cfc81..c28a563 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarControlContainerTest.java
@@ -18,6 +18,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.UmaRecorderHolder;
@@ -218,6 +219,7 @@
 
         // BOTH should cause a new onResourceRequested call.
         mConstraintsSupplier.set(BrowserControlsState.BOTH);
+        ShadowLooper.idleMainLooper();
         Assert.assertEquals(1, onResourceRequestedCount.get());
 
         // The constraints should no longer block isDirty/captures.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 5c92c4f..d9b5e3ec 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -1522,6 +1522,7 @@
 
     @Override
     public void draw(Canvas canvas) {
+        if (mDestroyChecker.isDestroyed()) return;
         // If capturing a texture of the toolbar, ensure the alpha is set prior to draw(...) being
         // called.  The alpha is being used prior to getting to draw(...), so updating the value
         // after this point was having no affect.
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
index 568ca547..589f64e8 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
@@ -12,7 +12,6 @@
 #include "ash/components/arc/arc_util.h"
 #include "ash/constants/app_types.h"
 #include "ash/constants/ash_pref_names.h"
-#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -130,26 +129,6 @@
   return standard_image;
 }
 
-// Report shelf buttons initialized to LoginUnlockThroughputRecorder.
-void ReportInitShelfIconList(const ash::ShelfModel* model) {
-  // Shell is not always initializaed in tests.
-  if (!ash::Shell::HasInstance())
-    return;
-
-  ash::Shell::Get()->login_unlock_throughput_recorder()->InitShelfIconList(
-      model);
-}
-
-// Report shelf buttons updated to LoginUnlockThroughputRecorder.
-void ReportUpdateShelfIconList(const ash::ShelfModel* model) {
-  // Shell is not always initializaed in tests.
-  if (!ash::Shell::HasInstance())
-    return;
-
-  ash::Shell::Get()->login_unlock_throughput_recorder()->UpdateShelfIconList(
-      model);
-}
-
 }  // namespace
 
 // A class to get events from ChromeOS when a user gets changed or added.
@@ -337,7 +316,6 @@
   if (browser_status_monitor_) {
     browser_status_monitor_->Initialize();
   }
-  ReportInitShelfIconList(model_);
 }
 
 ash::ShelfID ChromeShelfController::CreateAppItem(
@@ -487,8 +465,6 @@
             new_item.id.app_id, image);
     model_->Set(model_->ItemIndexByID(shelf_id), new_item);
   }
-
-  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::UpdateItemImage(const std::string& app_id) {
@@ -711,7 +687,6 @@
         model_->GetItemIndexForType(ash::TYPE_UNPINNED_BROWSER_SHORTCUT);
     if (item_index >= 0) {
       model_->RemoveItemAt(item_index);
-      ReportUpdateShelfIconList(model_);
       return;
     }
   }
@@ -737,8 +712,6 @@
 
   browser_item.status = browser_status;
   model_->Set(browser_index, browser_item);
-
-  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::SetShelfIDForBrowserWindowContents(
@@ -823,8 +796,6 @@
   model_->RemoveItemAt(index);
   model_->AddAt(index, item,
                 std::make_unique<AppShortcutShelfItemController>(item.id));
-
-  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::PinAppAtIndex(const std::string& app_id,
@@ -839,8 +810,6 @@
 
   model_->AddAt(target_index, item,
                 std::make_unique<AppShortcutShelfItemController>(item.id));
-
-  ReportUpdateShelfIconList(model_);
 }
 
 int ChromeShelfController::PinnedItemIndexByAppID(const std::string& app_id) {
@@ -1131,8 +1100,6 @@
     model_->Set(index, item);
     // It's possible we're waiting on more than one item, so don't break.
   }
-
-  ReportUpdateShelfIconList(model_);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1174,8 +1141,6 @@
   const int index = model_->ItemIndexByID(id);
   if (index >= 0 && index < model_->item_count())
     model_->RemoveItemAt(index);
-
-  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::PinRunningAppInternal(
@@ -1308,8 +1273,6 @@
   }
 
   UpdatePolicyPinnedAppsFromPrefs();
-
-  ReportUpdateShelfIconList(model_);
 }
 
 bool ChromeShelfController::EnsureAppPinnedInModelAtIndex(
@@ -1367,8 +1330,6 @@
     item.pinned_by_policy = pinned_by_policy;
     model_->Set(model_index, item);
   }
-
-  ReportUpdateShelfIconList(model_);
 }
 
 ash::ShelfItemStatus ChromeShelfController::GetAppState(
@@ -1412,8 +1373,6 @@
   item.app_status = ShelfControllerHelper::GetAppStatus(
       latest_active_profile_, item_delegate->shelf_id().app_id);
   model_->AddAt(index, item, std::move(item_delegate));
-
-  ReportUpdateShelfIconList(model_);
   return item.id;
 }
 
@@ -1443,8 +1402,6 @@
     model_->Add(browser_shortcut,
                 std::make_unique<BrowserShortcutShelfItemController>(model_));
   }
-
-  ReportUpdateShelfIconList(model_);
 }
 
 int ChromeShelfController::FindInsertionPoint() {
@@ -1611,8 +1568,6 @@
   // Update the pin position preference as needed.
   if (ShouldSyncItemWithReentrancy(item))
     SyncPinPosition(item.id);
-
-  ReportUpdateShelfIconList(model_);
 }
 
 void ChromeShelfController::ShelfItemRemoved(int index,
@@ -1639,6 +1594,4 @@
     SyncPinPosition(item.id);
   else if (ShouldSyncItemWithReentrancy(old_item) && !ItemTypeIsPinned(item))
     shelf_prefs_->RemovePinPosition(profile(), old_item.id);
-
-  ReportUpdateShelfIconList(model_);
 }
diff --git a/chrome/browser/ui/lens/lens_side_panel_helper.h b/chrome/browser/ui/lens/lens_side_panel_helper.h
index 9637f6a..d87a812 100644
--- a/chrome/browser/ui/lens/lens_side_panel_helper.h
+++ b/chrome/browser/ui/lens/lens_side_panel_helper.h
@@ -25,6 +25,9 @@
 void OpenLensSidePanel(Browser* browser,
                        const content::OpenURLParams& url_params);
 
+// Opens the Lens region search feature in a new tab with a WebUI page.
+void OpenLensStaticPage(Browser* browser);
+
 // Check if the lens URL is a valid results page. This is done by checking if
 // the URL has a payload parameter.
 bool IsValidLensResultUrl(const GURL& url);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 1a3e5076..09144bcb 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1038,7 +1038,7 @@
   // Ensure that the indices are nonempty, sorted, and unique.
   DCHECK_GT(indices.size(), 0u);
   DCHECK(base::ranges::is_sorted(indices));
-  DCHECK(std::adjacent_find(indices.begin(), indices.end()) == indices.end());
+  DCHECK(base::ranges::adjacent_find(indices) == indices.end());
 
   // The odds of |new_group| colliding with an existing group are astronomically
   // low. If there is a collision, a DCHECK will fail in |AddToNewGroupImpl()|,
@@ -1058,7 +1058,7 @@
 
   // Ensure that the indices are sorted and unique.
   DCHECK(base::ranges::is_sorted(indices));
-  DCHECK(std::adjacent_find(indices.begin(), indices.end()) == indices.end());
+  DCHECK(base::ranges::adjacent_find(indices) == indices.end());
   CHECK(ContainsIndex(*(indices.begin())));
   CHECK(ContainsIndex(*(indices.rbegin())));
 
diff --git a/chrome/browser/ui/views/lens/lens_side_panel_helper.cc b/chrome/browser/ui/views/lens/lens_side_panel_helper.cc
index 7c142ab..9746fddc 100644
--- a/chrome/browser/ui/views/lens/lens_side_panel_helper.cc
+++ b/chrome/browser/ui/views/lens/lens_side_panel_helper.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/views/lens/lens_side_panel_controller.h"
 #include "chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
+#include "chrome/common/webui_url_constants.h"
 #include "components/lens/lens_entrypoints.h"
 #include "components/lens/lens_features.h"
 #include "components/lens/lens_rendering_environment.h"
@@ -119,4 +120,16 @@
   return web_contents;
 }
 
+void OpenLensStaticPage(Browser* browser) {
+  // TODO(juanmojica): Expand this function to simulate the current region
+  // search experience in the new tab.
+  DCHECK(browser);
+  GURL url(chrome::kChromeUILensURL);
+  content::OpenURLParams params(
+      url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false);
+  params.initiator_origin = url::Origin::Create(url);
+  browser->OpenURL(params);
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc
index 31e2d57e..621c7a1 100644
--- a/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc
+++ b/chrome/browser/ui/views/performance_controls/high_efficiency_chip_view_browsertest.cc
@@ -65,7 +65,7 @@
     return promo_controller;
   }
 
-  PageActionIconView* GetPageActionIconView() {
+  PageActionIconView* GetHighEfficiencyChipView() {
     BrowserView* browser_view =
         BrowserView::GetBrowserViewForBrowser(browser());
     return browser_view->GetLocationBarView()
@@ -73,9 +73,10 @@
         ->GetIconView(PageActionIconType::kHighEfficiency);
   }
 
-  void PressButton(views::Button* button) {
+  void ClickHighEfficiencyChip() {
     views::test::InteractionTestUtilSimulatorViews::PressButton(
-        button, ui::test::InteractionTestUtil::InputType::kMouse);
+        GetHighEfficiencyChipView(),
+        ui::test::InteractionTestUtil::InputType::kMouse);
   }
 
   void SetTabDiscardState(bool is_discarded) {
@@ -100,8 +101,31 @@
     waiter.WaitIfNeededAndGet();
   }
 
+  user_education::HelpBubbleView* GetHelpBubbleView() {
+    return GetFeaturePromoController()
+        ->promo_bubble_for_testing()
+        ->AsA<user_education::HelpBubbleViews>()
+        ->bubble_view();
+  }
+
+  void ClickIPHCancelButton() {
+    views::test::WidgetDestroyedWaiter waiter(GetHelpBubbleView()->GetWidget());
+    views::test::InteractionTestUtilSimulatorViews::PressButton(
+        GetHelpBubbleView()->GetDefaultButtonForTesting(),
+        ui::test::InteractionTestUtil::InputType::kMouse);
+    waiter.Wait();
+  }
+
+  void ClickIPHSettingsButton() {
+    views::test::WidgetDestroyedWaiter waiter(GetHelpBubbleView()->GetWidget());
+    views::test::InteractionTestUtilSimulatorViews::PressButton(
+        GetHelpBubbleView()->GetNonDefaultButtonForTesting(0),
+        ui::test::InteractionTestUtil::InputType::kMouse);
+    waiter.Wait();
+  }
+
   views::InkDropState GetInkDropState() {
-    return views::InkDrop::Get(GetPageActionIconView())
+    return views::InkDrop::Get(GetHighEfficiencyChipView())
         ->GetInkDrop()
         ->GetTargetInkDropState();
   }
@@ -111,17 +135,13 @@
 };
 
 IN_PROC_BROWSER_TEST_F(HighEfficiencyChipViewBrowserTest,
-                       PromoCustomActionClicked) {
+                       NavigatesOnIPHSettingsLinkClicked) {
   auto lock = BrowserFeaturePromoController::BlockActiveWindowCheckForTesting();
-  auto* const promo_controller = GetFeaturePromoController();
 
   EXPECT_FALSE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
 
   SetTabDiscardState(true);
-  PageActionIconView* icon = GetPageActionIconView();
-  EXPECT_TRUE(icon->GetVisible());
-
   WaitForIPHToShow();
 
   EXPECT_TRUE(GetFeaturePromoController()->IsPromoActive(
@@ -129,11 +149,7 @@
 
   content::TestNavigationObserver navigation_observer(
       browser()->tab_strip_model()->GetWebContentsAt(0));
-  auto* promo_bubble = promo_controller->promo_bubble_for_testing()
-                           ->AsA<user_education::HelpBubbleViews>()
-                           ->bubble_view();
-  auto* custom_action_button = promo_bubble->GetNonDefaultButtonForTesting(0);
-  PressButton(custom_action_button);
+  ClickIPHSettingsButton();
   navigation_observer.Wait();
 
   GURL expected(chrome::kChromeUIPerformanceSettingsURL);
@@ -141,56 +157,40 @@
 }
 
 IN_PROC_BROWSER_TEST_F(HighEfficiencyChipViewBrowserTest,
-                       PromoDismissesOnChipClick) {
+                       PromoDismissesOnCancelClick) {
   auto lock = BrowserFeaturePromoController::BlockActiveWindowCheckForTesting();
 
   SetTabDiscardState(true);
-  PageActionIconView* icon = GetPageActionIconView();
   WaitForIPHToShow();
 
   EXPECT_TRUE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
 
-  PressButton(icon);
+  ClickHighEfficiencyChip();
 
   // Expect the bubble to be open and the promo to be closed.
   EXPECT_FALSE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
-  EXPECT_NE(icon->GetBubble(), nullptr);
+  EXPECT_NE(GetHighEfficiencyChipView()->GetBubble(), nullptr);
 }
 
 IN_PROC_BROWSER_TEST_F(HighEfficiencyChipViewBrowserTest,
                        ShowAndHideInkDropWithPromo) {
   auto lock = BrowserFeaturePromoController::BlockActiveWindowCheckForTesting();
-  auto* const promo_controller = GetFeaturePromoController();
 
   EXPECT_FALSE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
 
   SetTabDiscardState(true);
-  PageActionIconView* icon = GetPageActionIconView();
-  EXPECT_TRUE(icon->GetVisible());
-
   WaitForIPHToShow();
 
   EXPECT_TRUE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
-
   EXPECT_EQ(GetInkDropState(), views::InkDropState::ACTIVATED);
 
-  auto* promo_bubble = promo_controller->promo_bubble_for_testing()
-                           ->AsA<user_education::HelpBubbleViews>()
-                           ->bubble_view();
+  ClickIPHCancelButton();
 
-  views::test::WidgetDestroyedWaiter waiter(promo_bubble->GetWidget());
-  auto* default_action_button = promo_bubble->GetDefaultButtonForTesting();
-  PressButton(default_action_button);
-  waiter.Wait();
-
-  EXPECT_FALSE(browser()->window()->IsFeaturePromoActive(
+  EXPECT_FALSE(GetFeaturePromoController()->IsPromoActive(
       feature_engagement::kIPHHighEfficiencyInfoModeFeature));
-
-  views::InkDropState current_state = GetInkDropState();
-  EXPECT_TRUE(current_state == views::InkDropState::HIDDEN ||
-              current_state == views::InkDropState::DEACTIVATED);
+  EXPECT_TRUE(GetInkDropState() == views::InkDropState::DEACTIVATED);
 }
diff --git a/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc b/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc
index 455907a..646a985 100644
--- a/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc
+++ b/chrome/browser/ui/views/side_panel/lens/lens_side_panel_coordinator_browsertest.cc
@@ -432,6 +432,7 @@
 
 IN_PROC_BROWSER_TEST_F(SearchImageWithSidePanel3PDseDisabled,
                        ImageSearchFor3PDSEWithValidImageOpensInNewTab) {
+  SetupImageSearchEngine();
   SetupAndLoadValidImagePage();
 
   // Ensures that the lens side panel coordinator is open and is valid when
@@ -458,6 +459,7 @@
 
 IN_PROC_BROWSER_TEST_F(SearchImageWithSidePanel3PDseDisabled,
                        ImageSearchForLensWithValidImageOpensInSidePanel) {
+  SetupImageSearchEngine();
   SetupUnifiedSidePanel();
   EXPECT_TRUE(GetUnifiedSidePanel()->GetVisible());
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index ede9f17..1f0c418 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -396,6 +396,10 @@
 #include "chrome/browser/ui/webui/media_router/cast_feedback_ui.h"
 #endif
 
+#if !BUILDFLAG(IS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#include "chrome/browser/ui/webui/lens/lens_ui.h"
+#endif
+
 #if BUILDFLAG(PLATFORM_CFM)
 #include "chrome/browser/ui/webui/ash/chromebox_for_meetings/network_settings_dialog.h"
 #endif  // BUILDFLAG(PLATFORM_CFM)
@@ -1354,6 +1358,12 @@
     return &NewWebUI<PrivacySandboxDialogUI>;
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if !BUILDFLAG(IS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  if (url.host_piece() == chrome::kChromeUILensHost) {
+    return &NewWebUI<LensUI>;
+  }
+#endif
+
   return nullptr;
 }
 
diff --git a/chrome/browser/ui/webui/lens/DIR_METADATA b/chrome/browser/ui/webui/lens/DIR_METADATA
new file mode 100644
index 0000000..749bdad
--- /dev/null
+++ b/chrome/browser/ui/webui/lens/DIR_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser"
+}
+team_email: "lens-chrome-eng+bugs@google.com"
diff --git a/chrome/browser/ui/webui/lens/OWNERS b/chrome/browser/ui/webui/lens/OWNERS
new file mode 100644
index 0000000..6e913aa
--- /dev/null
+++ b/chrome/browser/ui/webui/lens/OWNERS
@@ -0,0 +1,2 @@
+file://components/lens/OWNERS
+
diff --git a/chrome/browser/ui/webui/lens/lens_ui.cc b/chrome/browser/ui/webui/lens/lens_ui.cc
new file mode 100644
index 0000000..fa20353
--- /dev/null
+++ b/chrome/browser/ui/webui/lens/lens_ui.cc
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/lens/lens_ui.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/lens_resources.h"
+#include "chrome/grit/lens_resources_map.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+LensUI::LensUI(content::WebUI* web_ui) : WebUIController(web_ui) {
+  // Set up the chrome://lens source.
+  content::WebUIDataSource* html_source =
+      content::WebUIDataSource::CreateAndAdd(Profile::FromWebUI(web_ui),
+                                             chrome::kChromeUILensHost);
+  webui::SetupWebUIDataSource(
+      html_source, base::make_span(kLensResources, kLensResourcesSize),
+      IDR_LENS_LENS_HTML);
+}
+
+LensUI::~LensUI() = default;
diff --git a/chrome/browser/ui/webui/lens/lens_ui.h b/chrome/browser/ui/webui/lens/lens_ui.h
new file mode 100644
index 0000000..0bc6a6fa
--- /dev/null
+++ b/chrome/browser/ui/webui/lens/lens_ui.h
@@ -0,0 +1,16 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_LENS_LENS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_LENS_LENS_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+// The WebUI for chrome://lens
+class LensUI : public content::WebUIController {
+ public:
+  explicit LensUI(content::WebUI* web_ui);
+  ~LensUI() override;
+};
+#endif  // CHROME_BROWSER_UI_WEBUI_LENS_LENS_UI_H_
diff --git a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_browsertest.cc
index bd70ac5..346f478 100644
--- a/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/install_isolated_app_from_command_line_browsertest.cc
@@ -76,5 +76,6 @@
   const WebApp* web_app = GetWebAppRegistrar().GetAppById(app_id);
   EXPECT_THAT(web_app->isolation_data().has_value(), IsTrue());
 }
+
 }  // namespace
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
index 45e2a23..cee7da70 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_factory.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
+#include "chrome/browser/web_applications/isolated_web_apps/pending_install_info.h"
 #include "chrome/browser/web_applications/isolation_data.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/url_constants.h"
@@ -140,6 +141,7 @@
     LOG(ERROR) << error_message;
     return;
   }
+
   web_contents->ForEachRenderFrameHostWithAction(
       [frame_tree_node_id,
        &error_message](content::RenderFrameHost* render_frame_host) {
@@ -194,8 +196,8 @@
 
   IsolatedWebAppURLLoader(const IsolatedWebAppURLLoader&) = delete;
   IsolatedWebAppURLLoader& operator=(const IsolatedWebAppURLLoader&) = delete;
-
-  ~IsolatedWebAppURLLoader() override = default;
+  IsolatedWebAppURLLoader(IsolatedWebAppURLLoader&&) = delete;
+  IsolatedWebAppURLLoader& operator=(IsolatedWebAppURLLoader&&) = delete;
 
  private:
   void OnResponseRead(
@@ -348,63 +350,79 @@
     return;
   }
 
+  auto forward_request_to_isolation_data_content =
+      [&](const IsolationData& isolation_data) {
+        if (!IsSupportedHttpMethod(resource_request.method)) {
+          CompleteWithGeneratedHtmlResponse(
+              mojo::Remote<network::mojom::URLLoaderClient>(
+                  std::move(loader_client)),
+              net::HTTP_METHOD_NOT_ALLOWED, /*body=*/absl::nullopt);
+          return;
+        }
+
+        absl::visit(
+            base::Overloaded{
+                [&](const IsolationData::InstalledBundle& content) {
+                  auto* isolated_web_app_reader_registry =
+                      IsolatedWebAppReaderRegistryFactory::GetForProfile(
+                          profile_);
+                  if (!isolated_web_app_reader_registry) {
+                    LogErrorAndFail(
+                        "Support for Isolated Web Apps is not enabled.",
+                        std::move(loader_client));
+                    return;
+                  }
+                  mojo::MakeSelfOwnedReceiver(
+                      std::make_unique<IsolatedWebAppURLLoader>(
+                          isolated_web_app_reader_registry, content.path,
+                          *web_bundle_id, std::move(loader_client),
+                          resource_request, frame_tree_node_id_),
+                      mojo::PendingReceiver<network::mojom::URLLoader>(
+                          std::move(loader_receiver)));
+                },
+                [&](const IsolationData::DevModeBundle& content) {
+                  // TODO: Implement dev mode bundles.
+                  CompleteWithGeneratedHtmlResponse(
+                      mojo::Remote<network::mojom::URLLoaderClient>(
+                          std::move(loader_client)),
+                      net::HTTP_NOT_FOUND, /*body=*/absl::nullopt);
+                },
+                [&](const IsolationData::DevModeProxy& content) {
+                  HandleDevModeProxy(*url_info, content,
+                                     std::move(loader_receiver),
+                                     resource_request, std::move(loader_client),
+                                     traffic_annotation);
+                }},
+            isolation_data.content);
+      };
+
+  absl::optional<IsolationData> pending_install_isolation_data =
+      IsolatedWebAppPendingInstallInfo::FromWebContents(
+          *content::WebContents::FromFrameTreeNodeId(frame_tree_node_id_))
+          .isolation_data();
+  if (pending_install_isolation_data.has_value()) {
+    if (resource_request.url.path() == kInstallPagePath &&
+        IsSupportedHttpMethod(resource_request.method)) {
+      CompleteWithGeneratedHtmlResponse(
+          mojo::Remote<network::mojom::URLLoaderClient>(
+              std::move(loader_client)),
+          net::HTTP_OK, kInstallPageContent);
+      return;
+    }
+
+    forward_request_to_isolation_data_content(*pending_install_isolation_data);
+    return;
+  }
+
   base::expected<std::reference_wrapper<const WebApp>, std::string> iwa =
       FindIsolatedWebApp(profile_, *url_info);
+
   if (!iwa.has_value()) {
     LogErrorAndFail(iwa.error(), std::move(loader_client));
     return;
   }
 
-  if (!IsSupportedHttpMethod(resource_request.method)) {
-    CompleteWithGeneratedHtmlResponse(
-        mojo::Remote<network::mojom::URLLoaderClient>(std::move(loader_client)),
-        net::HTTP_METHOD_NOT_ALLOWED, /*body=*/absl::nullopt);
-    return;
-  }
-
-  // TODO(crbug.com/1333966): Check that the app is being installed before
-  // returning the auto-generated installation page.
-  if (resource_request.url.path() == kInstallPagePath) {
-    CompleteWithGeneratedHtmlResponse(
-        mojo::Remote<network::mojom::URLLoaderClient>(std::move(loader_client)),
-        net::HTTP_OK, kInstallPageContent);
-    return;
-  }
-
-  IsolationData isolation_data = iwa->get().isolation_data().value();
-  absl::visit(
-      base::Overloaded{
-          [&](const IsolationData::InstalledBundle& content) {
-            auto* isolated_web_app_reader_registry =
-                IsolatedWebAppReaderRegistryFactory::GetForProfile(profile_);
-            if (!isolated_web_app_reader_registry) {
-              LogErrorAndFail("Support for Isolated Web Apps is not enabled.",
-                              std::move(loader_client));
-              return;
-            }
-
-            auto loader = std::make_unique<IsolatedWebAppURLLoader>(
-                isolated_web_app_reader_registry, content.path, *web_bundle_id,
-                std::move(loader_client), resource_request,
-                frame_tree_node_id_);
-            mojo::MakeSelfOwnedReceiver(
-                std::move(std::move(loader)),
-                mojo::PendingReceiver<network::mojom::URLLoader>(
-                    std::move(loader_receiver)));
-          },
-          [&loader_client](const IsolationData::DevModeBundle& content) {
-            // TODO: Implement dev mode bundles.
-            CompleteWithGeneratedHtmlResponse(
-                mojo::Remote<network::mojom::URLLoaderClient>(
-                    std::move(loader_client)),
-                net::HTTP_NOT_FOUND, /*body=*/absl::nullopt);
-          },
-          [&](const IsolationData::DevModeProxy& content) {
-            HandleDevModeProxy(*url_info, content, std::move(loader_receiver),
-                               resource_request, std::move(loader_client),
-                               traffic_annotation);
-          }},
-      isolation_data.content);
+  forward_request_to_isolation_data_content(*iwa->get().isolation_data());
 }
 
 void IsolatedWebAppURLLoaderFactory::OnProfileWillBeDestroyed(
@@ -439,19 +457,20 @@
   network::ResourceRequest proxy_request(resource_request);
   proxy_request.url = proxy_url;
 
-  content::StoragePartition* iwa_partition = profile_->GetStoragePartition(
+  content::StoragePartition* storage_partition = profile_->GetStoragePartition(
       url_info.storage_partition_config(profile_), /*can_create=*/false);
-  if (iwa_partition == nullptr) {
+  if (storage_partition == nullptr) {
     LogErrorAndFail(base::StrCat({"Storage not found for Isolated Web App: ",
                                   resource_request.url.spec()}),
                     std::move(loader_client));
     return;
   }
 
-  iwa_partition->GetURLLoaderFactoryForBrowserProcess()->CreateLoaderAndStart(
-      std::move(loader_receiver),
-      /*request_id=*/0, network::mojom::kURLLoadOptionNone, proxy_request,
-      std::move(loader_client), traffic_annotation);
+  storage_partition->GetURLLoaderFactoryForBrowserProcess()
+      ->CreateLoaderAndStart(std::move(loader_receiver),
+                             /*request_id=*/0,
+                             network::mojom::kURLLoadOptionNone, proxy_request,
+                             std::move(loader_client), traffic_annotation);
 }
 
 void IsolatedWebAppURLLoaderFactory::LogErrorAndFail(
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
index 4f183eb7..4f818ec 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
+#include "chrome/browser/web_applications/isolated_web_apps/pending_install_info.h"
 #include "chrome/browser/web_applications/isolation_data.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
@@ -23,6 +24,7 @@
 #include "components/web_package/test_support/signed_web_bundles/web_bundle_signer.h"
 #include "components/web_package/web_bundle_builder.h"
 #include "content/public/browser/storage_partition_config.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/simple_url_loader_test_helper.h"
 #include "content/public/test/url_loader_interceptor.h"
@@ -149,10 +151,7 @@
   void RegisterWebApp(std::unique_ptr<WebApp> web_app,
                       bool create_storage_partition = true) {
     if (create_storage_partition) {
-      auto url_info = IsolatedWebAppUrlInfo::Create(web_app->scope());
-      profile()->GetStoragePartition(
-          url_info->storage_partition_config(profile()),
-          /*can_create=*/true);
+      CreateStoragePartitionForUrl(web_app->scope());
     }
 
     provider()->GetRegistrarMutable().registry().emplace(web_app->app_id(),
@@ -160,9 +159,9 @@
   }
 
   void CreateFactory() {
-    int dummy_frame_tree_node_id = 42;
     factory_.Bind(IsolatedWebAppURLLoaderFactory::Create(
-        dummy_frame_tree_node_id, profile()));
+        web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId(),
+        profile()));
   }
 
   int CreateLoaderAndRun(std::unique_ptr<network::ResourceRequest> request) {
@@ -187,6 +186,30 @@
     return loader->NetError();
   }
 
+  void CreateStoragePartitionForUrl(const GURL& url) {
+    base::expected<IsolatedWebAppUrlInfo, std::string> url_info =
+        IsolatedWebAppUrlInfo::Create(url);
+    if (!url_info.has_value()) {
+      CHECK(false) << "Can't  create url info for url " << url
+                   << ", error: " << url_info.error();
+    }
+
+    content::StoragePartition* current_storage_partition =
+        profile()->GetStoragePartition(
+            url_info->storage_partition_config(profile()),
+            /*can_create=*/false);
+
+    CHECK(current_storage_partition == nullptr)
+        << "Partition already exists for url: " << url;
+
+    content::StoragePartition* new_storage_partition =
+        profile()->GetStoragePartition(
+            url_info->storage_partition_config(profile()),
+            /*can_create=*/true);
+
+    CHECK(new_storage_partition != nullptr);
+  }
+
   const ScopedUrlHandler& url_handler() {
     CHECK(url_handler_);
     return *url_handler_;
@@ -304,7 +327,7 @@
 }
 
 TEST_F(IsolatedWebAppURLLoaderFactoryTest,
-       PostRequestsReturnMethodNotSupported) {
+       PostRequestsReturnMethodNotSupportedWhenAppIsInstalled) {
   RegisterWebApp(CreateIsolatedWebApp(kAppStartUrl,
                                       IsolationData{IsolationData::DevModeProxy{
                                           .proxy_url = kProxyUrl.spec()}}));
@@ -322,12 +345,39 @@
               IsHttpStatusCode(net::HTTP_METHOD_NOT_ALLOWED));
 }
 
-TEST_F(IsolatedWebAppURLLoaderFactoryTest,
-       PostRequestsFailWithErrFailedIfAppNotInstalled) {
+TEST_F(
+    IsolatedWebAppURLLoaderFactoryTest,
+    PostRequestsReturnMethodNotSupportedWhenAppIsInstalledAndThereIsPendingInstall) {
+  RegisterWebApp(CreateIsolatedWebApp(
+      kAppStartUrl, IsolationData{IsolationData::DevModeProxy{
+                        .proxy_url = "http://installed-app-proxy-url.com"}}));
+
+  IsolatedWebAppPendingInstallInfo::FromWebContents(*web_contents())
+      .set_isolation_data(IsolationData{IsolationData::DevModeProxy{
+          .proxy_url = "http://pending-install-proxy-url.com"}});
+
   CreateFactory();
 
   auto request = std::make_unique<network::ResourceRequest>();
-  request->method = net::HttpRequestHeaders::kPostMethod;
+  const char* kUnsupportedHttpMethod = net::HttpRequestHeaders::kPostMethod;
+  request->method = kUnsupportedHttpMethod;
+  request->url = kAppStartUrl;
+  int status = CreateLoaderAndRun(std::move(request));
+
+  EXPECT_THAT(status, IsNetError(net::OK));
+  ASSERT_THAT(ResponseInfo(), NotNull());
+  EXPECT_THAT(ResponseInfo()->headers->response_code(),
+              IsHttpStatusCode(net::HTTP_METHOD_NOT_ALLOWED));
+}
+
+TEST_F(IsolatedWebAppURLLoaderFactoryTest,
+       RequestWithUnsupportedHttpMethodFailWithErrFailedIfAppNotInstalled) {
+  CreateFactory();
+
+  auto request = std::make_unique<network::ResourceRequest>();
+
+  const char* kUnsupportedHttpMethod = net::HttpRequestHeaders::kPostMethod;
+  request->method = kUnsupportedHttpMethod;
   request->url = kAppStartUrl;
   int status = CreateLoaderAndRun(std::move(request));
 
@@ -455,7 +505,8 @@
               Eq(GURL("http://example.com/foo/bar.html")));
 }
 
-TEST_F(IsolatedWebAppURLLoaderFactoryTest, GeneratedInstallPageIsReturned) {
+TEST_F(IsolatedWebAppURLLoaderFactoryTest,
+       DoNotReturnGeneratedPageWhenNotInstallingApplication) {
   RegisterWebApp(CreateIsolatedWebApp(kAppStartUrl,
                                       IsolationData{IsolationData::DevModeProxy{
                                           .proxy_url = "http://example.com"}}));
@@ -465,6 +516,31 @@
   auto request = std::make_unique<network::ResourceRequest>();
   request->url = GURL("isolated-app://" + kWebBundleId +
                       "/.well-known/_generated_install_page.html");
+
+  int status = CreateLoaderAndRun(std::move(request));
+
+  EXPECT_THAT(status, IsNetError(net::OK));
+  EXPECT_THAT(
+      url_handler().intercepted_url(),
+      Eq("http://example.com/.well-known/_generated_install_page.html"));
+}
+
+TEST_F(IsolatedWebAppURLLoaderFactoryTest,
+       ReturnGeneratedPageWhenInstallingApplication) {
+  IsolatedWebAppPendingInstallInfo::FromWebContents(*web_contents())
+      .set_isolation_data(IsolationData{IsolationData::DevModeProxy{
+          .proxy_url = "http://some-proxy-url.com"}});
+
+  RegisterWebApp(CreateIsolatedWebApp(kAppStartUrl,
+                                      IsolationData{IsolationData::DevModeProxy{
+                                          .proxy_url = "http://example.com"}}));
+
+  CreateFactory();
+
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = GURL("isolated-app://" + kWebBundleId +
+                      "/.well-known/_generated_install_page.html");
+
   int status = CreateLoaderAndRun(std::move(request));
 
   EXPECT_THAT(status, IsNetError(net::OK));
@@ -475,7 +551,53 @@
 }
 
 TEST_F(IsolatedWebAppURLLoaderFactoryTest,
-       GeneratedInstallPageIsNotReturnedForNonIwa) {
+       RequestsRedirectedToPendingInstallIsolationDataWhenAppIsInstalled) {
+  IsolatedWebAppPendingInstallInfo::FromWebContents(*web_contents())
+      .set_isolation_data(IsolationData{IsolationData::DevModeProxy{
+          .proxy_url = "http://some-proxy-url.com"}});
+
+  RegisterWebApp(CreateIsolatedWebApp(kAppStartUrl,
+                                      IsolationData{IsolationData::DevModeProxy{
+                                          .proxy_url = "http://example.com"}}));
+
+  CreateFactory();
+
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = GURL("isolated-app://" + kWebBundleId +
+                      "/some-resource-for-testing.html");
+
+  int status = CreateLoaderAndRun(std::move(request));
+
+  EXPECT_THAT(status, IsNetError(net::OK));
+  EXPECT_THAT(
+      url_handler().intercepted_url(),
+      Eq(GURL("http://some-proxy-url.com/some-resource-for-testing.html")));
+}
+
+TEST_F(IsolatedWebAppURLLoaderFactoryTest,
+       RequestsRedirectedToPendingInstallIsolationDataWhenAppIsNotInstalled) {
+  CreateStoragePartitionForUrl(GURL("isolated-app://" + kWebBundleId));
+
+  IsolatedWebAppPendingInstallInfo::FromWebContents(*web_contents())
+      .set_isolation_data(IsolationData{IsolationData::DevModeProxy{
+          .proxy_url = "http://some-proxy-url.com"}});
+
+  CreateFactory();
+
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = GURL("isolated-app://" + kWebBundleId +
+                      "/some-resource-for-testing.html");
+
+  int status = CreateLoaderAndRun(std::move(request));
+
+  EXPECT_THAT(status, IsNetError(net::OK));
+  EXPECT_THAT(
+      url_handler().intercepted_url(),
+      Eq(GURL("http://some-proxy-url.com/some-resource-for-testing.html")));
+}
+
+TEST_F(IsolatedWebAppURLLoaderFactoryTest,
+       GeneratedInstallPageIsNotReturnedForNonInstallingApp) {
   RegisterWebApp(CreateWebApp(kAppStartUrl));
 
   CreateFactory();
diff --git a/chrome/browser/win/conflicts/installed_applications_unittest.cc b/chrome/browser/win/conflicts/installed_applications_unittest.cc
index f1b6d7c..ae494e1 100644
--- a/chrome/browser/win/conflicts/installed_applications_unittest.cc
+++ b/chrome/browser/win/conflicts/installed_applications_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/win/conflicts/installed_applications.h"
 
-#include <algorithm>
 #include <map>
 
+#include "base/ranges/algorithm.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
@@ -397,13 +397,10 @@
   auto applications = installed_applications().applications_;
   std::sort(std::begin(applications), std::end(applications));
   EXPECT_EQ(std::end(applications),
-            std::adjacent_find(std::begin(applications), std::end(applications),
-                               [](const auto& lhs, const auto& rhs) {
-                                 return std::tie(lhs.name, lhs.registry_root,
-                                                 lhs.registry_key_path,
-                                                 lhs.registry_wow64_access) ==
-                                        std::tie(rhs.name, rhs.registry_root,
-                                                 rhs.registry_key_path,
-                                                 rhs.registry_wow64_access);
-                               }));
+            base::ranges::adjacent_find(
+                applications, std::equal<>(), [](const auto& app) {
+                  return std::tie(app.name, app.registry_root,
+                                  app.registry_key_path,
+                                  app.registry_wow64_access);
+                }));
 }
diff --git a/chrome/browser/win/conflicts/module_blocklist_cache_util_unittest.cc b/chrome/browser/win/conflicts/module_blocklist_cache_util_unittest.cc
index 0af2cdd09..2db9d15 100644
--- a/chrome/browser/win/conflicts/module_blocklist_cache_util_unittest.cc
+++ b/chrome/browser/win/conflicts/module_blocklist_cache_util_unittest.cc
@@ -52,8 +52,8 @@
 
   // Sort the entries and make sure each module is unique.
   std::sort(entries.begin(), entries.end(), internal::ModuleLess());
-  CHECK(std::adjacent_find(entries.begin(), entries.end(),
-                           internal::ModuleEqual()) == entries.end());
+  CHECK(base::ranges::adjacent_find(entries, internal::ModuleEqual()) ==
+        entries.end());
 
   return entries;
 }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 01d48837..883d8a80 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1665748375-b2b65b3edd4aa54d39584ec37f17a02b534c6a88.profdata
+chrome-linux-main-1665770398-17d4f7bea9fcc7d745ba4f47c559f834a80ec320.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index a6075393..324fd7d 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1664819315-34a4cf7009d4c6f71f01d59b264c8857d33d762e.profdata
+chrome-mac-arm-main-1665770398-c2ca4d7140879c329be52f41540880b88c5e6fea.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 069b275..40e18e1 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1665748375-fdaca138baf43e64fc055e9a634fed17cf608280.profdata
+chrome-mac-main-1665770398-3e2cbb4cbec67c24aa069dcf24f9a5316ce169a2.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 2484d07..b704373 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1665725711-7a5ece51c21f206817e2bbc0fdf1b1588c007956.profdata
+chrome-win32-main-1665770398-e5491636ea29ef2e4a2a0d4123cb4c9b39977e3f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9fadd49..c0e6f11 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1665748375-fe5d46e806b458fcf6d095059fa61765fe504a88.profdata
+chrome-win64-main-1665770398-60ea39db78e2e9990263a15c0195420700de507e.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index c298d35..c5eb50b 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -217,6 +217,11 @@
           "//chrome/browser/resources/media_router/cast_feedback:resources",
         ]
       }
+
+      if (is_chrome_branded && toolkit_views) {
+        sources += [ "$root_gen_dir/chrome/lens_resources.pak" ]
+        deps += [ "//chrome/browser/resources/lens:resources" ]
+      }
     }
     if (is_chromeos_ash) {
       sources += [
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json
index 28393334..8d119adc 100644
--- a/chrome/common/extensions/api/accessibility_private.json
+++ b/chrome/common/extensions/api/accessibility_private.json
@@ -234,7 +234,7 @@
       {
         "id": "AccessibilityFeature",
         "type": "string",
-        "enum": [ "enhancedNetworkVoices", "googleTtsLanguagePacks", "dictationPumpkinParsing", "selectToSpeakVoiceSwitching"],
+        "enum": [ "enhancedNetworkVoices", "googleTtsLanguagePacks", "dictationPumpkinParsing", "selectToSpeakVoiceSwitching", "dictationMoreCommands"],
         "description": "Subset of accessibility features."
       },
       {
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index cc945d1..c7f9465 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -619,6 +619,11 @@
 const char kChromeUICastFeedbackHost[] = "cast-feedback";
 #endif
 
+#if !BUILDFLAG(IS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+const char kChromeUILensURL[] = "chrome://lens/";
+const char kChromeUILensHost[] = "lens";
+#endif
+
 // Extension sub pages.
 const char kExtensionConfigureCommandsSubPage[] = "configureCommands";
 
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 276f7a7..31a4c4c 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -542,6 +542,11 @@
 extern const char kChromeUICastFeedbackHost[];
 #endif
 
+#if !BUILDFLAG(IS_ANDROID) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
+extern const char kChromeUILensURL[];
+extern const char kChromeUILensHost[];
+#endif
+
 // Extensions sub pages.
 extern const char kExtensionConfigureCommandsSubPage[];
 
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
index 533da31c..e3f4235 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -105,6 +105,17 @@
                                    html_tag);
 }
 
+void SetAXNodeDataTextDirection(v8::Isolate* isolate,
+                                gin::Dictionary* v8_dict,
+                                ui::AXNodeData* ax_node_data) {
+  v8::Local<v8::Value> v8_direction;
+  v8_dict->Get("direction", &v8_direction);
+  int direction;
+  gin::ConvertFromV8(isolate, v8_direction, &direction);
+  ax_node_data->AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
+                                direction);
+}
+
 void SetAXNodeDataUrl(v8::Isolate* isolate,
                       gin::Dictionary* v8_dict,
                       ui::AXNodeData* ax_node_data) {
@@ -183,6 +194,7 @@
     SetAXNodeDataChildIds(isolate, &v8_node_dict, &ax_node_data);
     SetAXNodeDataHtmlTag(isolate, &v8_node_dict, &ax_node_data);
     SetAXNodeDataLanguage(isolate, &v8_node_dict, &ax_node_data);
+    SetAXNodeDataTextDirection(isolate, &v8_node_dict, &ax_node_data);
     SetAXNodeDataUrl(isolate, &v8_node_dict, &ax_node_data);
     snapshot.nodes.push_back(ax_node_data);
   }
@@ -213,13 +225,13 @@
 ReadAnythingAppController* ReadAnythingAppController::Install(
     content::RenderFrame* render_frame) {
   v8::Isolate* isolate = blink::MainThreadIsolate();
-  v8::MicrotasksScope microtask_scope(isolate,
-                                      v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context =
       render_frame->GetWebFrame()->MainWorldScriptContext();
   if (context.IsEmpty())
     return nullptr;
+  v8::MicrotasksScope microtask_scope(isolate, context->GetMicrotaskQueue(),
+                                      v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   v8::Context::Scope context_scope(context);
 
@@ -325,6 +337,8 @@
       .SetProperty("letterSpacing", &ReadAnythingAppController::LetterSpacing)
       .SetProperty("lineSpacing", &ReadAnythingAppController::LineSpacing)
       .SetMethod("getChildren", &ReadAnythingAppController::GetChildren)
+      .SetMethod("getTextDirection",
+                 &ReadAnythingAppController::GetTextDirection)
       .SetMethod("getHtmlTag", &ReadAnythingAppController::GetHtmlTag)
       .SetMethod("getLanguage", &ReadAnythingAppController::GetLanguage)
       .SetMethod("getTextContent", &ReadAnythingAppController::GetTextContent)
@@ -415,6 +429,30 @@
   return text_content;
 }
 
+std::string ReadAnythingAppController::GetTextDirection(
+    ui::AXNodeID ax_node_id) {
+  ui::AXNode* ax_node = GetAXNode(ax_node_id);
+  if (!ax_node)
+    return std::string();
+
+  auto text_direction = static_cast<ax::mojom::WritingDirection>(
+      ax_node->GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
+
+  // Vertical writing is displayed horizontally with "auto".
+  switch (text_direction) {
+    case ax::mojom::WritingDirection::kLtr:
+      return "ltr";
+    case ax::mojom::WritingDirection::kRtl:
+      return "rtl";
+    case ax::mojom::WritingDirection::kTtb:
+      return "auto";
+    case ax::mojom::WritingDirection::kBtt:
+      return "auto";
+    default:
+      return std::string();
+  }
+}
+
 std::string ReadAnythingAppController::GetUrl(ui::AXNodeID ax_node_id) {
   ui::AXNode* ax_node = GetAXNode(ax_node_id);
   if (!ax_node)
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything_app_controller.h
index 527cc5d..2a33fea3 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.h
+++ b/chrome/renderer/accessibility/read_anything_app_controller.h
@@ -82,6 +82,7 @@
   std::string GetHtmlTag(ui::AXNodeID ax_node_id);
   std::string GetLanguage(ui::AXNodeID ax_node_id);
   std::string GetTextContent(ui::AXNodeID ax_node_id);
+  std::string GetTextDirection(ui::AXNodeID ax_node_id);
   std::string GetUrl(ui::AXNodeID ax_node_id);
   void OnConnected();
 
diff --git a/chrome/renderer/cart/commerce_hint_agent.cc b/chrome/renderer/cart/commerce_hint_agent.cc
index 878bbc3..7d9ed7e 100644
--- a/chrome/renderer/cart/commerce_hint_agent.cc
+++ b/chrome/renderer/cart/commerce_hint_agent.cc
@@ -501,6 +501,9 @@
   const GURL& navigation_url(frame->GetDocument().Url());
   const GURL& url = request.Url();
 
+  if (CommerceHintAgent::ShouldSkipAddToCartRequest(navigation_url, url)) {
+    return false;
+  }
   bool is_add_to_cart = false;
   if (navigation_url.DomainIs("dickssportinggoods.com")) {
     is_add_to_cart = CommerceHintAgent::IsAddToCart(url.spec());
@@ -532,10 +535,6 @@
     return true;
   }
 
-  if (CommerceHintAgent::ShouldSkipAddToCartRequest(navigation_url, url)) {
-    return false;
-  }
-
   if (IsCartHeuristicsImprovementEnabled()) {
     if (navigation_url.DomainIs("abebooks.com"))
       return false;
@@ -1170,11 +1169,17 @@
 
 bool CommerceHintAgent::ShouldSkipAddToCartRequest(const GURL& navigation_url,
                                                    const GURL& request_url) {
+  const std::string& navigation_domain = eTLDPlusOne(navigation_url);
+  const re2::RE2* pattern =
+      commerce_heuristics::CommerceHeuristicsData::GetInstance()
+          .GetSkipAddToCartPatternForDomain(navigation_domain);
+  if (pattern) {
+    return PartialMatch(request_url.spec().substr(0, kLengthLimit), *pattern);
+  }
   const std::map<std::string, std::string>& skip_string_map =
       GetSkipAddToCartMapping();
   static base::NoDestructor<std::map<std::string, std::unique_ptr<re2::RE2>>>
       skip_regex_map;
-  const std::string& navigation_domain = eTLDPlusOne(navigation_url);
   if (skip_string_map.find(navigation_domain) == skip_string_map.end()) {
     return false;
   }
diff --git a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc
index 5687c26..b08ec0c6 100644
--- a/chrome/renderer/cart/commerce_hint_agent_browsertest.cc
+++ b/chrome/renderer/cart/commerce_hint_agent_browsertest.cc
@@ -504,6 +504,27 @@
   ExpectUKMCount(XHREntry::kEntryName, "IsAddToCart", 1);
 }
 
+IN_PROC_BROWSER_TEST_F(CommerceHintAgentTest, SkipAddToCart_FromComponent) {
+  bool is_populated =
+      commerce_hint_service_->InitializeCommerceHeuristicsForTesting(
+          base::Version("0.0.0.1"), R"###(
+          {
+            "guitarcenter.com": {
+              "skip_add_to_cart_regex": "dummy-request"
+            }
+          }
+      )###",
+          "{}", "", "");
+  DCHECK(is_populated);
+
+  NavigateToURL("https://www.guitarcenter.com/");
+  SendXHR("/add-to-cart", "product: 123");
+  WaitForUmaCount("Commerce.Carts.AddToCartByURL", 1);
+
+  SendXHR("/add-to-cart/dummy-request-url", "product: 123");
+  WaitForUmaCount("Commerce.Carts.AddToCartByURL", 1);
+}
+
 // TODO(https://crbug/1310497, https://crbug.com/1362442): This test is flaky
 // on ChromeOS and Linux Asan.
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/renderer/net/net_error_page_controller.cc b/chrome/renderer/net/net_error_page_controller.cc
index 20d0993..6424315 100644
--- a/chrome/renderer/net/net_error_page_controller.cc
+++ b/chrome/renderer/net/net_error_page_controller.cc
@@ -24,13 +24,14 @@
                                      base::WeakPtr<Delegate> delegate) {
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
-  v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Context> context =
       render_frame->GetWebFrame()->MainWorldScriptContext();
   if (context.IsEmpty())
     return;
 
+  v8::MicrotasksScope microtasks_scope(
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Context::Scope context_scope(context);
 
   gin::Handle<NetErrorPageController> controller = gin::CreateHandle(
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
index da71ced..f5da744d 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
@@ -33,13 +33,14 @@
     base::WeakPtr<SupervisedUserErrorPageControllerDelegate> delegate) {
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
-  v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Context> context =
       render_frame->GetWebFrame()->MainWorldScriptContext();
   if (context.IsEmpty())
     return;
 
+  v8::MicrotasksScope microtasks_scope(
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Context::Scope context_scope(context);
 
   gin::Handle<SupervisedUserErrorPageController> controller = gin::CreateHandle(
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
index 4c3b12b..7589844 100644
--- a/chrome/services/printing/print_backend_service_impl.cc
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -51,6 +51,9 @@
 #if BUILDFLAG(IS_WIN)
 #include "base/containers/queue.h"
 #include "base/win/win_util.h"
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "printing/emf_win.h"
 #include "printing/printed_page_win.h"
 #include "ui/gfx/geometry/rect.h"
@@ -734,6 +737,13 @@
                            std::move(callback)));
 }
 
+#if BUILDFLAG(IS_WIN)
+void PrintBackendServiceImpl::BindPrinterXmlParser(
+    mojo::PendingRemote<mojom::PrinterXmlParser> remote) {
+  xml_parser_remote_.Bind(std::move(remote));
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 void PrintBackendServiceImpl::OnDidStartPrintingReadyDocument(
     DocumentHelper& document_helper,
     mojom::ResultCode result) {
diff --git a/chrome/services/printing/print_backend_service_impl.h b/chrome/services/printing/print_backend_service_impl.h
index ca339999..cfd95ee 100644
--- a/chrome/services/printing/print_backend_service_impl.h
+++ b/chrome/services/printing/print_backend_service_impl.h
@@ -27,6 +27,12 @@
 #include "printing/printing_context.h"
 #include "ui/gfx/native_widget_types.h"
 
+#if BUILDFLAG(IS_WIN)
+#include "chrome/services/printing/public/mojom/printer_xml_parser.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#endif  // BUILDFLAG(IS_WIN)
+
 #if !BUILDFLAG(ENABLE_OOP_PRINTING)
 #error "Out-of-process printing must be enabled."
 #endif
@@ -122,6 +128,10 @@
 
   // mojom::PrintBackendService implementation:
   void Init(const std::string& locale) override;
+#if BUILDFLAG(IS_WIN)
+  void BindPrinterXmlParser(
+      mojo::PendingRemote<mojom::PrinterXmlParser> remote) override;
+#endif  // BUILDFLAG(IS_WIN)
   void Poke() override;
   void EnumeratePrinters(
       mojom::PrintBackendService::EnumeratePrintersCallback callback) override;
@@ -218,6 +228,10 @@
   std::vector<std::unique_ptr<DocumentHelper>> documents_;
 
   mojo::Receiver<mojom::PrintBackendService> receiver_;
+
+#if BUILDFLAG(IS_WIN)
+  mojo::Remote<mojom::PrinterXmlParser> xml_parser_remote_;
+#endif  // BUILDFLAG(IS_WIN)
 };
 
 }  // namespace printing
diff --git a/chrome/services/printing/public/mojom/BUILD.gn b/chrome/services/printing/public/mojom/BUILD.gn
index 5c17796..759524f1 100644
--- a/chrome/services/printing/public/mojom/BUILD.gn
+++ b/chrome/services/printing/public/mojom/BUILD.gn
@@ -46,6 +46,9 @@
       "//printing/mojom:printing_context",
       "//ui/gfx/geometry/mojom",
     ]
+    if (is_win) {
+      sources += [ "printer_xml_parser.mojom" ]
+    }
   }
 
   cpp_typemaps = [
diff --git a/chrome/services/printing/public/mojom/print_backend_service.mojom b/chrome/services/printing/public/mojom/print_backend_service.mojom
index 912330b..bf5e1de0 100644
--- a/chrome/services/printing/public/mojom/print_backend_service.mojom
+++ b/chrome/services/printing/public/mojom/print_backend_service.mojom
@@ -13,6 +13,9 @@
 import "sandbox/policy/mojom/sandbox.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
+[EnableIf=is_win]
+import "chrome/services/printing/public/mojom/printer_xml_parser.mojom";
+
 // The default printer name, or the `ResultCode` if there was an error when
 // trying to retrieve this data.
 union DefaultPrinterNameResult {
@@ -91,6 +94,11 @@
   // interface to the underlying data source.
   Init(string locale);
 
+  // Binds an interface that is used to communicate with the browser process
+  // to parse XML in a separate process.
+  [EnableIf=is_win]
+  BindPrinterXmlParser(pending_remote<PrinterXmlParser> remote);
+
   // TODO(crbug.com/1225111)  Message with no arguments and no reply that is
   // useful to ensure that an idle timeout change takes effect.
   Poke();
diff --git a/chrome/services/printing/public/mojom/printer_xml_parser.mojom b/chrome/services/printing/public/mojom/printer_xml_parser.mojom
new file mode 100644
index 0000000..18abced4
--- /dev/null
+++ b/chrome/services/printing/public/mojom/printer_xml_parser.mojom
@@ -0,0 +1,27 @@
+// 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.
+
+module printing.mojom;
+
+import "mojo/public/mojom/base/values.mojom";
+import "printing/mojom/print.mojom";
+
+// The capabilities of a printer as a `base::Value`, or the `ResultCode` if
+// there was an error when trying to retrieve this data.
+union PrinterCapabilitiesValueResult {
+  mojo_base.mojom.Value capabilities;
+  ResultCode result_code;
+};
+
+// An interface that is used by printing utility services to send XML parse
+// requests to the browser process. The browser process can then facilitate
+// safely parsing the XML.
+interface PrinterXmlParser {
+  // Receives an XML string of printer capabilities and responds with a
+  // base::Value of the parsed XML or ResultCode if there was an error
+  // retrieving the data.
+  [Sync]
+  ParseXmlForPrinterCapabilities(string capabilities_xml) =>
+    (PrinterCapabilitiesValueResult value_result);
+};
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js
index ff265ae5..2c5784e 100644
--- a/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js
+++ b/chrome/test/data/webui/chromeos/os_feedback_ui/confirmation_page_test.js
@@ -264,6 +264,15 @@
     assertEquals(1, feedbackServiceProvider.getOpenDiagnosticsAppCallCount());
     verifyRecordPostSubmitActionCalled(
         true, FeedbackAppPostSubmitAction.kOpenDiagnosticsApp);
+
+    // Make sure that the label and the sub-label are clickable too.
+    const label = link.querySelector('.label');
+    label.click();
+    assertEquals(2, feedbackServiceProvider.getOpenDiagnosticsAppCallCount());
+
+    const subLabel = link.querySelector('.sub-label');
+    subLabel.click();
+    assertEquals(3, feedbackServiceProvider.getOpenDiagnosticsAppCallCount());
   });
 
   // Test clicking explore app link.
@@ -280,6 +289,15 @@
     assertEquals(1, feedbackServiceProvider.getOpenExploreAppCallCount());
     verifyRecordPostSubmitActionCalled(
         true, FeedbackAppPostSubmitAction.kOpenExploreApp);
+
+    // Make sure that the label and the sub-label are clickable too.
+    const label = link.querySelector('.label');
+    label.click();
+    assertEquals(2, feedbackServiceProvider.getOpenExploreAppCallCount());
+
+    const subLabel = link.querySelector('.sub-label');
+    subLabel.click();
+    assertEquals(3, feedbackServiceProvider.getOpenExploreAppCallCount());
   });
 
   // Test clicking openChromebookHelp link.
@@ -312,6 +330,15 @@
         url, 'https://support.google.com/chromebook/?hl=en#topic=3399709');
     verifyRecordPostSubmitActionCalled(
         true, FeedbackAppPostSubmitAction.kOpenChromebookCommunity);
+
+    // Make sure that the label and the sub-label are clickable too.
+    const label = link.querySelector('.label');
+    label.click();
+    assertEquals(2, windowOpenCalled);
+
+    const subLabel = link.querySelector('.sub-label');
+    subLabel.click();
+    assertEquals(3, windowOpenCalled);
   });
 
   // Test that we only record the user's first action on confirmation page.
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
index acbbb1e4..49911a4 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
@@ -104,7 +104,6 @@
       layout: WallpaperLayout.kCenter,
       key: '1',
       type: WallpaperType.kOnline,
-      url: {url: 'data:image/png;base64somedataurl/0'},
     };
   }
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_fullscreen_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_fullscreen_element_test.ts
index bf1479c..e51df833 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_fullscreen_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_fullscreen_element_test.ts
@@ -26,7 +26,6 @@
     layout: WallpaperLayout.kCenter,
     key: 'testing',
     type: WallpaperType.kCustomized,
-    url: {url: 'data://testing'},
   };
 
   const pendingSelectedCustomImage:
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_preview_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_preview_element_test.ts
index 3a76ca9..d1e341f 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_preview_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_preview_element_test.ts
@@ -86,7 +86,11 @@
     await waitAfterNextRender(wallpaperPreviewElement);
 
     const img = wallpaperPreviewElement.shadowRoot!.querySelector('img');
-    assertEquals(wallpaperProvider.currentWallpaper.url.url, img!.src);
+    assertEquals(
+        `chrome://personalization/wallpaper.png?key=${
+            wallpaperProvider.currentWallpaper.key}`,
+        img!.src,
+        'current wallpaper key is appended to url as query parameter');
   });
 
   test('shows placeholders when image fails to load', async () => {
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_selected_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_selected_element_test.ts
index f5e6c31b..73fc488 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_selected_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_selected_element_test.ts
@@ -91,7 +91,10 @@
     await waitAfterNextRender(wallpaperSelectedElement);
 
     const img = wallpaperSelectedElement.shadowRoot!.querySelector('img');
-    assertEquals(wallpaperProvider.currentWallpaper.url.url, img!.src);
+    assertEquals(
+        `chrome://personalization/wallpaper.png?key=${
+            wallpaperProvider.currentWallpaper.key}`,
+        img!.src, 'sets current wallpaper key appended to url');
 
     const textContainerElements =
         wallpaperSelectedElement.shadowRoot!.querySelectorAll(
@@ -142,17 +145,22 @@
 
     const img = wallpaperSelectedElement.shadowRoot!.querySelector('img') as
         HTMLImageElement;
-    assertEquals(wallpaperProvider.currentWallpaper.url.url, img.src);
+    assertEquals(
+        `chrome://personalization/wallpaper.png?key=${
+            wallpaperProvider.currentWallpaper.key}`,
+        img!.src, 'sets current wallpaper key appended to url');
+
 
     personalizationStore.data.wallpaper.currentSelected = {
-      url: {url: 'data:image/png;base64_some_new_data'},
-      attribution: ['New attribution'],
-      assetId: BigInt(100),
+      ...personalizationStore.data.wallpaper.currentSelected,
+      key: 'new_key',
     };
     personalizationStore.notifyObservers();
     await waitAfterNextRender(wallpaperSelectedElement);
 
-    assertEquals('data:image/png;base64_some_new_data', img.src);
+    assertEquals(
+        `chrome://personalization/wallpaper.png?key=new_key`, img.src,
+        'updates wallpaper key query parameter');
   });
 
   test('shows placeholders when image fails to load', async () => {
@@ -181,20 +189,6 @@
         null, wallpaperSelectedElement.shadowRoot!.querySelector('img'));
   });
 
-  test('shows image url with data scheme', async () => {
-    personalizationStore.data.wallpaper.currentSelected = {
-      url: {url: 'data:image/png;base64,abc='},
-      attribution: [],
-      assetId: BigInt(100),
-    };
-    personalizationStore.data.wallpaper.loading.selected = false;
-    wallpaperSelectedElement = initElement(WallpaperSelected);
-    await waitAfterNextRender(wallpaperSelectedElement);
-
-    const img = wallpaperSelectedElement.shadowRoot!.querySelector('img');
-    assertEquals('data:image/png;base64,abc=', img!.src);
-  });
-
   test('shows daily refresh option on the collection view', async () => {
     personalizationStore.data.wallpaper.currentSelected = {
       url: {url: 'data:image/png;base64,abc='},
@@ -335,7 +329,6 @@
 
   test('shows attribution for device default wallpaper', async () => {
     const currentSelected: CurrentWallpaper = {
-      url: {url: 'url'},
       attribution: ['testing attribution'],
       layout: WallpaperLayout.kStretch,
       type: WallpaperType.kDefault,
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
index 4d6777d..63161a01 100644
--- a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
@@ -608,4 +608,146 @@
     const expected: string = '<div><p>ello</p><p>World</p><p>Fr</p></div>';
     assertContainerInnerHTML(expected);
   });
+
+  test('updateContent textDirection', () => {
+    // root htmlTag='#document' id=1
+    // ++paragraph htmlTag='p' id=2 direction='ltr'
+    // ++++staticText name='This is left to right writing' id=3
+    // ++paragraph htmlTag='p' id=4 direction='rtl'
+    // ++++staticText name='This is right to left writing' id=4
+    const axTree = {
+      rootId: 1,
+      nodes: [
+        {
+          id: 1,
+          role: 'rootWebArea',
+          htmlTag: '#document',
+          childIds: [2, 4],
+        },
+        {
+          id: 2,
+          role: 'paragraph',
+          htmlTag: 'p',
+          direction: 1,
+          childIds: [3],
+        },
+        {
+          id: 3,
+          role: 'staticText',
+          name: 'This is left to right writing',
+        },
+        {
+          id: 4,
+          role: 'paragraph',
+          htmlTag: 'p',
+          direction: 2,
+          childIds: [5],
+        },
+        {
+          id: 5,
+          role: 'staticText',
+          name: 'This is right to left writing',
+        },
+      ],
+    };
+    chrome.readAnything.setContentForTesting(axTree, [2, 4]);
+    const expected: string = '<p dir="ltr">This is left to right writing</p>' +
+        '<p dir="rtl">This is right to left writing</p>';
+    assertContainerInnerHTML(expected);
+  });
+
+  test('updateContent textDirection parentNodeDiffDir', () => {
+    // root htmlTag='#document' id=1
+    // ++paragraph htmlTag='p' id=2 direction='ltr'
+    // ++++staticText name='This is ltr' id=3
+    // ++++link htmlTag='a' url='http://www.google.com/' id=4 direction='rtl'
+    // ++++++staticText name='This link is rtl' id=5
+    const axTree = {
+      rootId: 1,
+      nodes: [
+        {
+          id: 1,
+          role: 'rootWebArea',
+          htmlTag: '#document',
+          childIds: [2],
+        },
+        {
+          id: 2,
+          role: 'paragraph',
+          htmlTag: 'p',
+          direction: 1,
+          childIds: [3, 4],
+        },
+        {
+          id: 3,
+          role: 'staticText',
+          name: 'This is ltr',
+        },
+        {
+          id: 4,
+          role: 'link',
+          htmlTag: 'a',
+          direction: 2,
+          url: 'http://www.google.com/',
+          childIds: [5],
+        },
+        {
+          id: 5,
+          role: 'staticText',
+          name: 'This link is rtl',
+        },
+      ],
+    };
+    chrome.readAnything.setContentForTesting(axTree, [2]);
+    const expected: string =
+        '<p dir="ltr">This is ltr<a dir="rtl" href="http://www.google.com/">This link is rtl</a></p>';
+    assertContainerInnerHTML(expected);
+  });
+
+  test('updateContent textDirection verticalDir', () => {
+    // root htmlTag='#document' id=1
+    // ++paragraph htmlTag='p' id=2 direction='ttb'
+    // ++++staticText name='This should be auto' id=3
+    // ++paragraph htmlTag='p' id=4 direction='btt'
+    // ++++staticText name='This should be also be auto' id=4
+    const axTree = {
+      rootId: 1,
+      nodes: [
+        {
+          id: 1,
+          role: 'rootWebArea',
+          htmlTag: '#document',
+          childIds: [2, 4],
+        },
+        {
+          id: 2,
+          role: 'paragraph',
+          htmlTag: 'p',
+          direction: 3,
+          childIds: [3],
+        },
+        {
+          id: 3,
+          role: 'staticText',
+          name: 'This should be auto',
+        },
+        {
+          id: 4,
+          role: 'paragraph',
+          htmlTag: 'p',
+          direction: 4,
+          childIds: [5],
+        },
+        {
+          id: 5,
+          role: 'staticText',
+          name: 'This should be also be auto',
+        },
+      ],
+    };
+    chrome.readAnything.setContentForTesting(axTree, [2, 4]);
+    const expected: string = '<p dir="auto">This should be auto</p>' +
+        '<p dir="auto">This should be also be auto</p>';
+    assertContainerInnerHTML(expected);
+  });
 });
diff --git a/chrome/test/data/webui/tab_strip/tab_list_test.ts b/chrome/test/data/webui/tab_strip/tab_list_test.ts
index d60ba37..e33c7cd 100644
--- a/chrome/test/data/webui/tab_strip/tab_list_test.ts
+++ b/chrome/test/data/webui/tab_strip/tab_list_test.ts
@@ -994,15 +994,15 @@
   });
 
   test('PreventsDraggingWhenOnlyOneTab', () => {
-    assertFalse(tabList.shouldPreventDrag());
+    assertFalse(tabList.shouldPreventDrag(/*isDraggingTab=*/ true));
     const tabElements = getUnpinnedTabs();
     tabElements[1]!.remove();
     tabElements[2]!.remove();
-    assertTrue(tabList.shouldPreventDrag());
+    assertTrue(tabList.shouldPreventDrag(/*isDraggingTab=*/ true));
   });
 
   test('PreventsDraggingWhenOnlyOneTabGroup', async () => {
-    // Create a tab group with 2 tabs.
+    // Create a tab group with 1 tab.
     const appendedTab = createTab({
       groupId: 'group0',
       id: 3,
@@ -1011,6 +1011,22 @@
     });
     callbackRouter.tabCreated(appendedTab);
     await flushTasks();
+
+    // Remove all tabs outside the tab group.
+    const tabElements = getUnpinnedTabs();
+    tabElements[0]!.remove();
+    tabElements[1]!.remove();
+    tabElements[2]!.remove();
+
+    // At this point there's only 1 tab in 1 tab group.
+
+    // Dragging a tab is not allowed.
+    assertTrue(tabList.shouldPreventDrag(/*isDraggingTab=*/ true));
+
+    // Dragging a tab group is not allowed.
+    assertTrue(tabList.shouldPreventDrag(/*isDraggingTab=*/ false));
+
+    // Add another tab in the same tab group.
     const appendedTabInSameGroup = createTab({
       groupId: 'group0',
       id: 4,
@@ -1019,13 +1035,13 @@
     });
     callbackRouter.tabCreated(appendedTabInSameGroup);
     await flushTasks();
-    assertFalse(tabList.shouldPreventDrag());
 
-    // Remove all tabs outside the tab group.
-    const tabElements = getUnpinnedTabs();
-    tabElements[0]!.remove();
-    tabElements[1]!.remove();
-    tabElements[2]!.remove();
-    assertTrue(tabList.shouldPreventDrag());
+    // At this point there are 2 tabs in 1 tab group;
+
+    // Dragging a tab is still allowed.
+    assertFalse(tabList.shouldPreventDrag(/*isDraggingTab=*/ true));
+
+    // Dragging a tab group is not allowed.
+    assertTrue(tabList.shouldPreventDrag(/*isDraggingTab=*/ false));
   });
 });
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 281a8b27..49f74e8f 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -214,10 +214,11 @@
   if (!test_provider_->HasRoutes())
     return;
 
-  // FIXME: There can't be a good reason to use the observer API to check for
-  // routes asynchronously, which is fragile.  However, some browser tests rely
-  // on this behavior.  Either add a callback parameter to TerminateRoute, or
-  // add pass callback to the TestProvider to run when all routes are gone.
+  // TODO(crbug.com/1374499): There can't be a good reason to use the observer
+  // API to check for routes asynchronously, which is fragile.  However, some
+  // browser tests rely on this behavior.  Either add a callback parameter to
+  // TerminateRoute, or add pass callback to the TestProvider to run when all
+  // routes are gone.
   base::RunLoop run_loop;
   NoRoutesObserver no_routes_observer(
       MediaRouterFactory::GetApiForBrowserContext(
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 91305ef..292dfef 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -369,9 +369,7 @@
   Uninstall();
 }
 
-// TODO(crbug.com/1345407): this test is disabled temporarily. Reenable after
-// the build that adds `IUpdater::FetchPolicies` is published to CIPD.
-TEST_F(IntegrationTest, DISABLED_OverinstallWorking) {
+TEST_F(IntegrationTest, OverinstallWorking) {
   SetupRealUpdaterLowerVersion();
   EXPECT_TRUE(WaitForUpdaterExit());
   ExpectVersionNotActive(kUpdaterVersion);
@@ -385,13 +383,7 @@
   Uninstall();
 }
 
-// TODO(crbug.com/1359334): Flaky on Win10.
-#if BUILDFLAG(IS_WIN)
-#define MAYBE_OverinstallBroken DISABLED_OverinstallBroken
-#else
-#define MAYBE_OverinstallBroken OverinstallBroken
-#endif
-TEST_F(IntegrationTest, MAYBE_OverinstallBroken) {
+TEST_F(IntegrationTest, OverinstallBroken) {
   SetupRealUpdaterLowerVersion();
   EXPECT_TRUE(WaitForUpdaterExit());
   DeleteUpdaterDirectory();
diff --git a/chromeos/metrics/login_event_recorder.cc b/chromeos/metrics/login_event_recorder.cc
index 388f6c339..b6cf00b 100644
--- a/chromeos/metrics/login_event_recorder.cc
+++ b/chromeos/metrics/login_event_recorder.cc
@@ -106,10 +106,6 @@
   total_hist->AddTime(total);
   std::string output =
       base::StringPrintf("%s: %.2f", uma_name.c_str(), total.InSecondsF());
-  if (uma_name == "BootTime.Login2" || uma_name == "BootTime.LoginNewUser") {
-    UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Tast.BootTime.Login2", total,
-                               base::Milliseconds(1), base::Seconds(300), 100);
-  }
   base::Time prev = first;
   // Convert base::Time to base::TimeTicks for tracing.
   auto time2timeticks = [](const base::Time& ts) {
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 0fc7416..59a3cae8 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-108-5335.0-1665395930-benchmark-108.0.5355.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-108-5335.0-1665395930-benchmark-108.0.5359.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index b8215a2..e3fc160 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-108-5335.0-1665395359-benchmark-108.0.5355.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-108-5335.0-1665395359-benchmark-108.0.5359.0-r1-redacted.afdo.xz
diff --git a/components/breadcrumbs/DIR_METADATA b/components/breadcrumbs/DIR_METADATA
new file mode 100644
index 0000000..030c855
--- /dev/null
+++ b/components/breadcrumbs/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>CrashReporting"
+}
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/AllSiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/AllSiteSettings.java
index 2b9eb67f..df41bc1 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/AllSiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/AllSiteSettings.java
@@ -398,7 +398,6 @@
     private boolean isNewAllSitesUiEnabled() {
         // Only in the "All sites" mode and with the flag enabled.
         return mCategory.getType() == SiteSettingsCategory.Type.ALL_SITES
-                && SiteSettingsFeatureList.isEnabled(
-                        SiteSettingsFeatureList.SITE_DATA_IMPROVEMENTS);
+                && SiteSettingsUtil.isSiteDataImprovementEnabled();
     }
 }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GroupedWebsitesSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GroupedWebsitesSettings.java
index 0d72530..7cd3d5c 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GroupedWebsitesSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GroupedWebsitesSettings.java
@@ -4,9 +4,7 @@
 
 package org.chromium.components.browser_ui.site_settings;
 
-import android.content.Context;
 import android.os.Bundle;
-import android.text.format.Formatter;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
@@ -81,12 +79,11 @@
 
     private void setUpClearDataPreference() {
         ClearWebsiteStorage preference = findPreference(PREF_CLEAR_DATA);
-        long usage = mSiteGroup.getTotalUsage();
-        if (usage > 0) {
-            Context context = preference.getContext();
-            preference.setTitle(
-                    String.format(context.getString(R.string.origin_settings_storage_usage_brief),
-                            Formatter.formatShortFileSize(context, usage)));
+        long storage = mSiteGroup.getTotalUsage();
+        int cookies = mSiteGroup.getNumberOfCookies();
+        if (storage > 0 || cookies > 0) {
+            preference.setTitle(SiteSettingsUtil.generateStorageUsageText(
+                    preference.getContext(), storage, cookies));
             // TODO(crbug.com/1342991): Get clearingApps information from underlying sites.
             preference.setDataForDisplay(mSiteGroup.getDomainAndRegistry(), /*clearingApps=*/false);
             // TODO(crbug.com/1342991): Disable the preference if all underlying origins have
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 85fb1f7..70235b23 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -524,13 +524,20 @@
     private void setUpClearDataPreference() {
         ClearWebsiteStorage preference = findPreference(PREF_CLEAR_DATA);
         long usage = mSite.getTotalUsage();
-        if (usage > 0) {
+        int cookies = mSite.getNumberOfCookies();
+        // Only take cookies into account when the new UI is enabled.
+        if (usage > 0 || (SiteSettingsUtil.isSiteDataImprovementEnabled() && cookies > 0)) {
             boolean appFound = getSiteSettingsDelegate().getOriginsWithInstalledApp().contains(
                     mSite.getAddress().getOrigin());
             Context context = preference.getContext();
-            preference.setTitle(
-                    String.format(context.getString(R.string.origin_settings_storage_usage_brief),
-                            Formatter.formatShortFileSize(context, usage)));
+            if (SiteSettingsUtil.isSiteDataImprovementEnabled()) {
+                preference.setTitle(
+                        SiteSettingsUtil.generateStorageUsageText(context, usage, cookies));
+            } else {
+                preference.setTitle(String.format(
+                        context.getString(R.string.origin_settings_storage_usage_brief),
+                        Formatter.formatShortFileSize(context, usage)));
+            }
             preference.setDataForDisplay(mSite.getTitle(), appFound);
             if (WebsitePreferenceBridge.isCookieDeletionDisabled(
                         getSiteSettingsDelegate().getBrowserContextHandle(),
@@ -545,7 +552,7 @@
     private void setupResetSitePreference() {
         Preference preference = findPreference(PREF_RESET_SITE);
         int titleResId;
-        if (SiteSettingsFeatureList.isEnabled(SiteSettingsFeatureList.SITE_DATA_IMPROVEMENTS)) {
+        if (SiteSettingsUtil.isSiteDataImprovementEnabled()) {
             titleResId = mHideNonPermissionPreferences ? R.string.page_info_permissions_reset
                                                        : R.string.website_reset_full;
         } else {
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
index aa5b7f5..3090b6a 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsUtil.java
@@ -4,6 +4,9 @@
 
 package org.chromium.components.browser_ui.site_settings;
 
+import android.content.Context;
+import android.text.format.Formatter;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
@@ -76,4 +79,34 @@
         }
         return ContentSettingsType.DEFAULT;
     }
+
+    /**
+     * @return whether the flag for the improved UI for "All sites" and "Site settings" is enabled.
+     */
+    public static boolean isSiteDataImprovementEnabled() {
+        return SiteSettingsFeatureList.isEnabled(SiteSettingsFeatureList.SITE_DATA_IMPROVEMENTS);
+    }
+
+    /**
+     * @param context A {@link Context} object to pull strings out of.
+     * @param storage The amount of storage (in bytes) used by the entry.
+     * @param cookies The number of cookies associated with the entry.
+     * @return A string to display in the UI to show and clear storage and cookies.
+     */
+    public static String generateStorageUsageText(Context context, long storage, int cookies) {
+        String result = "";
+        if (storage > 0) {
+            result = String.format(context.getString(R.string.origin_settings_storage_usage_brief),
+                    Formatter.formatShortFileSize(context, storage));
+        }
+        if (cookies > 0) {
+            String cookie_str = context.getResources().getQuantityString(
+                    R.plurals.cookies_count, cookies, cookies);
+            result = result.isEmpty()
+                    ? cookie_str
+                    : String.format(context.getString(R.string.summary_with_one_bullet), result,
+                            cookie_str);
+        }
+        return result;
+    }
 }
diff --git a/components/commerce/core/commerce_heuristics_data.cc b/components/commerce/core/commerce_heuristics_data.cc
index a07ddf14..d64b12e 100644
--- a/components/commerce/core/commerce_heuristics_data.cc
+++ b/components/commerce/core/commerce_heuristics_data.cc
@@ -18,6 +18,7 @@
 constexpr char kMerchantCartURLRegexType[] = "cart_url_regex";
 constexpr char kMerchantCheckoutURLRegexType[] = "checkout_url_regex";
 constexpr char kMerchantPurchaseURLRegexType[] = "purchase_url_regex";
+constexpr char kSkipAddToCartRegexType[] = "skip_add_to_cart_regex";
 
 // CommerceGlobalHeuristics types.
 constexpr char kSkipProductPatternType[] = "sensitive_product_regex";
@@ -90,6 +91,7 @@
   domain_cart_url_pattern_mapping_.clear();
   domain_checkout_url_pattern_mapping_.clear();
   domain_purchase_url_pattern_mapping_.clear();
+  domain_skip_add_to_cart_pattern_mapping_.clear();
   return true;
 }
 
@@ -177,6 +179,13 @@
                                         kMerchantPurchaseURLRegexType, domain);
 }
 
+const re2::RE2* CommerceHeuristicsData::GetSkipAddToCartPatternForDomain(
+    const std::string& domain) {
+  return GetCommerceHintHeuristicsRegex(
+      domain_skip_add_to_cart_pattern_mapping_, kSkipAddToCartRegexType,
+      domain);
+}
+
 std::string CommerceHeuristicsData::GetProductIDExtractionJSON() {
   return product_id_json_;
 }
diff --git a/components/commerce/core/commerce_heuristics_data.h b/components/commerce/core/commerce_heuristics_data.h
index ae9356c..49f4d9ab 100644
--- a/components/commerce/core/commerce_heuristics_data.h
+++ b/components/commerce/core/commerce_heuristics_data.h
@@ -88,6 +88,10 @@
   // `domain`.
   const re2::RE2* GetPurchasePageURLPatternForDomain(const std::string& domain);
 
+  // Try to get the pattern regex used to match against XHR request URL to see
+  // if the request should be ignored for AddToCart detection in `domain`.
+  const re2::RE2* GetSkipAddToCartPatternForDomain(const std::string& domain);
+
   // Get the JSON data with product ID extraction heuristics.
   std::string GetProductIDExtractionJSON();
 
@@ -132,6 +136,8 @@
       domain_checkout_url_pattern_mapping_;
   std::map<std::string, std::unique_ptr<re2::RE2>>
       domain_purchase_url_pattern_mapping_;
+  std::map<std::string, std::unique_ptr<re2::RE2>>
+      domain_skip_add_to_cart_pattern_mapping_;
   std::string product_id_json_;
   std::string cart_extraction_script_;
 };
diff --git a/components/commerce/core/commerce_heuristics_data_unittest.cc b/components/commerce/core/commerce_heuristics_data_unittest.cc
index 0ef8836f..04197e8e 100644
--- a/components/commerce/core/commerce_heuristics_data_unittest.cc
+++ b/components/commerce/core/commerce_heuristics_data_unittest.cc
@@ -21,7 +21,8 @@
               "checkout_url_regex" : "bar.com/([^/]+/)?checkout"
           },
           "baz.com": {
-              "purchase_url_regex" : "baz.com/([^/]+/)?purchase"
+              "purchase_url_regex" : "baz.com/([^/]+/)?purchase",
+              "skip_add_to_cart_regex": "dummy-request-url"
           }
       }
   )###";
@@ -95,6 +96,9 @@
   EXPECT_EQ(
       *hint_heuristics->FindDict("baz.com")->FindString("purchase_url_regex"),
       "baz.com/([^/]+/)?purchase");
+  EXPECT_EQ(*hint_heuristics->FindDict("baz.com")->FindString(
+                "skip_add_to_cart_regex"),
+            "dummy-request-url");
   auto* global_heuristics = GetGlobalHeuristics();
   EXPECT_EQ(global_heuristics->size(), 9u);
   EXPECT_TRUE(global_heuristics->contains("sensitive_product_regex"));
@@ -271,6 +275,16 @@
             "baz.com/([^/]+/)?purchase");
 }
 
+TEST_F(CommerceHeuristicsDataTest, TestGetSkipAddToCartPatternForDomain) {
+  auto& data = commerce_heuristics::CommerceHeuristicsData::GetInstance();
+
+  ASSERT_TRUE(data.PopulateDataFromComponent(
+      kHintHeuristicsJSONData, kGlobalHeuristicsJSONData, "", ""));
+
+  EXPECT_EQ(data.GetSkipAddToCartPatternForDomain("baz.com")->pattern(),
+            "dummy-request-url");
+}
+
 TEST_F(CommerceHeuristicsDataTest, TestRepopulateHintData) {
   auto& data = commerce_heuristics::CommerceHeuristicsData::GetInstance();
 
diff --git a/components/drive/OWNERS b/components/drive/OWNERS
index 4ad89d4..6f2bdb8f 100644
--- a/components/drive/OWNERS
+++ b/components/drive/OWNERS
@@ -1,5 +1 @@
-# Primary
 file://chrome/browser/sync_file_system/OWNERS
-
-# Secondary
-file://ash/projector/OWNERS
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 9ee52ae0..067fe06 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -67,13 +67,8 @@
 
 bool SameLocation(const gfx::PointF& location_in_target,
                   const gfx::PointF& location) {
-  // In general, it is good practice to compare floats using an epsilon.
-  // In particular, the mouse location_f() could differ between the
-  // MOUSE_PRESSED and MOUSE_RELEASED events. At MOUSE_RELEASED, it will have a
-  // targeter() already cached, while at MOUSE_PRESSED, it will have to
-  // calculate it passing through all the hierarchy of windows, and that could
-  // generate rounding error. std::numeric_limits<float>::epsilon() is not big
-  // enough to catch this rounding error.
+  // TODO(crbug.com/1354573): This is no longer necessary.  Switch to
+  // std::numeric_limits<float>::eplison().
   gfx::Vector2dF offset = location_in_target - location;
   return offset.LengthSquared() < (2 * kLocatedEventEpsilonSquared);
 }
@@ -381,7 +376,8 @@
   aura::Env::GetInstance()->AddPreTargetHandler(
       this, ui::EventTarget::Priority::kSystem);
 
-  location_when_pointer_capture_enabled_ = gfx::ToRoundedPoint(location_);
+  location_when_pointer_capture_enabled_ =
+      gfx::ToRoundedPoint(location_in_root_);
 
   if (ShouldMoveToCenter())
     MoveCursorToCenterOfActiveDisplay();
@@ -464,7 +460,7 @@
   }
 
   if (surface == focus_surface_) {
-    SetFocus(nullptr, gfx::PointF(), 0);
+    SetFocus(nullptr, gfx::PointF(), gfx::PointF(), 0);
     was_correctly_subscribed = true;
   } else if (surface == root_surface()) {
     UpdatePointerSurface(nullptr);
@@ -488,12 +484,13 @@
 
   gfx::PointF location_in_target;
   Surface* target = GetEffectiveTargetForEvent(event, &location_in_target);
+  gfx::PointF location_in_root = event->root_location_f();
 
   // Update focus if target is different than the current pointer focus.
-  if (target != focus_surface_)
-    SetFocus(target, location_in_target, event->button_flags());
-
-  gfx::PointF location_in_root = GetLocationInRoot(target, location_in_target);
+  if (target != focus_surface_) {
+    SetFocus(target, location_in_root, location_in_target,
+             event->button_flags());
+  }
 
   if (!focus_surface_)
     return;
@@ -516,9 +513,9 @@
     // so to avoid generating mouse event jitter we consider the location of
     // these events to be the same as |location| if floored values match.
     bool same_location = !event->IsSynthesized()
-                             ? SameLocation(location_in_root, location_)
+                             ? SameLocation(location_in_root, location_in_root_)
                              : gfx::ToFlooredPoint(location_in_root) ==
-                                   gfx::ToFlooredPoint(location_);
+                                   gfx::ToFlooredPoint(location_in_root_);
 
     // Ordinal motion is sent only on platforms that support it, which is
     // indicated by the presence of a flag.
@@ -561,7 +558,7 @@
       }
       if (needs_frame)
         delegate_->OnPointerFrame();
-      location_ = location_in_root;
+      location_in_root_ = location_in_root;
     }
   }
   switch (event->type()) {
@@ -717,7 +714,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // aura::client::DragDropClientObserver overrides:
 void Pointer::OnDragStarted() {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Drag 'n drop operations driven by sources different than pointer/mouse
   // should have not effect here.
   WMHelper* helper = WMHelper::GetInstance();
@@ -727,12 +723,10 @@
       return;
   }
 
-  SetFocus(nullptr, gfx::PointF(), 0);
-#endif
+  SetFocus(nullptr, gfx::PointF(), gfx::PointF(), 0);
 }
 
 void Pointer::OnDragCompleted(const ui::DropTargetEvent& event) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Drag 'n drop operations driven by sources different than pointer/mouse
   // should have not effect here.
   WMHelper* helper = WMHelper::GetInstance();
@@ -757,9 +751,10 @@
 
   gfx::PointF location_in_target;
   auto* target = GetEffectiveTargetForEvent(&event, &location_in_target);
-  if (target)
-    SetFocus(target, location_in_target, /*button_flags=*/0);
-#endif
+  if (target) {
+    SetFocus(target, event.root_location_f(), location_in_target,
+             /*button_flags=*/0);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -836,7 +831,8 @@
 }
 
 void Pointer::SetFocus(Surface* surface,
-                       const gfx::PointF& location,
+                       const gfx::PointF& root_location,
+                       const gfx::PointF& surface_location,
                        int button_flags) {
   DCHECK(!surface || delegate_->CanAcceptPointerEventsForSurface(surface));
   // First generate a leave event if we currently have a target in focus.
@@ -852,9 +848,9 @@
   }
   // Second generate an enter event if focus moved to a new surface.
   if (surface) {
-    delegate_->OnPointerEnter(surface, location, button_flags);
+    delegate_->OnPointerEnter(surface, surface_location, button_flags);
     delegate_->OnPointerFrame();
-    location_ = GetLocationInRoot(surface, location);
+    location_in_root_ = root_location;
     focus_surface_ = surface;
     if (!focus_surface_->HasSurfaceObserver(this))
       focus_surface_->AddSurfaceObserver(this);
@@ -996,23 +992,13 @@
   }
 }
 
-gfx::PointF Pointer::GetLocationInRoot(Surface* target,
-                                       gfx::PointF location_in_target) {
-  if (!target || !target->window())
-    return location_in_target;
-  aura::Window* w = target->window();
-  gfx::PointF p(location_in_target.x(), location_in_target.y());
-  aura::Window::ConvertPointToTarget(w, w->GetRootWindow(), &p);
-  return gfx::PointF(p.x(), p.y());
-}
-
 bool Pointer::ShouldMoveToCenter() {
   if (!capture_window_)
     return false;
 
   gfx::Rect rect = capture_window_->GetRootWindow()->bounds();
   rect.Inset(gfx::Insets::VH(rect.height() / 6, rect.width() / 6));
-  return !rect.Contains(location_.x(), location_.y());
+  return !rect.Contains(location_in_root_.x(), location_in_root_.y());
 }
 
 void Pointer::MoveCursorToCenterOfActiveDisplay() {
@@ -1031,7 +1017,7 @@
   if (!relative_pointer_delegate_)
     return false;
 
-  gfx::Vector2dF delta = location_in_root - location_;
+  gfx::Vector2dF delta = location_in_root - location_in_root_;
   relative_pointer_delegate_->OnPointerRelativeMotion(
       time_stamp, delta,
       ordinal_motion.has_value() ? ordinal_motion.value() : delta);
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 20f92d9..099bc00 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -157,7 +157,8 @@
 
   // Change pointer focus to |surface|.
   void SetFocus(Surface* surface,
-                const gfx::PointF& location,
+                const gfx::PointF& root_location,
+                const gfx::PointF& surface_location,
                 int button_flags);
 
   // Updates the root_surface in |SurfaceTreeHost| from which the cursor
@@ -175,10 +176,6 @@
   // Update |cursor_| to |cursor_bitmap_| transformed for the current display.
   void UpdateCursor();
 
-  // Convert the given |location_in_target| to coordinates in the root window.
-  gfx::PointF GetLocationInRoot(Surface* target,
-                                gfx::PointF location_in_target);
-
   // Called to check if cursor should be moved to the center of the window when
   // sending relative movements.
   bool ShouldMoveToCenter();
@@ -225,8 +222,8 @@
   // The current focus surface for the pointer.
   Surface* focus_surface_ = nullptr;
 
-  // The location of the pointer in the current focus surface.
-  gfx::PointF location_;
+  // The location of the pointer in the root window.
+  gfx::PointF location_in_root_;
 
   // The location of the pointer when pointer capture is first enabled.
   absl::optional<gfx::Point> location_when_pointer_capture_enabled_;
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 63c5e6e2..d5b4a9fc 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -9,7 +9,6 @@
 #include "ash/constants/ash_constants.h"
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/frame/non_client_frame_view_ash.h"
-#include "ash/metrics/login_unlock_throughput_recorder.h"
 #include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/rounded_corner_utils.h"
 #include "ash/public/cpp/shelf_types.h"
@@ -653,9 +652,6 @@
   DCHECK(!widget_);
   restore_session_id_.emplace(restore_session_id);
   restore_window_id_.emplace(restore_window_id);
-  ash::LoginUnlockThroughputRecorder* throughput_recorder =
-      ash::Shell::Get()->login_unlock_throughput_recorder();
-  throughput_recorder->OnRestoredWindowCreated(restore_window_id);
 }
 
 void ShellSurfaceBase::SetRestoreInfoWithWindowIdSource(
@@ -1812,17 +1808,6 @@
       needs_layout_on_show_ = false;
     }
 
-    if (restore_window_id_.has_value()) {
-      ash::LoginUnlockThroughputRecorder* throughput_recorder =
-          ash::Shell::Get()->login_unlock_throughput_recorder();
-
-      aura::Window* root_window = host_window()->GetRootWindow();
-      if (root_window) {
-        ui::Compositor* compositor = root_window->layer()->GetCompositor();
-        throughput_recorder->OnBeforeRestoredWindowShown(
-            restore_window_id_.value(), compositor);
-      }
-    }
     widget_->Show();
     if (has_grab_)
       StartCapture();
diff --git a/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc b/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
index f8e6392a..e3c03194 100644
--- a/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
@@ -224,6 +224,9 @@
       "ContentSuggestions.Feed.WebFeed.FollowCount.AfterFollow", 1, 1);
   histograms.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.NewFollow.IsRecommended", 0, 1);
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.WebFeed.NewFollow.ChangeReason",
+      WebFeedChangeReason::WEB_PAGE_MENU, 1);
 }
 
 TEST_F(FeedApiSubscriptionsTest, FollowWebFeedAbortOnClearAll) {
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc
index c0dc933..941d52e2 100644
--- a/components/feed/core/v2/metrics_reporter.cc
+++ b/components/feed/core/v2/metrics_reporter.cc
@@ -1102,6 +1102,14 @@
     base::UmaHistogramBoolean(
         "ContentSuggestions.Feed.WebFeed.NewFollow.IsRecommended",
         result.web_feed_metadata.is_recommended);
+    if (result.change_reason) {
+      // Because WebFeedChangeReason_MAX is not an enum value, we can't use
+      // UmaHistogramEnumeration, but UmaHistogramExactLinear is equivalent.
+      base::UmaHistogramExactLinear(
+          "ContentSuggestions.Feed.WebFeed.NewFollow.ChangeReason",
+          static_cast<int>(result.change_reason),
+          feedwire::webfeed::WebFeedChangeReason_MAX + 1);
+    }
   }
 }
 
diff --git a/components/feed/core/v2/public/web_feed_subscriptions.h b/components/feed/core/v2/public/web_feed_subscriptions.h
index 033f6211..02cac4c5 100644
--- a/components/feed/core/v2/public/web_feed_subscriptions.h
+++ b/components/feed/core/v2/public/web_feed_subscriptions.h
@@ -24,6 +24,8 @@
     WebFeedMetadata web_feed_metadata;
     // Number of subscriptions the user has after the Follow operation.
     int subscription_count = 0;
+    // The change reason from the request.
+    feedwire::webfeed::WebFeedChangeReason change_reason;
   };
   // Follow a web feed given information about a web page. Calls `callback` when
   // complete. The callback parameter reports whether the url is now considered
diff --git a/components/feed/core/v2/web_feed_subscription_coordinator.cc b/components/feed/core/v2/web_feed_subscription_coordinator.cc
index 0770071..f6eaafb 100644
--- a/components/feed/core/v2/web_feed_subscription_coordinator.cc
+++ b/components/feed/core/v2/web_feed_subscription_coordinator.cc
@@ -304,6 +304,7 @@
       index_.IsRecommended(result.followed_web_feed_id);
   callback_result.request_status = result.request_status;
   callback_result.subscription_count = index_.SubscriptionCount();
+  callback_result.change_reason = result.change_reason;
   feed_stream_->GetMetricsReporter().OnFollowAttempt(followed_with_id,
                                                      callback_result);
   std::move(callback).Run(std::move(callback_result));
diff --git a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
index 8785fa0b..fcf87c74 100644
--- a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
+++ b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
@@ -108,6 +108,7 @@
   result.request_status = status;
   result.web_feed_info = subscribed_web_feed_info_;
   result.followed_web_feed_id = subscribed_web_feed_info_.web_feed_id();
+  result.change_reason = request_.change_reason;
   std::move(callback_).Run(std::move(result));
   TaskComplete();
 }
diff --git a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
index fb362bd8..b2ff2fb 100644
--- a/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
+++ b/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
@@ -26,7 +26,7 @@
     WebFeedPageInformation page_info;
     std::string web_feed_id;
     feedwire::webfeed::WebFeedChangeReason change_reason = feedwire::webfeed::
-        WebFeedChangeReason ::WEB_FEED_CHANGE_REASON_UNSPECIFIED;
+        WebFeedChangeReason::WEB_FEED_CHANGE_REASON_UNSPECIFIED;
     // Whether the subscription request will be stored and retried if failed.
     bool durable = false;
   };
@@ -37,6 +37,9 @@
     // is its ID.
     std::string followed_web_feed_id;
     feedstore::WebFeedInfo web_feed_info;
+    // The change reason from the request.
+    feedwire::webfeed::WebFeedChangeReason change_reason = feedwire::webfeed::
+        WebFeedChangeReason::WEB_FEED_CHANGE_REASON_UNSPECIFIED;
   };
   SubscribeToWebFeedTask(FeedStream* stream,
                          const OperationToken& operation_token,
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc
index e3fbe7a..527974c 100644
--- a/components/feed/feed_feature_list.cc
+++ b/components/feed/feed_feature_list.cc
@@ -73,6 +73,9 @@
 BASE_FEATURE(kReliabilityLogging,
              "FeedReliabilityLogging",
              base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kFeedHeaderStickToTop,
+             "FeedHeaderStickToTop",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kFeedInteractiveRefresh,
              "FeedInteractiveRefresh",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h
index 332bf065..edce9f13 100644
--- a/components/feed/feed_feature_list.h
+++ b/components/feed/feed_feature_list.h
@@ -57,6 +57,9 @@
 // Whether to log reliability events.
 BASE_DECLARE_FEATURE(kReliabilityLogging);
 
+// Feature that enables sticky header when users scroll down.
+BASE_DECLARE_FEATURE(kFeedHeaderStickToTop);
+
 // Feature that enables refreshing feeds triggered by the users.
 BASE_DECLARE_FEATURE(kFeedInteractiveRefresh);
 
diff --git a/components/guest_view/renderer/guest_view_container.cc b/components/guest_view/renderer/guest_view_container.cc
index 6a214a9..889d4c0 100644
--- a/components/guest_view/renderer/guest_view_container.cc
+++ b/components/guest_view/renderer/guest_view_container.cc
@@ -173,8 +173,9 @@
       return;
 
     v8::Context::Scope context_scope(context);
-    v8::MicrotasksScope microtasks(
-        destruction_isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks);
+    v8::MicrotasksScope microtasks(destruction_isolate_,
+                                   context->GetMicrotaskQueue(),
+                                   v8::MicrotasksScope::kDoNotRunMicrotasks);
 
     callback->Call(context, context->Global(), 0 /* argc */, nullptr)
         .FromMaybe(v8::Local<v8::Value>());
@@ -242,8 +243,9 @@
       v8::Integer::New(element_resize_isolate_, new_size.height())};
 
   v8::Context::Scope context_scope(context);
-  v8::MicrotasksScope microtasks(
-      element_resize_isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks);
+  v8::MicrotasksScope microtasks(element_resize_isolate_,
+                                 context->GetMicrotaskQueue(),
+                                 v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   callback->Call(context, context->Global(), argc, argv)
       .FromMaybe(v8::Local<v8::Value>());
diff --git a/components/guest_view/renderer/guest_view_request.cc b/components/guest_view/renderer/guest_view_request.cc
index 00443c3..2816577 100644
--- a/components/guest_view/renderer/guest_view_request.cc
+++ b/components/guest_view/renderer/guest_view_request.cc
@@ -80,7 +80,7 @@
     return;
 
   v8::Context::Scope context_scope(context);
-  v8::MicrotasksScope microtasks(isolate_,
+  v8::MicrotasksScope microtasks(isolate_, context->GetMicrotaskQueue(),
                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   callback->Call(context, context->Global(), argc, argv.get())
diff --git a/components/history/core/browser/expire_history_backend.cc b/components/history/core/browser/expire_history_backend.cc
index 785d36e..6a286cad 100644
--- a/components/history/core/browser/expire_history_backend.cc
+++ b/components/history/core/browser/expire_history_backend.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <functional>
 #include <limits>
 #include <memory>
@@ -21,6 +20,7 @@
 #include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "components/favicon/core/favicon_database.h"
@@ -262,10 +262,8 @@
   // `times` must be in reverse chronological order and have no
   // duplicates, i.e. each member must be earlier than the one before
   // it.
-  DCHECK(
-      std::adjacent_find(
-          times.begin(), times.end(), std::less_equal<base::Time>()) ==
-      times.end());
+  DCHECK(base::ranges::adjacent_find(times, std::less_equal<base::Time>()) ==
+         times.end());
 
   if (!main_db_)
     return;
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index 4751673..37f9fd86 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -50,6 +50,10 @@
              "EnableImageSearchSidePanelFor3PDse",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kLensRegionSearchStaticPage,
+             "LensRegionSearchStaticPage",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch{
     &kLensStandalone, "region-search-enable-ukm-logging", true};
 
@@ -221,5 +225,9 @@
   return kEnablePersistentBubble.Get();
 }
 
+bool IsLensRegionSearchStaticPageEnabled() {
+  return base::FeatureList::IsEnabled(kLensRegionSearchStaticPage);
+}
+
 }  // namespace features
 }  // namespace lens
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 5ec19da..cb31a61 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -44,6 +44,9 @@
 // engines
 BASE_DECLARE_FEATURE(kEnableImageSearchSidePanelFor3PDse);
 
+// Enables launching the region search experience in a new tab with WebUI.
+BASE_DECLARE_FEATURE(kLensRegionSearchStaticPage);
+
 // Enables using `Google` as the visual search provider instead of `Google
 // Lens`.
 extern const base::FeatureParam<bool> kUseGoogleAsVisualSearchProvider;
@@ -174,6 +177,9 @@
 
 // Returns whether we should use an alternative instruction chip string.
 extern bool UseAltChipString();
+
+// Returns whether we should use a WebUI static page for region search.
+extern bool IsLensRegionSearchStaticPageEnabled();
 }  // namespace features
 }  // namespace lens
 
diff --git a/components/local_state/DIR_METADATA b/components/local_state/DIR_METADATA
new file mode 100644
index 0000000..1c5b27e
--- /dev/null
+++ b/components/local_state/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Metrics>Variations"
+}
+
+team_email: "chromium-dev@chromium.org"
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc
index f7cdcbd..6347206 100644
--- a/components/omnibox/browser/in_memory_url_index_unittest.cc
+++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -7,7 +7,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <algorithm>
 #include <fstream>
 #include <memory>
 #include <numeric>
@@ -21,6 +20,7 @@
 #include "base/i18n/case_conversion.h"
 #include "base/memory/raw_ptr.h"
 #include "base/path_service.h"
+#include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -723,9 +723,8 @@
 
   // Each next group should fill almost everything, while the previous group
   // should occupy what's left.
-  auto* error_position = std::adjacent_find(
-      std::begin(item_groups), std::end(item_groups),
-      [&](const ItemGroup& previous, const ItemGroup& current) {
+  auto* error_position = base::ranges::adjacent_find(
+      item_groups, [&](const ItemGroup& previous, const ItemGroup& current) {
         auto ids = GetHistoryIdsUpTo(current.max_id);
         EXPECT_TRUE(GetPrivateData()->TrimHistoryIdsPool(&ids));
 
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc
index f853e91d..bb2c625f 100644
--- a/components/omnibox/browser/scored_history_match.cc
+++ b/components/omnibox/browser/scored_history_match.cc
@@ -6,13 +6,13 @@
 
 #include <math.h>
 
-#include <algorithm>
 #include <utility>
 #include <vector>
 
 #include "base/check_op.h"
 #include "base/no_destructor.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -634,11 +634,8 @@
   auto visits_end =
       visits.begin() + std::min(visits.size(), max_visits_to_score_);
   // Visits should be in newest to oldest order.
-  DCHECK(std::adjacent_find(
-             visits.begin(), visits_end,
-             [](const history::VisitInfo& a, const history::VisitInfo& b) {
-               return a.first < b.first;
-             }) == visits_end);
+  DCHECK(base::ranges::adjacent_find(visits.begin(), visits_end, std::less<>(),
+                                     &history::VisitInfo::first) == visits_end);
   for (auto i = visits.begin(); i != visits_end; ++i) {
     const bool is_page_transition_typed =
         ui::PageTransitionCoreTypeIs(i->second, ui::PAGE_TRANSITION_TYPED);
diff --git a/components/password_manager/core/browser/generation/password_generator.cc b/components/password_manager/core/browser/generation/password_generator.cc
index 5aec52d..d6544e0f 100644
--- a/components/password_manager/core/browser/generation/password_generator.cc
+++ b/components/password_manager/core/browser/generation/password_generator.cc
@@ -4,7 +4,6 @@
 
 #include "components/password_manager/core/browser/generation/password_generator.h"
 
-#include <algorithm>
 #include <limits>
 #include <map>
 #include <utility>
@@ -12,6 +11,7 @@
 
 #include "base/check.h"
 #include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/proto/password_requirements.pb.h"
 
@@ -80,10 +80,9 @@
 // sequences of '-' or '_' that are joined into long strokes on the screen
 // in many fonts.
 bool IsDifficultToRead(const std::u16string& password) {
-  return std::adjacent_find(password.begin(), password.end(),
-                            [](auto a, auto b) {
-                              return a == b && (a == '-' || a == '_');
-                            }) != password.end();
+  return base::ranges::adjacent_find(password, [](auto a, auto b) {
+           return a == b && (a == '-' || a == '_');
+         }) != password.end();
 }
 
 // Generates a password according to |spec| and tries to maximze the entropy
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 24294f8..f33819af 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -384,10 +384,11 @@
 
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
-  v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Context> context = frame_->MainWorldScriptContext();
   DCHECK(!context.IsEmpty());
+  v8::MicrotasksScope microtasks_scope(
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   v8::Context::Scope context_scope(context);
   v8::Local<v8::Object> global = context->Global();
diff --git a/components/security_interstitials/content/renderer/security_interstitial_page_controller.cc b/components/security_interstitials/content/renderer/security_interstitial_page_controller.cc
index 79ecbcbc..fc0d72f4 100644
--- a/components/security_interstitials/content/renderer/security_interstitial_page_controller.cc
+++ b/components/security_interstitials/content/renderer/security_interstitial_page_controller.cc
@@ -24,13 +24,14 @@
     content::RenderFrame* render_frame) {
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
-  v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Context> context =
       render_frame->GetWebFrame()->MainWorldScriptContext();
   if (context.IsEmpty())
     return;
 
+  v8::MicrotasksScope microtasks_scope(
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Context::Scope context_scope(context);
 
   gin::Handle<SecurityInterstitialPageController> controller =
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index 42e0b316..41f925f25 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -56,6 +56,10 @@
              "SyncResetPollIntervalOnStart",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kSyncSegmentationDataType,
+             "SyncSegmentationDataType",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kSyncSendInterestedDataTypes,
              "SyncSendInterestedDataTypes",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index ab9dc96..fbdeac4 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -72,6 +72,9 @@
 
 BASE_DECLARE_FEATURE(kSyncResetPollIntervalOnStart);
 
+// If enabled, Segmentation data type will be synced.
+BASE_DECLARE_FEATURE(kSyncSegmentationDataType);
+
 // If enabled, interested data types, excluding Wallet and Offer, will be sent
 // to the Sync Server as part of DeviceInfo.
 BASE_DECLARE_FEATURE(kSyncSendInterestedDataTypes);
diff --git a/components/sync/base/model_type.cc b/components/sync/base/model_type.cc
index a9ceb99..c0eaae1 100644
--- a/components/sync/base/model_type.cc
+++ b/components/sync/base/model_type.cc
@@ -73,8 +73,8 @@
      "Autofill Wallet Offer",
      sync_pb::EntitySpecifics::kAutofillOfferFieldNumber,
      ModelTypeForHistograms::kAutofillWalletOffer},
-    {AUTOFILL_WALLET_USAGE, "AUTOFILL_WALLET_USAGE",
-     "autofill_wallet_usage", "Autofill Wallet Usage",
+    {AUTOFILL_WALLET_USAGE, "AUTOFILL_WALLET_USAGE", "autofill_wallet_usage",
+     "Autofill Wallet Usage",
      sync_pb::EntitySpecifics::kAutofillWalletUsageFieldNumber,
      ModelTypeForHistograms::kAutofillWalletUsage},
     {THEMES, "THEME", "themes", "Themes",
@@ -137,6 +137,9 @@
     {USER_CONSENTS, "USER_CONSENT", "user_consent", "User Consents",
      sync_pb::EntitySpecifics::kUserConsentFieldNumber,
      ModelTypeForHistograms::kUserConsents},
+    {SEGMENTATION, "SEGMENTATION", "segmentation", "Segmentation",
+     sync_pb::EntitySpecifics::kSegmentationFieldNumber,
+     ModelTypeForHistograms::kSegmentation},
     {SEND_TAB_TO_SELF, "SEND_TAB_TO_SELF", "send_tab_to_self",
      "Send Tab To Self", sync_pb::EntitySpecifics::kSendTabToSelfFieldNumber,
      ModelTypeForHistograms::kSendTabToSelf},
@@ -184,7 +187,7 @@
 static_assert(std::size(kModelTypeInfoMap) == GetNumModelTypes(),
               "kModelTypeInfoMap should have GetNumModelTypes() elements");
 
-static_assert(42 == syncer::GetNumModelTypes(),
+static_assert(43 == syncer::GetNumModelTypes(),
               "When adding a new type, update enum SyncModelTypes in enums.xml "
               "and suffix SyncModelType in histograms.xml.");
 
@@ -318,6 +321,9 @@
     case CONTACT_INFO:
       specifics->mutable_contact_info();
       break;
+    case SEGMENTATION:
+      specifics->mutable_segmentation();
+      break;
   }
 }
 
@@ -348,7 +354,7 @@
 }
 
 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
-  static_assert(42 == syncer::GetNumModelTypes(),
+  static_assert(43 == syncer::GetNumModelTypes(),
                 "When adding new protocol types, the following type lookup "
                 "logic must be updated.");
   if (specifics.has_bookmark())
@@ -431,6 +437,8 @@
     return CONTACT_INFO;
   if (specifics.has_autofill_wallet_usage())
     return AUTOFILL_WALLET_USAGE;
+  if (specifics.has_segmentation())
+    return SEGMENTATION;
 
   // This client version doesn't understand |specifics|.
   DVLOG(1) << "Unknown datatype in sync proto.";
@@ -438,7 +446,7 @@
 }
 
 ModelTypeSet EncryptableUserTypes() {
-  static_assert(42 == syncer::GetNumModelTypes(),
+  static_assert(43 == syncer::GetNumModelTypes(),
                 "If adding an unencryptable type, remove from "
                 "encryptable_user_types below.");
   ModelTypeSet encryptable_user_types = UserTypes();
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index ed145e8..0e2e0149 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -112,6 +112,8 @@
   USER_EVENTS,
   // Commit only user consents.
   USER_CONSENTS,
+  // Segmentation data.
+  SEGMENTATION,
   // Tabs sent between devices.
   SEND_TAB_TO_SELF,
   // Commit only security events.
@@ -238,7 +240,8 @@
   kPrintersAuthorizationServers = 52,
   kContactInfo = 53,
   kAutofillWalletUsage = 54,
-  kMaxValue = kAutofillWalletUsage
+  kSegmentation = 55,
+  kMaxValue = kSegmentation
 };
 
 // Used to mark the type of EntitySpecifics that has no actual data.
diff --git a/components/sync/base/user_selectable_type.cc b/components/sync/base/user_selectable_type.cc
index 76bbe59..96cf28bd 100644
--- a/components/sync/base/user_selectable_type.cc
+++ b/components/sync/base/user_selectable_type.cc
@@ -33,7 +33,7 @@
 constexpr char kWifiConfigurationsTypeName[] = "wifiConfigurations";
 
 UserSelectableTypeInfo GetUserSelectableTypeInfo(UserSelectableType type) {
-  static_assert(42 == syncer::GetNumModelTypes(),
+  static_assert(43 == syncer::GetNumModelTypes(),
                 "Almost always when adding a new ModelType, you must tie it to "
                 "a UserSelectableType below (new or existing) so the user can "
                 "disable syncing of that data. Today you must also update the "
@@ -45,9 +45,12 @@
     case UserSelectableType::kBookmarks:
       return {kBookmarksTypeName, BOOKMARKS, {BOOKMARKS}};
     case UserSelectableType::kPreferences:
+      // TODO(crbug.com/1369259): Add GetPreconditionState() logic to check
+      // history state as a precondition for SEGMENTATION.
       return {kPreferencesTypeName,
               PREFERENCES,
-              {PREFERENCES, DICTIONARY, PRIORITY_PREFERENCES, SEARCH_ENGINES}};
+              {PREFERENCES, DICTIONARY, PRIORITY_PREFERENCES, SEARCH_ENGINES,
+               SEGMENTATION}};
     case UserSelectableType::kPasswords:
       return {kPasswordsTypeName, PASSWORDS, {PASSWORDS}};
     case UserSelectableType::kAutofill:
diff --git a/components/sync/driver/sync_user_settings_impl.cc b/components/sync/driver/sync_user_settings_impl.cc
index 57254a2..3c1b2c87 100644
--- a/components/sync/driver/sync_user_settings_impl.cc
+++ b/components/sync/driver/sync_user_settings_impl.cc
@@ -268,7 +268,7 @@
 #endif
   types.RetainAll(registered_model_types_);
 
-  static_assert(42 == GetNumModelTypes(),
+  static_assert(43 == GetNumModelTypes(),
                 "If adding a new sync data type, update the list below below if"
                 " you want to disable the new data type for local sync.");
   types.PutAll(ControlTypes());
@@ -277,6 +277,7 @@
     types.Remove(AUTOFILL_WALLET_OFFER);
     types.Remove(AUTOFILL_WALLET_USAGE);
     types.Remove(SECURITY_EVENTS);
+    types.Remove(SEGMENTATION);
     types.Remove(SEND_TAB_TO_SELF);
     types.Remove(SHARING_MESSAGE);
     types.Remove(USER_CONSENTS);
diff --git a/components/sync/engine/cycle/data_type_tracker.cc b/components/sync/engine/cycle/data_type_tracker.cc
index 790a92a..106f205 100644
--- a/components/sync/engine/cycle/data_type_tracker.cc
+++ b/components/sync/engine/cycle/data_type_tracker.cc
@@ -30,6 +30,9 @@
 constexpr base::TimeDelta kDefaultLocalChangeNudgeDelayForSessions =
     base::Seconds(11);
 
+constexpr base::TimeDelta kDefaultLocalChangeNudgeDelayForSegmentations =
+    base::Seconds(11);
+
 // Nudge delay for remote invalidations. Common to all data types.
 constexpr base::TimeDelta kRemoteInvalidationDelay = base::Milliseconds(250);
 
@@ -56,6 +59,11 @@
       // custom nudge delay, tuned for a reasonable trade-off between traffic
       // and freshness.
       return kDefaultLocalChangeNudgeDelayForSessions;
+    case SEGMENTATION:
+      // There are multiple segmentations computed during start-up within
+      // seconds. Applies a custom nudge delay, so that they are batched into
+      // one commit.
+      return kDefaultLocalChangeNudgeDelayForSegmentations;
     case BOOKMARKS:
     case PREFERENCES:
       // Types with sometimes automatic changes get longer delays to allow more
@@ -146,6 +154,7 @@
     case PRINTERS_AUTHORIZATION_SERVERS:
     case READING_LIST:
     case USER_CONSENTS:
+    case SEGMENTATION:
     case SEND_TAB_TO_SELF:
     case SECURITY_EVENTS:
     case WIFI_CONFIGURATIONS:
diff --git a/components/sync/protocol/proto_value_conversions.cc b/components/sync/protocol/proto_value_conversions.cc
index 26361e5..f4bb0d8 100644
--- a/components/sync/protocol/proto_value_conversions.cc
+++ b/components/sync/protocol/proto_value_conversions.cc
@@ -138,12 +138,14 @@
   void VisitBytes(const P& parent_proto,
                   const char* field_name,
                   const std::string& field) {
-    value_->Set(field_name, BytesToValue(field));
+    value_->GetDict().Set(
+        field_name,
+        base::Base64Encode(base::as_bytes(base::make_span(field))));
   }
 
   template <class P, class E>
   void VisitEnum(const P& parent_proto, const char* field_name, E field) {
-    value_->Set(field_name, EnumToValue(field));
+    value_->GetDict().Set(field_name, ProtoEnumToString(field));
   }
 
   template <class P, class F>
@@ -155,7 +157,7 @@
       for (const auto& field : repeated_field) {
         list.Append(base::Value::FromUniquePtrValue(ToValue(field)));
       }
-      value_->Set(field_name, std::make_unique<base::Value>(std::move(list)));
+      value_->GetDict().Set(field_name, std::move(list));
     }
   }
 
@@ -168,7 +170,7 @@
       for (const auto& field : repeated_field) {
         list.Append(base::Value::FromUniquePtrValue(ToValue(field)));
       }
-      value_->Set(field_name, std::make_unique<base::Value>(std::move(list)));
+      value_->GetDict().Set(field_name, std::move(list));
     }
   }
 
@@ -260,17 +262,6 @@
     return value;
   }
 
-  static std::unique_ptr<base::Value> BytesToValue(const std::string& bytes) {
-    std::string bytes_base64;
-    base::Base64Encode(bytes, &bytes_base64);
-    return std::make_unique<base::Value>(bytes_base64);
-  }
-
-  template <class E>
-  static std::unique_ptr<base::Value> EnumToValue(E value) {
-    return std::make_unique<base::Value>(ProtoEnumToString(value));
-  }
-
   std::unique_ptr<base::Value> ToValue(const std::string& value) const {
     return std::make_unique<base::Value>(value);
   }
@@ -301,7 +292,8 @@
   // Needs to be here to see all ToValue() overloads above.
   template <class P, class F>
   void VisitImpl(P&, const char* field_name, const F& field) {
-    value_->Set(field_name, ToValue(field));
+    value_->GetDict().Set(field_name,
+                          base::Value::FromUniquePtrValue(ToValue(field)));
   }
 
   const ProtoValueConversionOptions options_;
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc
index 409fc51..30d9c11 100644
--- a/components/sync/protocol/proto_value_conversions_unittest.cc
+++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -64,7 +64,7 @@
 
 DEFINE_SPECIFICS_TO_VALUE_TEST(encrypted)
 
-static_assert(42 == syncer::GetNumModelTypes(),
+static_assert(43 == syncer::GetNumModelTypes(),
               "When adding a new field, add a DEFINE_SPECIFICS_TO_VALUE_TEST "
               "for your field below, and optionally a test for the specific "
               "conversions.");
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index b47302d..1f1f9166 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -534,7 +534,7 @@
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::EntitySpecifics& proto) {
-  static_assert(42 == GetNumModelTypes(),
+  static_assert(43 == GetNumModelTypes(),
                 "When adding a new protocol type, you will likely need to add "
                 "it here as well.");
   VISIT(encrypted);
diff --git a/components/translate/core/browser/translate_language_list.cc b/components/translate/core/browser/translate_language_list.cc
index 088cc236..1e1753e 100644
--- a/components/translate/core/browser/translate_language_list.cc
+++ b/components/translate/core/browser/translate_language_list.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <iterator>
 
 #include "base/bind.h"
@@ -14,6 +13,7 @@
 #include "base/json/json_reader.h"
 #include "base/lazy_instance.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
@@ -185,8 +185,7 @@
   DCHECK(
       std::is_sorted(supported_languages_.begin(), supported_languages_.end()));
   DCHECK(supported_languages_.end() ==
-         std::adjacent_find(supported_languages_.begin(),
-                            supported_languages_.end()));
+         base::ranges::adjacent_find(supported_languages_));
 
   if (update_is_disabled)
     return;
@@ -362,8 +361,7 @@
   DCHECK(
       std::is_sorted(supported_languages_.begin(), supported_languages_.end()));
   DCHECK(supported_languages_.end() ==
-         std::adjacent_find(supported_languages_.begin(),
-                            supported_languages_.end()));
+         base::ranges::adjacent_find(supported_languages_));
 
   NotifyEvent(__LINE__, base::JoinString(supported_languages_, ", "));
   return true;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index b71d40d..e4cc6d8 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -314,16 +314,11 @@
     OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane =
         nullptr;
     if (output_surface_->IsDisplayedAsOverlayPlane()) {
-      // OutputSurface::GetOverlayMailbox() returns the mailbox for the last
-      // used buffer, which is most likely different from the one being used
-      // this frame. However, for the purpose of testing the overlay
-      // configuration, the mailbox for ANY buffer from BufferQueue is good
-      // enough because they're all created with identical properties.
       current_frame()->output_surface_plane =
           overlay_processor_->ProcessOutputSurfaceAsOverlay(
               device_viewport_size, surface_resource_size, frame_buffer_format,
               frame_color_space, frame_has_alpha, 1.0f /*opacity*/,
-              output_surface_->GetOverlayMailbox());
+              GetPrimaryPlaneOverlayTestingMailbox());
       primary_plane = &(current_frame()->output_surface_plane.value());
     }
 
@@ -1121,4 +1116,9 @@
   return gfx::Rect();
 }
 
+gpu::Mailbox DirectRenderer::GetPrimaryPlaneOverlayTestingMailbox() {
+  NOTREACHED();
+  return gpu::Mailbox();
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index 5b47646..733a7d6e8 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -180,6 +180,10 @@
   // 0 < n <= capabilities_.number_of_buffers.
   virtual void EnsureMinNumberOfBuffers(int n) {}
 
+  // Gets a mailbox that can be used for overlay testing the primary plane. This
+  // does not need to be the next mailbox that will be swapped.
+  virtual gpu::Mailbox GetPrimaryPlaneOverlayTestingMailbox();
+
   // Return the bounding rect of previously drawn delegated ink trail.
   gfx::Rect GetDelegatedInkTrailDamageRect();
 
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index daab4044..758999e 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -2718,6 +2718,9 @@
 #elif defined(USE_OZONE)
   // Only Wayland uses this code path.
   for (auto& overlay : current_frame()->overlay_list) {
+    if (overlay.is_root_render_pass) {
+      continue;
+    }
     if (overlay.rpdq) {
       PrepareRenderPassOverlay(&overlay);
       locks.emplace_back(overlay.mailbox);
@@ -3711,6 +3714,23 @@
   }
 }
 
+gpu::Mailbox SkiaRenderer::GetPrimaryPlaneOverlayTestingMailbox() {
+  // For the purpose of testing the overlay configuration, the mailbox for ANY
+  // buffer from BufferQueue is good enough because they're all created with
+  // identical properties.
+  // At the time we're testing overlays we don't yet know which mailbox will be
+  // presented this frame so we'll just use the last swapped buffer. (We might
+  // present a new frame's mailbox, or if we empty-swap we'll present the
+  // previous frame's mailbox.)
+  if (buffer_queue_) {
+    return buffer_queue_->GetLastSwappedBuffer();
+  } else {
+    // OutputSurface::GetOverlayMailbox() returns the mailbox for the last
+    // swapped buffer.
+    return skia_output_surface_->GetOverlayMailbox();
+  }
+}
+
 #if defined(USE_OZONE)
 const gpu::Mailbox SkiaRenderer::GetImageMailboxForColor(
     const SkColor4f& color) {
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index c6f95a3..b38120b 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -75,6 +75,7 @@
   gfx::Rect GetCurrentFramebufferDamage() const override;
   void Reshape(const OutputSurface::ReshapeParams& reshape_params) override;
   void EnsureMinNumberOfBuffers(int n) override;
+  gpu::Mailbox GetPrimaryPlaneOverlayTestingMailbox() override;
 
  protected:
   bool CanPartialSwap() override;
diff --git a/components/viz/service/display_embedder/buffer_queue.cc b/components/viz/service/display_embedder/buffer_queue.cc
index 6f2f0c6..2b760087 100644
--- a/components/viz/service/display_embedder/buffer_queue.cc
+++ b/components/viz/service/display_embedder/buffer_queue.cc
@@ -158,6 +158,29 @@
   return buffer;
 }
 
+gpu::Mailbox BufferQueue::GetLastSwappedBuffer() {
+  // The last swapped buffer will generally be in displayed_buffer_, as long as
+  // SwapBuffersComplete() has been called at least once for a non-empty swap
+  // since the last Reshape().
+  if (displayed_buffer_) {
+    return displayed_buffer_->mailbox;
+  }
+
+  // If displayed_buffer_ is null then any available buffer will do.
+  if (!available_buffers_.empty()) {
+    return available_buffers_.back()->mailbox;
+  }
+
+  // If there's nothing displayed or available, then we should have no buffers
+  // allocated because Reshape() hasn't been called yet, so a zero-mailbox is
+  // returned.
+  // If any buffers are in flight at this point then BufferQueue is being used
+  // incorrectly. We should not be Swap()ing all available buffers before
+  // receiving any SwapBuffersComplete() calls.
+  DCHECK(in_flight_buffers_.empty());
+  return gpu::Mailbox();
+}
+
 void BufferQueue::EnsureMinNumberOfBuffers(size_t n) {
   if (n <= number_of_buffers_) {
     return;
diff --git a/components/viz/service/display_embedder/buffer_queue.h b/components/viz/service/display_embedder/buffer_queue.h
index 78843b1..4381440 100644
--- a/components/viz/service/display_embedder/buffer_queue.h
+++ b/components/viz/service/display_embedder/buffer_queue.h
@@ -49,6 +49,8 @@
   // target for compositing).
   gpu::Mailbox GetCurrentBuffer();
 
+  gpu::Mailbox GetLastSwappedBuffer();
+
   // Returns a rectangle whose contents may have changed since the current
   // buffer was last submitted and needs to be redrawn. For partial swap,
   // only the contents outside this rectangle can be considered valid and do not
diff --git a/components/viz/service/display_embedder/buffer_queue_unittest.cc b/components/viz/service/display_embedder/buffer_queue_unittest.cc
index 908eb944..cce12c8f 100644
--- a/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -504,4 +504,53 @@
   SendDamagedFrame(small_damage);
 }
 
+TEST_F(BufferQueueTest, GetLastSwappedBuffer) {
+  // No images allocated, so zero-mailbox is returned.
+  EXPECT_TRUE(buffer_queue_->GetLastSwappedBuffer().IsZero());
+
+  // After reshape we'll get the last buffer in the queue.
+  EXPECT_TRUE(buffer_queue_->Reshape(screen_size, kBufferQueueColorSpace,
+                                     kBufferQueueFormat));
+  gpu::Mailbox last_swapped1 = buffer_queue_->GetLastSwappedBuffer();
+  EXPECT_FALSE(last_swapped1.IsZero());
+
+  // The last swapped buffer won't change until calling SwapBuffersComplete.
+  gpu::Mailbox mailbox1 = buffer_queue_->GetCurrentBuffer();
+  EXPECT_NE(last_swapped1, mailbox1);
+  EXPECT_EQ(last_swapped1, buffer_queue_->GetLastSwappedBuffer());
+  buffer_queue_->SwapBuffers(screen_rect);
+  EXPECT_EQ(last_swapped1, buffer_queue_->GetLastSwappedBuffer());
+  buffer_queue_->SwapBuffersComplete();
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox1);
+
+  // Swap another frame. Last swapped only updates after SwapBuffersComplete().
+  gpu::Mailbox mailbox2 = buffer_queue_->GetCurrentBuffer();
+  buffer_queue_->SwapBuffers(screen_rect);
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox1);
+  buffer_queue_->SwapBuffersComplete();
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox2);
+
+  // Swap a third frame. Last swapped only updates after SwapBuffersComplete().
+  gpu::Mailbox mailbox3 = buffer_queue_->GetCurrentBuffer();
+  // The third mailbox is the first one we got from GetLastSwappedBuffer().
+  EXPECT_EQ(mailbox3, last_swapped1);
+  buffer_queue_->SwapBuffers(screen_rect);
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox2);
+  buffer_queue_->SwapBuffersComplete();
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox3);
+
+  // Empty swap, Last swapped stays the same.
+  buffer_queue_->SwapBuffers(gfx::Rect());
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox3);
+  buffer_queue_->SwapBuffersComplete();
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox3);
+
+  // Swap a fourth frame. Last swapped only updates after SwapBuffersComplete().
+  EXPECT_EQ(buffer_queue_->GetCurrentBuffer(), mailbox1);
+  buffer_queue_->SwapBuffers(screen_rect);
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox3);
+  buffer_queue_->SwapBuffersComplete();
+  EXPECT_EQ(buffer_queue_->GetLastSwappedBuffer(), mailbox1);
+}
+
 }  // namespace viz
diff --git a/components/webapps/browser/features.cc b/components/webapps/browser/features.cc
index b18c71b..8222b62 100644
--- a/components/webapps/browser/features.cc
+++ b/components/webapps/browser/features.cc
@@ -62,7 +62,7 @@
 // Enables showing a detailed install dialog for user installs.
 BASE_FEATURE(kDesktopPWAsDetailedInstallDialog,
              "DesktopPWAsDetailedInstallDialog",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Enables sending the beforeinstallprompt without a service worker check.
 BASE_FEATURE(kSkipServiceWorkerForInstallPrompt,
diff --git a/components/zucchini/imposed_ensemble_matcher.cc b/components/zucchini/imposed_ensemble_matcher.cc
index 36afad6..09c09f0 100644
--- a/components/zucchini/imposed_ensemble_matcher.cc
+++ b/components/zucchini/imposed_ensemble_matcher.cc
@@ -4,12 +4,12 @@
 
 #include "components/zucchini/imposed_ensemble_matcher.h"
 
-#include <algorithm>
 #include <sstream>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/ranges/algorithm.h"
 #include "components/zucchini/io_utils.h"
 
 namespace zucchini {
@@ -67,9 +67,8 @@
             });
 
   // Check for overlaps in "new" file.
-  if (std::adjacent_find(
-          matches_.begin(), matches_.end(),
-          [](const ElementMatch& match1, const ElementMatch& match2) {
+  if (base::ranges::adjacent_find(
+          matches_, [](const ElementMatch& match1, const ElementMatch& match2) {
             return match1.new_element.hi() > match2.new_element.lo();
           }) != matches_.end()) {
     return kOverlapInNew;
diff --git a/content/browser/direct_sockets/direct_sockets_open_browsertest.cc b/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
index 4e27e196..2f919ab 100644
--- a/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
+++ b/content/browser/direct_sockets/direct_sockets_open_browsertest.cc
@@ -5,12 +5,10 @@
 #include <algorithm>
 #include <vector>
 
-#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram.h"
-#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
@@ -68,81 +66,12 @@
 
 constexpr char kLocalhostAddress[] = "127.0.0.1";
 
-constexpr char kPermissionDeniedHistogramName[] =
-    "DirectSockets.PermissionDeniedFailures";
-
 constexpr char kTCPNetworkFailuresHistogramName[] =
     "DirectSockets.TCPNetworkFailures";
 
 constexpr char kUDPNetworkFailuresHistogramName[] =
     "DirectSockets.UDPNetworkFailures";
 
-const std::string kIPv4_tests[] = {
-    // 0.0.0.0/8
-    "0.0.0.0", "0.255.255.255",
-    // 10.0.0.0/8
-    "10.0.0.0", "10.255.255.255",
-    // 100.64.0.0/10
-    "100.64.0.0", "100.127.255.255",
-    // 127.0.0.0/8
-    "127.0.0.0", "127.255.255.255",
-    // 169.254.0.0/16
-    "169.254.0.0", "169.254.255.255",
-    // 172.16.0.0/12
-    "172.16.0.0", "172.31.255.255",
-    // 192.0.2.0/24
-    "192.0.2.0", "192.0.2.255",
-    // 192.88.99.0/24
-    "192.88.99.0", "192.88.99.255",
-    // 192.168.0.0/16
-    "192.168.0.0", "192.168.255.255",
-    // 198.18.0.0/15
-    "198.18.0.0", "198.19.255.255",
-    // 198.51.100.0/24
-    "198.51.100.0", "198.51.100.255",
-    // 203.0.113.0/24
-    "203.0.113.0", "203.0.113.255",
-    // 224.0.0.0/8 - 255.0.0.0/8
-    "224.0.0.0", "255.255.255.255"};
-
-const std::string kIPv6_tests[] = {
-    // 0000::/8.
-    // Skip testing ::ffff:/96 explicitly since it will be tested through
-    // mapping Ipv4 Addresses.
-    "0:0:0:0:0:0:0:0", "ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 0100::/8
-    "100:0:0:0:0:0:0:0", "1ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 0200::/7
-    "200:0:0:0:0:0:0:0", "3ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 0400::/6
-    "400:0:0:0:0:0:0:0", "7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 0800::/5
-    "800:0:0:0:0:0:0:0", "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 1000::/4
-    "1000:0:0:0:0:0:0:0", "1fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 4000::/3
-    "4000:0:0:0:0:0:0:0", "5fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 6000::/3
-    "6000:0:0:0:0:0:0:0", "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // 8000::/3
-    "8000:0:0:0:0:0:0:0", "9fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // c000::/3
-    "c000:0:0:0:0:0:0:0", "dfff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // e000::/4
-    "e000:0:0:0:0:0:0:0", "efff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // f000::/5
-    "f000:0:0:0:0:0:0:0", "f7ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // f800::/6
-    "f800:0:0:0:0:0:0:0", "fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // fc00::/7
-    "fc00:0:0:0:0:0:0:0", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // fe00::/9
-    "fe00:0:0:0:0:0:0:0", "fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // fe80::/10
-    "fe80:0:0:0:0:0:0:0", "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-    // fec0::/10
-    "fec0:0:0:0:0:0:0:0", "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"};
-
 class MockOpenNetworkContext : public content::test::MockNetworkContext {
  public:
   explicit MockOpenNetworkContext(net::Error result) : result_(result) {}
@@ -291,78 +220,6 @@
               ::testing::HasSubstr("keepAliveDelay must be no less than"));
 }
 
-class DirectSocketsOpenCannotConnectBrowserTest
-    : public DirectSocketsOpenBrowserTest,
-      public testing::WithParamInterface<ProtocolType> {
- public:
-  static std::vector<std::string> ProduceAllTestParams() {
-    std::vector<std::string> params;
-    std::copy(std::begin(kIPv4_tests), std::end(kIPv4_tests),
-              std::back_inserter(params));
-    std::transform(std::begin(kIPv4_tests), std::end(kIPv4_tests),
-                   std::back_inserter(params),
-                   [](const std::string& ip_address) {
-                     net::IPAddress address;
-                     EXPECT_TRUE(address.AssignFromIPLiteral(ip_address));
-                     net::IPAddress mapped_address =
-                         net::ConvertIPv4ToIPv4MappedIPv6(address);
-                     return base::StrCat({"[", mapped_address.ToString(), "]"});
-                   });
-    std::transform(std::begin(kIPv6_tests), std::end(kIPv6_tests),
-                   std::back_inserter(params),
-                   [](const std::string& ip_address) {
-                     return base::StrCat({"[", ip_address, "]"});
-                   });
-    return params;
-  }
-
-  void RunTest() {
-    const auto protocol = GetParam();
-    const std::string type = protocol == ProtocolType::kTcp ? "Tcp" : "Udp";
-    const std::string expected_result = base::StringPrintf(
-        "open%s failed: NetworkError: Network Error.", type.c_str());
-
-    const std::string example_hostname = "mail.example.com";
-    const std::string script =
-        protocol == ProtocolType::kTcp
-            ? base::StringPrintf("openTcp('%s', 993)", example_hostname.c_str())
-            : base::StringPrintf(
-                  "openUdp({ remoteAddress: '%s', remotePort: 993 })",
-                  example_hostname.c_str());
-
-    for (const auto& address : ProduceAllTestParams()) {
-      const std::string mapping_rules = base::StringPrintf(
-          "MAP %s %s", example_hostname.c_str(), address.c_str());
-
-      MockOpenNetworkContext mock_network_context(net::OK);
-      mock_network_context.set_host_mapping_rules(mapping_rules);
-      DirectSocketsServiceImpl::SetNetworkContextForTesting(
-          &mock_network_context);
-
-      base::HistogramTester histogram_tester;
-      histogram_tester.ExpectBucketCount(
-          kPermissionDeniedHistogramName,
-          blink::mojom::DirectSocketFailureType::kResolvingToNonPublic, 0);
-
-      EXPECT_EQ(expected_result, EvalJs(shell(), script));
-
-      histogram_tester.ExpectBucketCount(
-          kPermissionDeniedHistogramName,
-          blink::mojom::DirectSocketFailureType::kResolvingToNonPublic, 1);
-    }
-  }
-};
-
-IN_PROC_BROWSER_TEST_P(DirectSocketsOpenCannotConnectBrowserTest,
-                       Open_CannotConnectNonPublic) {
-  RunTest();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    /*empty*/,
-    DirectSocketsOpenCannotConnectBrowserTest,
-    testing::Values(ProtocolType::kTcp, ProtocolType::kUdp));
-
 IN_PROC_BROWSER_TEST_F(DirectSocketsOpenBrowserTest, OpenTcp_OptionsOne) {
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectUniqueSample(kTCPNetworkFailuresHistogramName,
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.cc b/content/browser/direct_sockets/direct_sockets_service_impl.cc
index f9777e33..62bfde2 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.cc
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.cc
@@ -5,27 +5,25 @@
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
 
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 #include "content/browser/direct_sockets/direct_udp_socket_impl.h"
 #include "content/browser/direct_sockets/resolve_host_and_open_socket.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/direct_sockets_delegate.h"
-#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/document_service.h"
 #include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
 #include "mojo/public/cpp/bindings/message.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/tcp_socket.mojom.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-shared.h"
+#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
 
 namespace content {
@@ -57,11 +55,13 @@
 }
 
 bool IsFrameSufficientlyIsolated(content::RenderFrameHost* frame) {
-  return frame->GetWebExposedIsolationLevel() >=
-             content::RenderFrameHost::WebExposedIsolationLevel::
-                 kMaybeIsolatedApplication &&
-         frame->IsFeatureEnabled(
-             blink::mojom::PermissionsPolicyFeature::kDirectSockets);
+  if (frame->GetWebExposedIsolationLevel() >=
+      content::RenderFrameHost::WebExposedIsolationLevel::
+          kMaybeIsolatedApplication) {
+    return true;
+  }
+
+  return false;
 }
 
 network::mojom::TCPConnectedSocketOptionsPtr CreateTCPConnectedSocketOptions(
@@ -112,23 +112,29 @@
 
 }  // namespace
 
-DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost* frame_host)
-    : WebContentsObserver(WebContents::FromRenderFrameHost(frame_host)),
-      frame_host_(frame_host) {}
+DirectSocketsServiceImpl::DirectSocketsServiceImpl(
+    RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver)
+    : DocumentService(*render_frame_host, std::move(receiver)) {}
 
 DirectSocketsServiceImpl::~DirectSocketsServiceImpl() = default;
 
 // static
 void DirectSocketsServiceImpl::CreateForFrame(
-    RenderFrameHost* frame,
+    RenderFrameHost* render_frame_host,
     mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!IsFrameSufficientlyIsolated(frame)) {
+  if (!render_frame_host->IsFeatureEnabled(
+          blink::mojom::PermissionsPolicyFeature::kDirectSockets)) {
+    mojo::ReportBadMessage(
+        "Permissions policy blocks access to Direct Sockets.");
+  }
+  if (!IsFrameSufficientlyIsolated(render_frame_host)) {
+    mojo::ReportBadMessage(
+        "Frame is not sufficiently isolated to use Direct Sockets.");
     return;
   }
-  mojo::MakeSelfOwnedReceiver(
-      base::WrapUnique(new DirectSocketsServiceImpl(frame)),
-      std::move(receiver));
+  new DirectSocketsServiceImpl(render_frame_host, std::move(receiver));
 }
 
 content::DirectSocketsDelegate* DirectSocketsServiceImpl::GetDelegate() {
@@ -140,37 +146,26 @@
     mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
     mojo::PendingRemote<network::mojom::SocketObserver> observer,
     OpenTcpSocketCallback callback) {
-  if (!IsFrameSufficientlyIsolated(frame_host_)) {
-    mojo::ReportBadMessage("Insufficient isolation to open socket");
-    return;
-  }
-
-  if (!GetNetworkContext()) {
-    mojo::ReportBadMessage("Invalid request to open socket");
-    return;
-  }
+  const std::string remote_host = options->remote_hostname;
+  const uint16_t remote_port = options->remote_port;
 
   if (auto* delegate = GetDelegate();
-      delegate &&
-      !delegate->ValidateAddressAndPort(
-          frame_host_, options->remote_hostname, options->remote_port,
-          blink::mojom::DirectSocketProtocolType::kTcp)) {
+      delegate && !delegate->ValidateAddressAndPort(
+                      &render_frame_host(), remote_host, remote_port,
+                      blink::mojom::DirectSocketProtocolType::kTcp)) {
     std::move(callback).Run(net::ERR_ACCESS_DENIED, absl::nullopt,
                             absl::nullopt, mojo::ScopedDataPipeConsumerHandle(),
                             mojo::ScopedDataPipeProducerHandle());
     return;
   }
 
-  const std::string remote_host = options->remote_hostname;
-  const uint16_t remote_port = options->remote_port;
-
-  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
   ResolveHostAndOpenSocket::Create(
-      weak_ptr, remote_host, remote_port,
+      remote_host, remote_port,
       base::BindOnce(&DirectSocketsServiceImpl::OnResolveCompleteForTcpSocket,
-                     weak_ptr, std::move(options), std::move(receiver),
-                     std::move(observer), std::move(callback)))
-      ->Start();
+                     weak_ptr_factory_.GetWeakPtr(), std::move(options),
+                     std::move(receiver), std::move(observer),
+                     std::move(callback)))
+      ->Start(GetNetworkContext());
 }
 
 void DirectSocketsServiceImpl::OpenUdpSocket(
@@ -178,42 +173,25 @@
     mojo::PendingReceiver<blink::mojom::DirectUDPSocket> receiver,
     mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
     OpenUdpSocketCallback callback) {
-  if (!IsFrameSufficientlyIsolated(frame_host_)) {
-    mojo::ReportBadMessage("Insufficient isolation to open socket");
-    return;
-  }
-
-  if (!GetNetworkContext()) {
-    mojo::ReportBadMessage("Invalid request to open socket");
-    return;
-  }
+  const std::string remote_host = options->remote_hostname;
+  const uint16_t remote_port = options->remote_port;
 
   if (auto* delegate = GetDelegate();
-      delegate &&
-      !delegate->ValidateAddressAndPort(
-          frame_host_, options->remote_hostname, options->remote_port,
-          blink::mojom::DirectSocketProtocolType::kUdp)) {
+      delegate && !delegate->ValidateAddressAndPort(
+                      &render_frame_host(), remote_host, remote_port,
+                      blink::mojom::DirectSocketProtocolType::kUdp)) {
     std::move(callback).Run(net::ERR_ACCESS_DENIED, absl::nullopt,
                             absl::nullopt);
     return;
   }
 
-  const std::string remote_host = options->remote_hostname;
-  const uint16_t remote_port = options->remote_port;
-
-  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
   ResolveHostAndOpenSocket::Create(
-      weak_ptr, remote_host, remote_port,
+      remote_host, remote_port,
       base::BindOnce(&DirectSocketsServiceImpl::OnResolveCompleteForUdpSocket,
-                     weak_ptr, std::move(options), std::move(receiver),
-                     std::move(listener), std::move(callback)))
-      ->Start();
-}
-
-// static
-net::MutableNetworkTrafficAnnotationTag
-DirectSocketsServiceImpl::MutableTrafficAnnotation() {
-  return net::MutableNetworkTrafficAnnotationTag{TrafficAnnotation()};
+                     weak_ptr_factory_.GetWeakPtr(), std::move(options),
+                     std::move(receiver), std::move(listener),
+                     std::move(callback)))
+      ->Start(GetNetworkContext());
 }
 
 // static
@@ -227,38 +205,12 @@
   GetNetworkContextForTesting() = network_context;
 }
 
-void DirectSocketsServiceImpl::RenderFrameDeleted(
-    RenderFrameHost* render_frame_host) {
-  if (render_frame_host == frame_host_) {
-    frame_host_ = nullptr;
-  }
-}
-
-void DirectSocketsServiceImpl::RenderFrameHostChanged(
-    RenderFrameHost* old_host,
-    RenderFrameHost* new_host) {
-  if (old_host == frame_host_) {
-    frame_host_ = nullptr;
-  }
-}
-
-void DirectSocketsServiceImpl::WebContentsDestroyed() {
-  frame_host_ = nullptr;
-}
-
 network::mojom::NetworkContext* DirectSocketsServiceImpl::GetNetworkContext()
     const {
-  if (GetNetworkContextForTesting())
-    return GetNetworkContextForTesting();
-
-  if (!frame_host_)
-    return nullptr;
-
-  return frame_host_->GetStoragePartition()->GetNetworkContext();
-}
-
-RenderFrameHost* DirectSocketsServiceImpl::GetFrameHost() const {
-  return frame_host_;
+  if (auto* network_context = GetNetworkContextForTesting()) {
+    return network_context;
+  }
+  return render_frame_host().GetStoragePartition()->GetNetworkContext();
 }
 
 void DirectSocketsServiceImpl::OnResolveCompleteForTcpSocket(
@@ -275,19 +227,15 @@
     return;
   }
 
-  auto* network_context = GetNetworkContext();
-  if (!network_context) {
-    return;
-  }
-
   DCHECK(resolved_addresses && !resolved_addresses->empty());
   absl::optional<net::IPEndPoint> local_addr = GetLocalAddress(*options);
 
-  network_context->CreateTCPConnectedSocket(
+  GetNetworkContext()->CreateTCPConnectedSocket(
       std::move(local_addr), *resolved_addresses,
       CreateTCPConnectedSocketOptions(std::move(options)),
-      DirectSocketsServiceImpl::MutableTrafficAnnotation(), std::move(socket),
-      std::move(observer), std::move(callback));
+      net::MutableNetworkTrafficAnnotationTag{
+          DirectSocketsServiceImpl::TrafficAnnotation()},
+      std::move(socket), std::move(observer), std::move(callback));
 }
 
 void DirectSocketsServiceImpl::OnResolveCompleteForUdpSocket(
@@ -303,16 +251,11 @@
     return;
   }
 
-  auto* network_context = GetNetworkContext();
-  if (!network_context) {
-    return;
-  }
-
   DCHECK(resolved_addresses && !resolved_addresses->empty());
 
   net::IPEndPoint peer_addr = resolved_addresses->front();
   auto direct_udp_socket = std::make_unique<DirectUDPSocketImpl>(
-      network_context, std::move(listener));
+      GetNetworkContext(), std::move(listener));
 
   direct_udp_socket->Connect(
       resolved_addresses->front(), CreateUDPSocketOptions(std::move(options)),
diff --git a/content/browser/direct_sockets/direct_sockets_service_impl.h b/content/browser/direct_sockets/direct_sockets_service_impl.h
index 9c2837a..6d2fad8 100644
--- a/content/browser/direct_sockets/direct_sockets_service_impl.h
+++ b/content/browser/direct_sockets/direct_sockets_service_impl.h
@@ -8,9 +8,8 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/direct_sockets_delegate.h"
+#include "content/public/browser/document_service.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
@@ -24,10 +23,11 @@
 
 namespace content {
 
+class DirectSocketsDelegate;
+
 // Implementation of the DirectSocketsService Mojo service.
 class CONTENT_EXPORT DirectSocketsServiceImpl
-    : public blink::mojom::DirectSocketsService,
-      public WebContentsObserver {
+    : public DocumentService<blink::mojom::DirectSocketsService> {
  public:
   ~DirectSocketsServiceImpl() override;
 
@@ -49,23 +49,17 @@
       mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
       OpenUdpSocketCallback callback) override;
 
-  // WebContentsObserver:
-  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
-  void RenderFrameHostChanged(RenderFrameHost* old_host,
-                              RenderFrameHost* new_host) override;
-  void WebContentsDestroyed() override;
-
-  network::mojom::NetworkContext* GetNetworkContext() const;
-  RenderFrameHost* GetFrameHost() const;
-
-  static net::MutableNetworkTrafficAnnotationTag MutableTrafficAnnotation();
   static net::NetworkTrafficAnnotationTag TrafficAnnotation();
 
   // Testing:
   static void SetNetworkContextForTesting(network::mojom::NetworkContext*);
 
  private:
-  explicit DirectSocketsServiceImpl(RenderFrameHost*);
+  DirectSocketsServiceImpl(
+      RenderFrameHost*,
+      mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver);
+
+  network::mojom::NetworkContext* GetNetworkContext() const;
 
   void OnResolveCompleteForTcpSocket(
       blink::mojom::DirectSocketOptionsPtr,
@@ -83,7 +77,6 @@
       int result,
       const absl::optional<net::AddressList>& resolved_addresses);
 
-  raw_ptr<RenderFrameHost> frame_host_;
   mojo::UniqueReceiverSet<blink::mojom::DirectUDPSocket>
       direct_udp_socket_receivers_;
 
diff --git a/content/browser/direct_sockets/direct_udp_socket_impl.cc b/content/browser/direct_sockets/direct_udp_socket_impl.cc
index f19414a..f975091 100644
--- a/content/browser/direct_sockets/direct_udp_socket_impl.cc
+++ b/content/browser/direct_sockets/direct_udp_socket_impl.cc
@@ -5,6 +5,7 @@
 #include "content/browser/direct_sockets/direct_udp_socket_impl.h"
 
 #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace content {
 
@@ -40,7 +41,8 @@
     return;
   }
   remote_->Send(std::move(data),
-                DirectSocketsServiceImpl::MutableTrafficAnnotation(),
+                net::MutableNetworkTrafficAnnotationTag{
+                    DirectSocketsServiceImpl::TrafficAnnotation()},
                 std::move(callback));
 }
 
diff --git a/content/browser/direct_sockets/resolve_host_and_open_socket.cc b/content/browser/direct_sockets/resolve_host_and_open_socket.cc
index bb23d60..7d9908e 100644
--- a/content/browser/direct_sockets/resolve_host_and_open_socket.cc
+++ b/content/browser/direct_sockets/resolve_host_and_open_socket.cc
@@ -5,24 +5,15 @@
 #include "content/browser/direct_sockets/resolve_host_and_open_socket.h"
 
 #include "base/functional/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram_functions.h"
 #include "build/build_config.h"
-#include "content/browser/direct_sockets/direct_sockets_service_impl.h"
-#include "content/public/browser/direct_sockets_delegate.h"
 #include "content/public/browser/render_frame_host.h"
 #include "net/base/address_list.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
 #include "net/net_buildflags.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
 namespace content {
 namespace {
 
-constexpr char kPermissionDeniedHistogramName[] =
-    "DirectSockets.PermissionDeniedFailures";
-
 #if BUILDFLAG(ENABLE_MDNS)
 bool ResemblesMulticastDNSName(const std::string& hostname) {
   return base::EndsWith(hostname, ".local") ||
@@ -30,64 +21,37 @@
 }
 #endif  // !BUILDFLAG(ENABLE_MDNS)
 
-bool IsRawIPAddress(const std::string& address) {
-  net::IPAddress ip;
-  return ip.AssignFromIPLiteral(address);
-}
-
-bool ContainNonPubliclyRoutableAddress(const net::AddressList& addresses) {
-  DCHECK(!addresses.empty());
-  return !base::ranges::all_of(addresses, &net::IPAddress::IsPubliclyRoutable,
-                               &net::IPEndPoint::address);
-}
-
-RenderFrameHost* GetFrameHostFromService(
-    base::WeakPtr<DirectSocketsServiceImpl> service) {
-  if (!service) {
-    return nullptr;
-  }
-  return service->GetFrameHost();
-}
-
 }  // namespace
 
-ResolveHostAndOpenSocket::ResolveHostAndOpenSocket(
-    base::WeakPtr<DirectSocketsServiceImpl> service,
-    const std::string& host,
-    uint16_t port,
-    OpenSocketCallback callback)
-    : service_(service),
-      host_(host),
-      port_(port),
-      callback_(std::move(callback)) {}
+ResolveHostAndOpenSocket::ResolveHostAndOpenSocket(const std::string& host,
+                                                   uint16_t port,
+                                                   OpenSocketCallback callback)
+    : host_(host), port_(port), callback_(std::move(callback)) {}
 
 ResolveHostAndOpenSocket::~ResolveHostAndOpenSocket() = default;
 
 // static
 ResolveHostAndOpenSocket* ResolveHostAndOpenSocket::Create(
-    base::WeakPtr<DirectSocketsServiceImpl> service,
-    const std::string& host,
+    const std::string& address,
     uint16_t port,
     OpenSocketCallback callback) {
-  return new ResolveHostAndOpenSocket(std::move(service), host, port,
-                                      std::move(callback));
+  return new ResolveHostAndOpenSocket(address, port, std::move(callback));
 }
 
-void ResolveHostAndOpenSocket::Start() {
-  auto* network_context = service_->GetNetworkContext();
-  DCHECK(network_context);
+void ResolveHostAndOpenSocket::Start(
+    network::mojom::NetworkContext* network_context) {
   DCHECK(!receiver_.is_bound());
   DCHECK(!resolver_.is_bound());
 
-  network_context->CreateHostResolver(/*config_overrides=*/absl::nullopt,
-                                      resolver_.BindNewPipeAndPassReceiver());
+  network_context->CreateHostResolver(
+      /*config_overrides=*/absl::nullopt,
+      resolver_.BindNewPipeAndPassReceiver());
 
   network::mojom::ResolveHostParametersPtr parameters =
       network::mojom::ResolveHostParameters::New();
 #if BUILDFLAG(ENABLE_MDNS)
   if (ResemblesMulticastDNSName(host_)) {
     parameters->source = net::HostResolverSource::MULTICAST_DNS;
-    is_mdns_name_ = true;
   }
 #endif  // !BUILDFLAG(ENABLE_MDNS)
   // Intentionally using a HostPortPair because scheme isn't specified.
@@ -111,36 +75,8 @@
         endpoint_results_with_metadata) {
   DCHECK(receiver_.is_bound());
   receiver_.reset();
+  resolver_.reset();
 
-  auto* frame = GetFrameHostFromService(service_);
-  if (!frame) {
-    OpenSocket(net::ERR_UNEXPECTED, {});
-    return;
-  }
-
-  if (auto* delegate = DirectSocketsServiceImpl::GetDelegate();
-      delegate && delegate->ShouldSkipPostResolveChecks(frame)) {
-    OpenSocket(result, resolved_addresses);
-    return;
-  }
-
-  // Reject hostnames that resolve to non-public exception unless a raw IP
-  // address or a *.local hostname is entered by the user.
-  if (!IsRawIPAddress(host_) && !is_mdns_name_ && resolved_addresses &&
-      ContainNonPubliclyRoutableAddress(*resolved_addresses)) {
-    base::UmaHistogramEnumeration(
-        kPermissionDeniedHistogramName,
-        blink::mojom::DirectSocketFailureType::kResolvingToNonPublic);
-    OpenSocket(net::ERR_NETWORK_ACCESS_DENIED, {});
-    return;
-  }
-
-  OpenSocket(result, resolved_addresses);
-}
-
-void ResolveHostAndOpenSocket::OpenSocket(
-    int result,
-    const absl::optional<net::AddressList>& resolved_addresses) {
   std::move(callback_).Run(result, resolved_addresses);
   delete this;
 }
diff --git a/content/browser/direct_sockets/resolve_host_and_open_socket.h b/content/browser/direct_sockets/resolve_host_and_open_socket.h
index 0d778ce..7f4b414 100644
--- a/content/browser/direct_sockets/resolve_host_and_open_socket.h
+++ b/content/browser/direct_sockets/resolve_host_and_open_socket.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_BROWSER_DIRECT_SOCKETS_RESOLVE_HOST_AND_OPEN_SOCKET_H_
 #define CONTENT_BROWSER_DIRECT_SOCKETS_RESOLVE_HOST_AND_OPEN_SOCKET_H_
 
-#include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -13,12 +12,14 @@
 #include "net/dns/public/host_resolver_results.h"
 #include "services/network/public/cpp/resolve_host_client_base.h"
 
+namespace network::mojom {
+class NetworkContext;
+}  // namespace network::mojom
+
 namespace content {
 
-class DirectSocketsServiceImpl;
-
-// Resolves the host/port pair provided in options. Upon completion invokes the
-// supplied callback and deletes |this|.
+// Resolves the host/port pair provided on creation. After resolver signals
+// completion via OnComplete(), fires the supplied callback and deletes itself.
 class CONTENT_EXPORT ResolveHostAndOpenSocket
     : public network::ResolveHostClientBase {
  public:
@@ -28,17 +29,14 @@
 
   ~ResolveHostAndOpenSocket() override;
 
-  static ResolveHostAndOpenSocket* Create(
-      base::WeakPtr<DirectSocketsServiceImpl>,
-      const std::string& host,
-      uint16_t port,
-      OpenSocketCallback);
+  static ResolveHostAndOpenSocket* Create(const std::string& host,
+                                          uint16_t port,
+                                          OpenSocketCallback);
 
-  void Start();
+  void Start(network::mojom::NetworkContext*);
 
  private:
-  ResolveHostAndOpenSocket(base::WeakPtr<DirectSocketsServiceImpl>,
-                           const std::string& host,
+  ResolveHostAndOpenSocket(const std::string& host,
                            uint16_t port,
                            OpenSocketCallback);
 
@@ -48,18 +46,11 @@
                   const absl::optional<net::HostResolverEndpointResults>&
                       endpoint_results_with_metadata) override;
 
-  void OpenSocket(int result,
-                  const absl::optional<net::AddressList>& resolved_addresses);
-
-  base::WeakPtr<DirectSocketsServiceImpl> service_;
-
   const std::string host_;
   uint16_t port_;
 
   OpenSocketCallback callback_;
 
-  bool is_mdns_name_ = false;
-
   mojo::Receiver<network::mojom::ResolveHostClient> receiver_{this};
   mojo::Remote<network::mojom::HostResolver> resolver_;
 };
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
index ee262ed..5568647 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.cc
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
@@ -222,12 +222,6 @@
   db_helper_.Reset();
 }
 
-void FirstPartySetsHandlerImpl::SetGlobalSetsForTesting(
-    net::GlobalFirstPartySets global_sets) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  global_sets_ = std::move(global_sets);
-}
-
 void FirstPartySetsHandlerImpl::GetPersistedGlobalSetsForTesting(
     const std::string& browser_context_id,
     base::OnceCallback<void(absl::optional<net::GlobalFirstPartySets>)>
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h
index 5ea1af2..bc69f225 100644
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.h
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
@@ -111,7 +111,6 @@
   void SetPublicFirstPartySets(const base::Version& version,
                                base::File sets_file) override;
   void ResetForTesting() override;
-  void SetGlobalSetsForTesting(net::GlobalFirstPartySets global_sets) override;
   absl::optional<net::FirstPartySetEntry> FindEntry(
       const net::SchemefulSite& site,
       const net::FirstPartySetsContextConfig& config) const override;
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc
index 29c2078..fc279464 100644
--- a/content/browser/interest_group/interest_group_auction.cc
+++ b/content/browser/interest_group/interest_group_auction.cc
@@ -1091,7 +1091,7 @@
   DCHECK(!bidding_and_scoring_phase_callback_);
   DCHECK(!reporting_phase_callback_);
   DCHECK(!final_auction_result_);
-  DCHECK(!top_bid_);
+  DCHECK(!auction_leader_.top_bid);
   DCHECK_EQ(pending_component_seller_worklet_requests_, 0u);
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "bidding_and_scoring_phase",
@@ -1139,16 +1139,17 @@
   DCHECK(!bidding_and_scoring_phase_callback_);
   DCHECK(!reporting_phase_callback_);
   DCHECK(!final_auction_result_);
-  DCHECK(top_bid_);
+  DCHECK(auction_leader_.top_bid);
   // This should only be called on top-level auctions.
   DCHECK(!parent_);
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "reporting_phase", trace_id_);
 
   InterestGroupAuctionReporter::WinningBidInfo winning_bid_info;
-  winning_bid_info.storage_interest_group = &top_bid_->bid->bid_state->bidder;
-  winning_bid_info.render_url = top_bid_->bid->render_url;
-  winning_bid_info.ad_components = top_bid_->bid->ad_components;
+  winning_bid_info.storage_interest_group =
+      &auction_leader_.top_bid->bid->bid_state->bidder;
+  winning_bid_info.render_url = auction_leader_.top_bid->bid->render_url;
+  winning_bid_info.ad_components = auction_leader_.top_bid->bid->ad_components;
   // Need the bid from the bidder itself. If the bid was from a component
   // auction, then `top_bid_->bid` will be the bid from the component auction,
   // which the component seller worklet may have modified, and thus the wrong
@@ -1157,22 +1158,23 @@
   // the bid was from the top-level auction, and the original top bid from the
   // component auction, otherwise, so will always be the bid returned by the
   // winning bidder's generateBid() method.
-  winning_bid_info.bid = top_bid_->bid->auction->top_bid()->bid->bid;
-  winning_bid_info.bid_duration = top_bid_->bid->bid_duration;
+  winning_bid_info.bid =
+      auction_leader_.top_bid->bid->auction->top_bid()->bid->bid;
+  winning_bid_info.bid_duration = auction_leader_.top_bid->bid->bid_duration;
   winning_bid_info.bidding_signals_data_version =
-      top_bid_->bid->bidding_signals_data_version;
+      auction_leader_.top_bid->bid->bidding_signals_data_version;
 
   InterestGroupAuctionReporter::SellerWinningBidInfo
       top_level_seller_winning_bid_info;
   top_level_seller_winning_bid_info.auction_config = config_;
-  top_level_seller_winning_bid_info.bid = top_bid_->bid->bid;
-  top_level_seller_winning_bid_info.score = top_bid_->score;
+  top_level_seller_winning_bid_info.bid = auction_leader_.top_bid->bid->bid;
+  top_level_seller_winning_bid_info.score = auction_leader_.top_bid->score;
   top_level_seller_winning_bid_info.highest_scoring_other_bid =
-      highest_scoring_other_bid_;
+      auction_leader_.highest_scoring_other_bid;
   top_level_seller_winning_bid_info.highest_scoring_other_bid_owner =
-      highest_scoring_other_bid_owner_;
+      auction_leader_.highest_scoring_other_bid_owner;
   top_level_seller_winning_bid_info.scoring_signals_data_version =
-      top_bid_->scoring_signals_data_version;
+      auction_leader_.top_bid->scoring_signals_data_version;
   top_level_seller_winning_bid_info.trace_id = trace_id_;
 
   // Populate the SellerWinningBidInfo for the component auction that the
@@ -1187,25 +1189,27 @@
   // SellerWinningBidInfos.
   absl::optional<InterestGroupAuctionReporter::SellerWinningBidInfo>
       component_seller_winning_bid_info;
-  if (top_bid_->bid->auction != this) {
-    const InterestGroupAuction* component_auction = top_bid_->bid->auction;
+  if (auction_leader_.top_bid->bid->auction != this) {
+    const InterestGroupAuction* component_auction =
+        auction_leader_.top_bid->bid->auction;
     component_seller_winning_bid_info.emplace();
     component_seller_winning_bid_info->auction_config =
         component_auction->config_;
     component_seller_winning_bid_info->bid =
-        component_auction->top_bid_->bid->bid;
+        component_auction->auction_leader_.top_bid->bid->bid;
     component_seller_winning_bid_info->score =
-        component_auction->top_bid_->score;
+        component_auction->auction_leader_.top_bid->score;
     component_seller_winning_bid_info->highest_scoring_other_bid =
-        component_auction->highest_scoring_other_bid_;
+        component_auction->auction_leader_.highest_scoring_other_bid;
     component_seller_winning_bid_info->highest_scoring_other_bid_owner =
-        component_auction->highest_scoring_other_bid_owner_;
+        component_auction->auction_leader_.highest_scoring_other_bid_owner;
     component_seller_winning_bid_info->scoring_signals_data_version =
-        component_auction->top_bid_->scoring_signals_data_version;
+        component_auction->auction_leader_.top_bid
+            ->scoring_signals_data_version;
     component_seller_winning_bid_info->trace_id = component_auction->trace_id_;
     component_seller_winning_bid_info->component_auction_modified_bid_params =
-        component_auction->top_bid_->component_auction_modified_bid_params
-            ->Clone();
+        component_auction->auction_leader_.top_bid
+            ->component_auction_modified_bid_params->Clone();
   }
 
   reporting_phase_callback_ = std::move(reporting_phase_callback);
@@ -1369,14 +1373,15 @@
   // `debug_win_report_urls`.
   BidState* winner = nullptr;
   if (final_auction_result_ == AuctionResult::kSuccess &&
-      top_bid_->bid->auction == this) {
-    winner = top_bid_->bid->bid_state;
+      auction_leader_.top_bid->bid->auction == this) {
+    winner = auction_leader_.top_bid->bid->bid_state;
   }
 
   // `signals` includes post auction signals from current auction.
   PostAuctionSignals signals;
-  signals.winning_bid = top_bid_ ? top_bid_->bid->bid : 0.0;
-  signals.highest_scoring_other_bid = highest_scoring_other_bid_;
+  signals.winning_bid =
+      auction_leader_.top_bid ? auction_leader_.top_bid->bid->bid : 0.0;
+  signals.highest_scoring_other_bid = auction_leader_.highest_scoring_other_bid;
   // `top_level_signals` includes post auction signals from top-level auction.
   // Will only will be used in debug report URLs of top-level seller and
   // component sellers.
@@ -1386,27 +1391,31 @@
   if (parent_) {
     top_level_signals = PostAuctionSignals();
     top_level_signals->winning_bid =
-        parent_->top_bid_ ? parent_->top_bid_->bid->bid : 0.0;
+        parent_->auction_leader_.top_bid
+            ? parent_->auction_leader_.top_bid->bid->bid
+            : 0.0;
   }
 
-  if (!top_bid_) {
-    DCHECK_EQ(highest_scoring_other_bid_, 0);
-    DCHECK(!highest_scoring_other_bid_owner_.has_value());
+  if (!auction_leader_.top_bid) {
+    DCHECK_EQ(auction_leader_.highest_scoring_other_bid, 0);
+    DCHECK(!auction_leader_.highest_scoring_other_bid_owner.has_value());
   }
 
   for (const auto& buyer_helper : buyer_helpers_) {
     const url::Origin& owner = buyer_helper->owner();
-    if (top_bid_)
-      signals.made_winning_bid = owner == top_bid_->bid->interest_group->owner;
-
-    if (highest_scoring_other_bid_owner_.has_value()) {
-      DCHECK_GT(highest_scoring_other_bid_, 0);
-      signals.made_highest_scoring_other_bid =
-          owner == highest_scoring_other_bid_owner_.value();
+    if (auction_leader_.top_bid) {
+      signals.made_winning_bid =
+          owner == auction_leader_.top_bid->bid->interest_group->owner;
     }
-    if (parent_ && parent_->top_bid_) {
+
+    if (auction_leader_.highest_scoring_other_bid_owner.has_value()) {
+      DCHECK_GT(auction_leader_.highest_scoring_other_bid, 0);
+      signals.made_highest_scoring_other_bid =
+          owner == auction_leader_.highest_scoring_other_bid_owner.value();
+    }
+    if (parent_ && parent_->auction_leader_.top_bid) {
       top_level_signals->made_winning_bid =
-          owner == parent_->top_bid_->bid->interest_group->owner;
+          owner == parent_->auction_leader_.top_bid->bid->interest_group->owner;
     }
 
     buyer_helper->TakeDebugReportUrls(winner, signals, top_level_signals,
@@ -1463,8 +1472,8 @@
 
 InterestGroupAuction::ScoredBid* InterestGroupAuction::top_bid() {
   DCHECK(all_bids_scored_);
-  DCHECK(top_bid_);
-  return top_bid_.get();
+  DCHECK(auction_leader_.top_bid);
+  return auction_leader_.top_bid.get();
 }
 
 absl::optional<uint16_t> InterestGroupAuction::GetBuyerExperimentId(
@@ -1489,6 +1498,9 @@
   return absl::nullopt;
 }
 
+InterestGroupAuction::LeaderInfo::LeaderInfo() = default;
+InterestGroupAuction::LeaderInfo::~LeaderInfo() = default;
+
 void InterestGroupAuction::OnInterestGroupRead(
     std::vector<StorageInterestGroup> interest_groups) {
   ++num_owners_loaded_;
@@ -1848,8 +1860,8 @@
 
   errors_.insert(errors_.end(), errors.begin(), errors.end());
 
-  // Use separate fields for component and top-level seller reports, so both can
-  // send debug reports.
+  // Use separate fields for component and top-level seller reports, so both
+  // can send debug reports.
   if (bid->auction == this) {
     bid->bid_state->seller_debug_loss_report_url =
         std::move(debug_loss_report_url);
@@ -1866,88 +1878,101 @@
   }
 
   // A score <= 0 means the seller rejected the bid.
-  if (score <= 0) {
-    // Need to delete `bid` because OnBiddingAndScoringComplete() may delete
-    // this, which leaves danging pointers on the stack. While this is safe to
-    // do (nothing has access to `bid` to dereference them), it makes the
-    // dangling pointer tooling sad.
-    bid.reset();
-    MaybeCompleteBiddingAndScoringPhase();
-    return;
+  if (score > 0) {
+    UpdateAuctionLeaders(std::move(bid), score,
+                         std::move(component_auction_modified_bid_params),
+                         data_version, has_data_version, auction_leader_);
   }
 
+  // Need to delete `bid` because OnBiddingAndScoringComplete() may delete
+  // this, which leaves danging pointers on the stack. While this is safe to
+  // do (nothing has access to `bid` to dereference them), it makes the
+  // dangling pointer tooling sad.
+  bid.reset();
+  MaybeCompleteBiddingAndScoringPhase();
+}
+
+void InterestGroupAuction::UpdateAuctionLeaders(
+    std::unique_ptr<Bid> bid,
+    double score,
+    auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr
+        component_auction_modified_bid_params,
+    uint32_t data_version,
+    bool has_data_version,
+    LeaderInfo& leader_info) {
   bool is_top_bid = false;
   const url::Origin& owner = bid->interest_group->owner;
 
-  if (!top_bid_ || score > top_bid_->score) {
+  if (!leader_info.top_bid || score > leader_info.top_bid->score) {
     // If there's no previous top bidder, or the bidder has the highest score,
     // need to replace the previous top bidder.
     is_top_bid = true;
-    if (top_bid_) {
-      OnNewHighestScoringOtherBid(top_bid_->score, top_bid_->bid->bid,
-                                  &top_bid_->bid->interest_group->owner);
+    if (leader_info.top_bid) {
+      OnNewHighestScoringOtherBid(
+          leader_info.top_bid->score, leader_info.top_bid->bid->bid,
+          &leader_info.top_bid->bid->interest_group->owner, leader_info);
     }
-    num_top_bids_ = 1;
-    at_most_one_top_bid_owner_ = true;
-  } else if (score == top_bid_->score) {
+    leader_info.num_top_bids = 1;
+    leader_info.at_most_one_top_bid_owner = true;
+  } else if (score == leader_info.top_bid->score) {
     // If there's a tie, replace the top-bidder with 1-in-`num_top_bids_`
     // chance. This is the select random value from a stream with fixed
     // storage problem.
-    ++num_top_bids_;
-    if (1 == base::RandInt(1, num_top_bids_))
+    ++leader_info.num_top_bids;
+    if (1 == base::RandInt(1, leader_info.num_top_bids))
       is_top_bid = true;
-    if (owner != top_bid_->bid->interest_group->owner)
-      at_most_one_top_bid_owner_ = false;
+    if (owner != leader_info.top_bid->bid->interest_group->owner)
+      leader_info.at_most_one_top_bid_owner = false;
     // If the top bid is being replaced, need to add the old top bid as a second
     // highest bid. Otherwise, need to add the current bid as a second highest
     // bid.
     double new_highest_scoring_other_bid =
-        is_top_bid ? top_bid_->bid->bid : bid->bid;
-    OnNewHighestScoringOtherBid(
-        score, new_highest_scoring_other_bid,
-        at_most_one_top_bid_owner_ ? &bid->interest_group->owner : nullptr);
-  } else if (score >= second_highest_score_) {
+        is_top_bid ? leader_info.top_bid->bid->bid : bid->bid;
+    OnNewHighestScoringOtherBid(score, new_highest_scoring_other_bid,
+                                leader_info.at_most_one_top_bid_owner
+                                    ? &bid->interest_group->owner
+                                    : nullptr,
+                                leader_info);
+  } else if (score >= leader_info.second_highest_score) {
     // Also use this bid (the most recent one) as highest scoring other bid if
     // there's a tie for second highest score.
-    OnNewHighestScoringOtherBid(score, bid->bid, &owner);
+    OnNewHighestScoringOtherBid(score, bid->bid, &owner, leader_info);
   }
 
   if (is_top_bid) {
-    top_bid_ = std::make_unique<ScoredBid>(
+    leader_info.top_bid = std::make_unique<ScoredBid>(
         score, has_data_version ? data_version : absl::optional<uint32_t>(),
         std::move(bid), std::move(component_auction_modified_bid_params));
   }
-
-  bid.reset();
-  MaybeCompleteBiddingAndScoringPhase();
 }
 
 void InterestGroupAuction::OnNewHighestScoringOtherBid(
     double score,
     double bid_value,
-    const url::Origin* owner) {
+    const url::Origin* owner,
+    LeaderInfo& leader_info) {
   // Current (the most recent) bid becomes highest scoring other bid.
-  if (score > second_highest_score_) {
-    highest_scoring_other_bid_ = bid_value;
-    num_second_highest_bids_ = 1;
+  if (score > leader_info.second_highest_score) {
+    leader_info.highest_scoring_other_bid = bid_value;
+    leader_info.num_second_highest_bids = 1;
     // Owner may be false if this is one of the bids tied for first place.
     if (!owner) {
-      highest_scoring_other_bid_owner_.reset();
+      leader_info.highest_scoring_other_bid_owner.reset();
     } else {
-      highest_scoring_other_bid_owner_ = *owner;
+      leader_info.highest_scoring_other_bid_owner = *owner;
     }
-    second_highest_score_ = score;
+    leader_info.second_highest_score = score;
     return;
   }
 
-  DCHECK_EQ(score, second_highest_score_);
-  if (!owner || *owner != highest_scoring_other_bid_owner_)
-    highest_scoring_other_bid_owner_.reset();
-  ++num_second_highest_bids_;
+  DCHECK_EQ(score, leader_info.second_highest_score);
+  if (!owner || *owner != leader_info.highest_scoring_other_bid_owner)
+    leader_info.highest_scoring_other_bid_owner.reset();
+  ++leader_info.num_second_highest_bids;
   // In case of a tie, randomly pick one. This is the select random value from a
   // stream with fixed storage problem.
-  if (1 == base::RandInt(1, num_second_highest_bids_))
-    highest_scoring_other_bid_ = bid_value;
+  if (1 == base::RandInt(1, leader_info.num_second_highest_bids))
+    leader_info.highest_scoring_other_bid = bid_value;
 }
 
 absl::optional<base::TimeDelta> InterestGroupAuction::PerBuyerTimeout(
@@ -1983,7 +2008,7 @@
 
   // If there's no winning bid, fail with kAllBidsRejected if there were any
   // bids. Otherwise, fail with kNoBids.
-  if (!top_bid_) {
+  if (!auction_leader_.top_bid) {
     if (any_bid_made_) {
       OnBiddingAndScoringComplete(AuctionResult::kAllBidsRejected);
     } else {
@@ -2036,8 +2061,10 @@
   for (auto& component_auction : component_auctions_) {
     // Leave the state of the winning component auction alone, if the winning
     // bid is from a component auction.
-    if (top_bid_ && top_bid_->bid->auction == component_auction.get())
+    if (auction_leader_.top_bid &&
+        auction_leader_.top_bid->bid->auction == component_auction.get()) {
       continue;
+    }
     if (component_auction->final_auction_result_)
       continue;
     component_auction->final_auction_result_ =
@@ -2069,8 +2096,10 @@
   // TODO(mmenke): Extract relevant data from `this` when creating the Reporter,
   // and have it handle reporting only if auction results are loaded in a frame,
   // or if there's no result.
-  if (top_bid_)
-    top_bid_->bid->auction->final_auction_result_ = AuctionResult::kSuccess;
+  if (auction_leader_.top_bid) {
+    auction_leader_.top_bid->bid->auction->final_auction_result_ =
+        AuctionResult::kSuccess;
+  }
 
   // Close all pipes, as they're no longer needed.
   ClosePipes();
diff --git a/content/browser/interest_group/interest_group_auction.h b/content/browser/interest_group/interest_group_auction.h
index cc91bd24..7096451 100644
--- a/content/browser/interest_group/interest_group_auction.h
+++ b/content/browser/interest_group/interest_group_auction.h
@@ -467,6 +467,36 @@
   // interest groups of a particular buyer, etc).
   class BuyerHelper;
 
+  struct LeaderInfo {
+    LeaderInfo();
+    ~LeaderInfo();
+
+    LeaderInfo(const LeaderInfo&) = delete;
+    LeaderInfo& operator=(LeaderInfo&) = delete;
+
+    // The highest scoring bid so far. Null if no bid has been accepted yet.
+    std::unique_ptr<ScoredBid> top_bid;
+    // Number of bidders with the same score as `top_bidder`.
+    size_t num_top_bids = 0;
+    // Number of bidders with the same score as `second_highest_score`. If the
+    // second highest score matches the highest score, this does not include the
+    // top bid.
+    size_t num_second_highest_bids = 0;
+
+    // The numeric value of the bid that got the second highest score. When
+    // there's a tie for the second highest score, one of the second highest
+    // scoring bids is randomly chosen.
+    double highest_scoring_other_bid = 0.0;
+    double second_highest_score = 0.0;
+    // Whether all bids of the highest score are from the same interest group
+    // owner.
+    bool at_most_one_top_bid_owner = true;
+    // Will be null in the end if there are interest groups having the second
+    // highest score with different owners. That includes the top bid itself, in
+    // the case there's a tie for the top bid.
+    absl::optional<url::Origin> highest_scoring_other_bid_owner;
+  };
+
   // ---------------------------------
   // Load interest group phase methods
   // ---------------------------------
@@ -567,12 +597,24 @@
       PrivateAggregationRequests pa_requests,
       const std::vector<std::string>& errors) override;
 
+  // Compares `bid` with current auction leaders in `leader_info`, updating
+  // `leader_info` if needed.
+  void UpdateAuctionLeaders(
+      std::unique_ptr<Bid> bid,
+      double score,
+      auction_worklet::mojom::ComponentAuctionModifiedBidParamsPtr
+          component_auction_modified_bid_params,
+      uint32_t data_version,
+      bool has_data_version,
+      LeaderInfo& leader_info);
+
   // Invoked when the bid becomes the new highest scoring other bid, to handle
   // calculation of post auction signals. `owner` is nullptr in the event the
   // bid is tied with the top bid, and they have different origins.
   void OnNewHighestScoringOtherBid(double score,
                                    double bid_value,
-                                   const url::Origin* owner);
+                                   const url::Origin* owner,
+                                   LeaderInfo& leader_info);
 
   absl::optional<base::TimeDelta> PerBuyerTimeout(const BidState* state);
   absl::optional<base::TimeDelta> SellerTimeout();
@@ -727,27 +769,7 @@
   std::vector<std::pair<blink::InterestGroupKey, double>>
       post_auction_priority_updates_;
 
-  // The highest scoring bid so far. Null if no bid has been accepted yet.
-  std::unique_ptr<ScoredBid> top_bid_;
-  // Number of bidders with the same score as `top_bidder`.
-  size_t num_top_bids_ = 0;
-  // Number of bidders with the same score as `second_highest_score_`. If the
-  // second highest score matches the highest score, this does not include the
-  // top bid.
-  size_t num_second_highest_bids_ = 0;
-
-  // The numeric value of the bid that got the second highest score. When
-  // there's a tie for the second highest score, one of the second highest
-  // scoring bids is randomly chosen.
-  double highest_scoring_other_bid_ = 0.0;
-  double second_highest_score_ = 0.0;
-  // Whether all bids of the highest score are from the same interest group
-  // owner.
-  bool at_most_one_top_bid_owner_ = true;
-  // Will be null in the end if there are interest groups having the second
-  // highest score with different owners. That includes the top bid itself, in
-  // the case there's a tie for the top bid.
-  absl::optional<url::Origin> highest_scoring_other_bid_owner_;
+  LeaderInfo auction_leader_;
 
   // Holds a reference to the SellerWorklet used by the auction.
   std::unique_ptr<AuctionWorkletManager::WorkletHandle> seller_worklet_handle_;
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 14dfb45..25a9534 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -3495,8 +3495,8 @@
         // if two or more such documents share a site/origin. Using
         // navigation_id_ means that each new NavigationRequest (and thus each
         // document) will get a different value.
-        if (features::kIsolateSandboxedIframesGroupingParam.Get() ==
-            features::IsolateSandboxedIframesGrouping::kPerDocument) {
+        if (blink::features::kIsolateSandboxedIframesGroupingParam.Get() ==
+            blink::features::IsolateSandboxedIframesGrouping::kPerDocument) {
           url_info_init.WithUniqueSandboxId(navigation_id_);
         }
       }
diff --git a/content/browser/site_info.cc b/content/browser/site_info.cc
index 1314683..ff5cf87b 100644
--- a/content/browser/site_info.cc
+++ b/content/browser/site_info.cc
@@ -24,6 +24,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace content {
 
@@ -845,8 +846,8 @@
     // origin, as we should be using the full origin for the SiteInstance, but
     // we don't need to track the origin like we do for OriginAgentCluster.
     if (real_url_info.is_sandboxed &&
-        features::kIsolateSandboxedIframesGroupingParam.Get() ==
-            features::IsolateSandboxedIframesGrouping::kPerOrigin) {
+        blink::features::kIsolateSandboxedIframesGroupingParam.Get() ==
+            blink::features::IsolateSandboxedIframesGrouping::kPerOrigin) {
       return origin.GetURL();
     }
 
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index f591ec3e..3c57b5c 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -31,6 +31,7 @@
 #include "content/public/common/url_utils.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/origin.h"
 
@@ -1117,8 +1118,8 @@
   // known to have the same value.
   if (SiteIsolationPolicy::IsStrictOriginIsolationEnabled() ||
       (real_src_url_info.is_sandboxed &&
-       features::kIsolateSandboxedIframesGroupingParam.Get() ==
-           features::IsolateSandboxedIframesGrouping::kPerOrigin)) {
+       blink::features::kIsolateSandboxedIframesGroupingParam.Get() ==
+           blink::features::IsolateSandboxedIframesGrouping::kPerOrigin)) {
     return src_origin == dest_origin;
   }
 
diff --git a/content/browser/site_per_process_oopsif_browsertest.cc b/content/browser/site_per_process_oopsif_browsertest.cc
index 9196ca1de..e901391 100644
--- a/content/browser/site_per_process_oopsif_browsertest.cc
+++ b/content/browser/site_per_process_oopsif_browsertest.cc
@@ -12,6 +12,7 @@
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/test/render_document_feature.h"
 #include "net/dns/mock_host_resolver.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace content {
 
@@ -24,8 +25,8 @@
       public ::testing::WithParamInterface<bool> {
  public:
   SrcdocIsolatedSandboxedIframeTest() {
-    feature_list_.InitWithFeatureState(features::kIsolateSandboxedIframes,
-                                       GetParam());
+    feature_list_.InitWithFeatureState(
+        blink::features::kIsolateSandboxedIframes, GetParam());
   }
 
   void SetUpOnMainThread() override {
@@ -50,7 +51,8 @@
     : public SitePerProcessBrowserTest {
  public:
   SitePerProcessIsolatedSandboxedIframeTest() {
-    feature_list_.InitAndEnableFeature(features::kIsolateSandboxedIframes);
+    feature_list_.InitAndEnableFeature(
+        blink::features::kIsolateSandboxedIframes);
   }
 
  private:
@@ -61,7 +63,8 @@
     : public SitePerProcessBrowserTest {
  public:
   SitePerProcessNotIsolatedSandboxedIframeTest() {
-    feature_list_.InitAndDisableFeature(features::kIsolateSandboxedIframes);
+    feature_list_.InitAndDisableFeature(
+        blink::features::kIsolateSandboxedIframes);
   }
 
  private:
@@ -75,7 +78,8 @@
  public:
   SitePerProcessPerOriginIsolatedSandboxedIframeTest() {
     feature_list_.InitWithFeaturesAndParameters(
-        {{features::kIsolateSandboxedIframes, {{"grouping", "per-origin"}}}},
+        {{blink::features::kIsolateSandboxedIframes,
+          {{"grouping", "per-origin"}}}},
         {/* disabled_features */});
   }
 
@@ -87,7 +91,8 @@
     : public SitePerProcessIsolatedSandboxedIframeTest {
  public:
   SitePerProcessIsolatedSandboxWithoutStrictSiteIsolationBrowserTest() {
-    feature_list_.InitAndEnableFeature(features::kIsolateSandboxedIframes);
+    feature_list_.InitAndEnableFeature(
+        blink::features::kIsolateSandboxedIframes);
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -150,7 +155,8 @@
  public:
   SitePerProcessPerDocumentIsolatedSandboxedIframeTest() {
     feature_list_.InitWithFeaturesAndParameters(
-        {{features::kIsolateSandboxedIframes, {{"grouping", "per-document"}}}},
+        {{blink::features::kIsolateSandboxedIframes,
+          {{"grouping", "per-document"}}}},
         {/* disabled_features */});
   }
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index fe77d59..f0048908 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -2613,7 +2613,8 @@
       attribution_manager->ClearData(
           begin, end, generic_filter, filter_builder,
           remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
-          CreateTaskCompletionClosure(TracingDataType::kConversions));
+          mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+              CreateTaskCompletionClosure(TracingDataType::kConversions)));
     } else if (storage_key.IsFirstPartyContext()) {
       // Attribution Reporting API doesn't support cross-site data deletion.
       std::unique_ptr<BrowsingDataFilterBuilder> effective_filter_builder =
@@ -2623,7 +2624,8 @@
       attribution_manager->ClearData(
           begin, end, generic_filter, effective_filter_builder.get(),
           remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
-          CreateTaskCompletionClosure(TracingDataType::kConversions));
+          mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+              CreateTaskCompletionClosure(TracingDataType::kConversions)));
     }
   }
 
@@ -2638,7 +2640,8 @@
     // `CookiesTreeModel`.
     aggregation_service->ClearData(
         begin, end, generic_filter,
-        CreateTaskCompletionClosure(TracingDataType::kAggregationService));
+        mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+            CreateTaskCompletionClosure(TracingDataType::kAggregationService)));
   }
 
   if (private_aggregation_manager &&
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 860e005..d8cd60b 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
+#include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/pattern.h"
 #include "base/strings/stringprintf.h"
@@ -1004,8 +1005,8 @@
 
   const std::vector<double>& progresses = delegate->progresses;
   // All updates should be in order ...
-  if (std::adjacent_find(progresses.begin(), progresses.end(),
-                         std::greater<>()) != progresses.end()) {
+  if (base::ranges::adjacent_find(progresses, std::greater<>()) !=
+      progresses.end()) {
     ADD_FAILURE() << "Progress values should be in order: "
                   << ::testing::PrintToString(progresses);
   }
@@ -1025,8 +1026,8 @@
 
   const std::vector<double>& progresses = delegate->progresses;
   // All updates should be in order ...
-  if (std::adjacent_find(progresses.begin(), progresses.end(),
-                         std::greater<>()) != progresses.end()) {
+  if (base::ranges::adjacent_find(progresses, std::greater<>()) !=
+      progresses.end()) {
     ADD_FAILURE() << "Progress values should be in order: "
                   << ::testing::PrintToString(progresses);
   }
diff --git a/content/public/browser/direct_sockets_delegate.h b/content/public/browser/direct_sockets_delegate.h
index 3d4424e..ee608cb 100644
--- a/content/public/browser/direct_sockets_delegate.h
+++ b/content/public/browser/direct_sockets_delegate.h
@@ -28,9 +28,6 @@
       const std::string& address,
       uint16_t port,
       blink::mojom::DirectSocketProtocolType) const = 0;
-
-  // If yes, skips post-resolve checks for Direct TCP/UDP sockets.
-  virtual bool ShouldSkipPostResolveChecks(content::RenderFrameHost*) const = 0;
 };
 
 }  // namespace content
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
index 15a5206..3cdcbe4 100644
--- a/content/public/browser/first_party_sets_handler.h
+++ b/content/public/browser/first_party_sets_handler.h
@@ -19,7 +19,6 @@
 class FirstPartySetEntry;
 class FirstPartySetsCacheFilter;
 class FirstPartySetsContextConfig;
-class GlobalFirstPartySets;
 class SchemefulSite;
 }
 
@@ -140,10 +139,6 @@
   // Resets the state on the instance for testing.
   virtual void ResetForTesting() = 0;
 
-  // Allows tests to override the post-initalization global First-Party Sets.
-  virtual void SetGlobalSetsForTesting(
-      net::GlobalFirstPartySets global_sets) = 0;
-
   // Looks up `site` in the global First-Party Sets and `config` to find its
   // associated FirstPartySetEntry.
   //
diff --git a/content/public/browser/site_isolation_policy.cc b/content/public/browser/site_isolation_policy.cc
index 16f994d..35725be 100644
--- a/content/public/browser/site_isolation_policy.cc
+++ b/content/public/browser/site_isolation_policy.cc
@@ -25,6 +25,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "third_party/blink/public/common/features.h"
 #include "url/origin.h"
 
 namespace content {
@@ -141,7 +142,8 @@
 // static
 bool SiteIsolationPolicy::AreIsolatedSandboxedIframesEnabled() {
   return !IsSiteIsolationDisabled(SiteIsolationMode::kPartialSiteIsolation) &&
-         base::FeatureList::IsEnabled(features::kIsolateSandboxedIframes);
+         base::FeatureList::IsEnabled(
+             blink::features::kIsolateSandboxedIframes);
 }
 
 // static
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 5b754837..0ca55f1 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -524,24 +524,6 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 const char kIsolateOriginsFieldTrialParamName[] = "OriginsList";
 
-// Allow process isolation of iframes with the 'sandbox' attribute set. Whether
-// or not such an iframe will be isolated may depend on options specified with
-// the attribute. Note: At present, only iframes with origin-restricted
-// sandboxes are isolated.
-BASE_FEATURE(kIsolateSandboxedIframes,
-             "IsolateSandboxedIframes",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-const base::FeatureParam<IsolateSandboxedIframesGrouping>::Option
-    isolated_sandboxed_iframes_grouping_types[] = {
-        {IsolateSandboxedIframesGrouping::kPerSite, "per-site"},
-        {IsolateSandboxedIframesGrouping::kPerOrigin, "per-origin"},
-        {IsolateSandboxedIframesGrouping::kPerDocument, "per-document"}};
-const base::FeatureParam<IsolateSandboxedIframesGrouping>
-    kIsolateSandboxedIframesGroupingParam{
-        &kIsolateSandboxedIframes, "grouping",
-        IsolateSandboxedIframesGrouping::kPerSite,
-        &isolated_sandboxed_iframes_grouping_types};
-
 // Enables the TC39 Array grouping proposal.
 BASE_FEATURE(kJavaScriptArrayGrouping,
              "JavaScriptArrayGrouping",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 1e543fa..e10cdf16 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -110,22 +110,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kIsolateFencedFrames);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kIsolateOrigins);
 CONTENT_EXPORT extern const char kIsolateOriginsFieldTrialParamName[];
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kIsolateSandboxedIframes);
-enum class IsolateSandboxedIframesGrouping {
-  // In this grouping, all isolated sandboxed iframes whose URLs share the same
-  // site in a given BrowsingInstance will share a process.
-  kPerSite,
-  // In this grouping, all isolated sandboxed iframes from a given
-  // BrowsingInstance whose URLs share the same origin will be isolated in an
-  // origin-keyed process.
-  kPerOrigin,
-  // Unlike the other two modes, which group sandboxed frames per-site or
-  // per-origin, this one doesn't do any grouping at all and uses one process
-  // per document.
-  kPerDocument,
-};
-CONTENT_EXPORT extern const base::FeatureParam<IsolateSandboxedIframesGrouping>
-    kIsolateSandboxedIframesGroupingParam;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kJavaScriptArrayGrouping);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kJavaScriptExperimentalSharedMemory);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kLazyFrameLoading);
diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.cc b/content/renderer/pepper/ppb_var_deprecated_impl.cc
index c106f9c..5becf078 100644
--- a/content/renderer/pepper/ppb_var_deprecated_impl.cc
+++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc
@@ -94,17 +94,14 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
   if (try_catch.HasException())
     return false;
 
-  v8::Local<v8::Context> context = try_catch.GetContext();
-  if (try_catch.HasException())
-    return false;
-
   bool result = false;
   if (!accessor.GetObject()->Has(context, v8_name).To(&result)) {
     try_catch.HasException();
@@ -121,17 +118,14 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
   if (try_catch.HasException())
     return false;
 
-  v8::Local<v8::Context> context = try_catch.GetContext();
-  if (try_catch.HasException())
-    return false;
-
   bool has_name = false;
   if (!accessor.GetObject()->Has(context, v8_name).To(&has_name)) {
     try_catch.HasException();
@@ -153,16 +147,17 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
   if (try_catch.HasException())
     return PP_MakeUndefined();
 
   v8::Local<v8::Value> result;
-  ScopedPPVar result_var = try_catch.FromV8Maybe(
-      accessor.GetObject()->Get(try_catch.GetContext(), v8_name));
+  ScopedPPVar result_var =
+      try_catch.FromV8Maybe(accessor.GetObject()->Get(context, v8_name));
   if (try_catch.HasException())
     return PP_MakeUndefined();
 
@@ -179,14 +174,14 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   *properties = nullptr;
   *property_count = 0;
 
-  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::Local<v8::Array> identifiers;
   if (!accessor.GetObject()->GetPropertyNames(context).ToLocal(&identifiers))
     return;
@@ -215,8 +210,9 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
   v8::Local<v8::Value> v8_value = try_catch.ToV8(value);
@@ -238,18 +234,15 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
 
   if (try_catch.HasException())
     return;
 
-  v8::Local<v8::Context> context = try_catch.GetContext();
-  if (try_catch.HasException())
-    return;
-
   if (accessor.GetObject()->Delete(context, v8_name).IsNothing()) {
     // Ensure exception object is created if V8 has thrown.
     try_catch.HasException();
@@ -277,8 +270,9 @@
 
   PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
                               exception);
+  v8::Local<v8::Context> context = try_catch.GetContext();
   v8::MicrotasksScope microtasks_scope(
-      accessor.GetObject()->GetIsolate(),
+      accessor.GetObject()->GetIsolate(), context->GetMicrotaskQueue(),
       v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
   if (try_catch.HasException())
@@ -290,7 +284,6 @@
   }
 
   v8::Local<v8::Object> function = accessor.GetObject();
-  v8::Local<v8::Context> context = accessor.instance()->GetMainWorldContext();
   v8::Local<v8::Object> recv = context->Global();
   if (v8_method_name.As<v8::String>()->Length() != 0) {
     v8::Local<v8::Value> value;
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
index e02ccd3..cac746dc 100644
--- a/content/renderer/pepper/v8_var_converter.cc
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -330,7 +330,8 @@
   v8::Isolate* isolate = context->GetIsolate();
   v8::EscapableHandleScope handle_scope(isolate);
   v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   VarHandleMap visited_ids;
   ParentVarSet parent_ids;
@@ -486,7 +487,8 @@
   v8::Isolate* isolate = context->GetIsolate();
   v8::HandleScope handle_scope(isolate);
   v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   HandleVarMap visited_handles;
   ParentHandleSet parent_handles;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index d7f19a4e..2e135b98 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/render_frame_impl.h"
 
-#include <algorithm>
 #include <map>
 #include <memory>
 #include <string>
@@ -34,6 +33,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/observer_list.h"
 #include "base/process/process.h"
+#include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
@@ -726,8 +726,7 @@
     DCHECK(std::is_sorted(params_.digests_of_uris_to_skip.begin(),
                           params_.digests_of_uris_to_skip.end()));
     // URLs are not duplicated.
-    DCHECK(std::adjacent_find(params_.digests_of_uris_to_skip.begin(),
-                              params_.digests_of_uris_to_skip.end()) ==
+    DCHECK(base::ranges::adjacent_find(params_.digests_of_uris_to_skip) ==
            params_.digests_of_uris_to_skip.end());
   }
 
@@ -3819,9 +3818,6 @@
 }
 
 void RenderFrameImpl::DidClearWindowObject() {
-  v8::MicrotasksScope microtasks(blink::MainThreadIsolate(),
-                                 v8::MicrotasksScope::kDoNotRunMicrotasks);
-
   if (enabled_bindings_ & BINDINGS_POLICY_WEB_UI)
     WebUIExtension::Install(frame_);
 
@@ -4339,6 +4335,7 @@
 void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
                                              int world_id) {
   v8::MicrotasksScope microtasks(blink::MainThreadIsolate(),
+                                 context->GetMicrotaskQueue(),
                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
   if (((enabled_bindings_ & BINDINGS_POLICY_MOJO_WEB_UI) ||
        enable_mojo_js_bindings_) &&
diff --git a/content/test/data/attribution_reporting/interop/aggregatable_dedup_key.json b/content/test/data/attribution_reporting/interop/aggregatable_dedup_key.json
new file mode 100644
index 0000000..df7579f
--- /dev/null
+++ b/content/test/data/attribution_reporting/interop/aggregatable_dedup_key.json
@@ -0,0 +1,171 @@
+{
+  "description": "2nd trigger with the same deduplication key is not attributed",
+  "input": {
+    "sources": [
+      {
+        "timestamp": "1643235573000",
+        "registration_request": {
+          "source_origin": "https://source.test",
+          "attribution_src_url": "https://reporter.test/register-source",
+          "source_type": "navigation"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-source",
+          "response": {
+            "Attribution-Reporting-Register-Source": {
+              "destination": "https://destination.test",
+              "source_event_id": "123",
+              "aggregation_keys": {
+                "a": "0x159"
+              }
+            }
+          }
+        }]
+      }
+    ],
+    "triggers": [
+      // Should result in an event-level report and an aggregatable report.
+      {
+        "timestamp": "1643235574000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "1",
+                  "deduplication_key": "1"
+                }
+              ],
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x400"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 123
+              },
+              "aggregatable_deduplication_key": "1"
+            }
+          }
+        }]
+      },
+      // Should result in an event-level report and the aggregatable report
+      // will be deduplicated.
+      {
+        "timestamp": "1643235575000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "event_trigger_data": [
+                {
+                  "trigger_data": "2"
+                }
+              ],
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x400"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 456
+              },
+              "aggregatable_deduplication_key": "1"
+            }
+          }
+        }]
+      },
+      // Should result in an aggregatable report as the deduplication key is
+      // different.
+      {
+        "timestamp": "1643235576000",
+        "registration_request": {
+          "attribution_src_url": "https://reporter.test/register-trigger",
+          "destination_origin": "https://destination.test"
+        },
+        "responses": [{
+          "url": "https://reporter.test/register-trigger",
+          "response": {
+            "Attribution-Reporting-Register-Trigger": {
+              "aggregatable_trigger_data": [
+                {
+                  "source_keys": ["a"],
+                  "key_piece": "0x400"
+                }
+              ],
+              "aggregatable_values": {
+                "a": 456
+              },
+              "aggregatable_deduplication_key": "2"
+            }
+          }
+        }]
+      }
+    ]
+  },
+  "output": {
+    "event_level_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "1"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643408373000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "randomized_trigger_rate": 0.0024,
+          "source_event_id": "123",
+          "source_type": "navigation",
+          "trigger_data": "2"
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-event-attribution",
+        "report_time": "1643408373000"
+      }
+    ],
+    "aggregatable_results": [
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x559",
+              "value": 123
+            }
+          ]
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239174000"
+      },
+      {
+        "payload": {
+          "attribution_destination": "https://destination.test",
+          "histograms": [
+            {
+              "key": "0x559",
+              "value": 456
+            }
+          ]
+        },
+        "report_url": "https://reporter.test/.well-known/attribution-reporting/report-aggregate-attribution",
+        "report_time": "1643239176000"
+      }
+    ]
+  }
+}
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 0b96724..0d1d2cd 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -907,9 +907,21 @@
 crbug.com/1284804 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/transformfeedback/random_separate_triangles.html [ Failure ]
 crbug.com/1285109 [ chromeos chromeos-board-kevin passthrough ] conformance/canvas/render-after-resize-test.html [ Failure ]
 crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/context/context-hidden-alpha.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/textures/misc/copy-tex-image-2d-formats.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/ogles/GL/array/array_001_to_006.html [ Failure ]
 crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/ogles/GL/functions/functions_033_to_040.html [ Failure ]
 crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/ogles/GL/refract/refract_001_to_006.html [ Failure ]
 crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance2/rendering/rasterizer-discard-and-implicit-clear.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance2/textures/image_bitmap_from_blob/tex-3d-rgb16f-rgb-float.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance2/textures/image_bitmap_from_blob/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] conformance2/textures/video/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/fbocolorbuffer/tex2d_03.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/fbocolorbuffer/tex3d_00.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/framebufferblit/conversion_26.html [ Failure ]
+crbug.com/1374285 [ chromeos chromeos-board-kevin passthrough ] deqp/functional/gles3/textureshadow/2d_array_nearest_always.html [ Failure ]
 crbug.com/1285111 [ chromeos chromeos-board-kevin passthrough ] conformance/textures/misc/copy-tex-image-and-sub-image-2d.html [ Failure ]
 crbug.com/1285112 [ chromeos chromeos-board-kevin passthrough ] conformance2/rendering/blitframebuffer-multisampled-readbuffer.html [ Failure ]
 crbug.com/1285114 [ chromeos chromeos-board-kevin passthrough ] conformance2/transform_feedback/transform_feedback.html [ Failure ]
diff --git a/content/web_test/renderer/gc_controller.cc b/content/web_test/renderer/gc_controller.cc
index c9b46e2..5743ad7 100644
--- a/content/web_test/renderer/gc_controller.cc
+++ b/content/web_test/renderer/gc_controller.cc
@@ -101,7 +101,8 @@
   v8::Context::Scope context_scope(context);
   v8::TryCatch try_catch(isolate);
   v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
   auto result = func->Call(context, context->Global(), 0, nullptr);
   // Swallow potential exception.
   std::ignore = result;
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index c95fcc33a..0dd00b8 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -744,8 +744,6 @@
   // Avoid installing bindings on the about:blank in between tests. This is
   // especially problematic for web platform tests that would inject javascript
   // into the page when installing bindings.
-  v8::MicrotasksScope microtask_scope(blink::MainThreadIsolate(),
-                                      v8::MicrotasksScope::kDoNotRunMicrotasks);
   if (test_runner()->TestIsRunning()) {
     blink::WebLocalFrame* frame = GetWebFrame();
     // These calls will install the various JS bindings for web tests into the
diff --git a/extensions/browser/api/storage/settings_test_util.cc b/extensions/browser/api/storage/settings_test_util.cc
index 61e18d57..15a16b9 100644
--- a/extensions/browser/api/storage/settings_test_util.cc
+++ b/extensions/browser/api/storage/settings_test_util.cc
@@ -72,15 +72,14 @@
     const std::string& id,
     Manifest::Type type,
     const std::set<std::string>& permissions_set) {
-  base::DictionaryValue manifest;
-  manifest.SetStringKey("name", std::string("Test extension ") + id);
-  manifest.SetStringKey("version", "1.0");
-  manifest.SetIntKey("manifest_version", 2);
+  base::Value::Dict manifest;
+  manifest.Set("name", std::string("Test extension ") + id);
+  manifest.Set("version", "1.0");
+  manifest.Set("manifest_version", 2);
 
-  std::unique_ptr<base::ListValue> permissions(new base::ListValue());
-  for (auto it = permissions_set.cbegin(); it != permissions_set.cend(); ++it) {
-    permissions->Append(*it);
-  }
+  base::Value::List permissions;
+  for (const auto& perm : permissions_set)
+    permissions.Append(perm);
   manifest.Set("permissions", std::move(permissions));
 
   switch (type) {
@@ -88,10 +87,10 @@
       break;
 
     case Manifest::TYPE_LEGACY_PACKAGED_APP: {
-      auto app = std::make_unique<base::DictionaryValue>();
-      auto app_launch = std::make_unique<base::DictionaryValue>();
-      app_launch->SetStringKey("local_path", "fake.html");
-      app->Set("launch", std::move(app_launch));
+      base::Value::Dict app;
+      base::Value::Dict app_launch;
+      app_launch.Set("local_path", "fake.html");
+      app.Set("launch", std::move(app_launch));
       manifest.Set("app", std::move(app));
       break;
     }
diff --git a/extensions/browser/requirements_checker_unittest.cc b/extensions/browser/requirements_checker_unittest.cc
index ddcf5ea..a454de32 100644
--- a/extensions/browser/requirements_checker_unittest.cc
+++ b/extensions/browser/requirements_checker_unittest.cc
@@ -47,21 +47,18 @@
 
 class RequirementsCheckerTest : public ExtensionsTest {
  public:
-  RequirementsCheckerTest() {
-    manifest_dict_ = std::make_unique<base::DictionaryValue>();
-  }
-
-  ~RequirementsCheckerTest() override {}
+  RequirementsCheckerTest() = default;
+  ~RequirementsCheckerTest() override = default;
 
   void CreateExtension() {
-    manifest_dict_->SetStringKey("name", "dummy name");
-    manifest_dict_->SetStringKey("version", "1");
-    manifest_dict_->SetIntKey("manifest_version", 2);
+    manifest_dict_.Set("name", "dummy name");
+    manifest_dict_.Set("version", "1");
+    manifest_dict_.Set("manifest_version", 2);
 
     std::string error;
     extension_ =
         Extension::Create(base::FilePath(), mojom::ManifestLocation::kUnpacked,
-                          *manifest_dict_, Extension::NO_FLAGS, &error);
+                          manifest_dict_, Extension::NO_FLAGS, &error);
     ASSERT_TRUE(extension_.get()) << error;
   }
 
@@ -74,15 +71,14 @@
   }
 
   void RequireWindowShape() {
-    manifest_dict_->SetBoolPath("requirements.window.shape", true);
+    manifest_dict_.SetByDottedPath("requirements.window.shape", true);
   }
 
   void RequireFeature(const char feature[]) {
-    if (!manifest_dict_->FindKey(kFeaturesKey))
-      manifest_dict_->Set(kFeaturesKey, std::make_unique<base::ListValue>());
-    base::ListValue* features_list = nullptr;
-    ASSERT_TRUE(manifest_dict_->GetList(kFeaturesKey, &features_list));
-    features_list->Append(feature);
+    base::Value* features_list = manifest_dict_.Find(kFeaturesKey);
+    if (!features_list)
+      features_list = manifest_dict_.Set(kFeaturesKey, base::Value::List());
+    features_list->GetList().Append(feature);
   }
 
   std::unique_ptr<RequirementsChecker> checker_;
@@ -90,7 +86,7 @@
 
  private:
   scoped_refptr<Extension> extension_;
-  std::unique_ptr<base::DictionaryValue> manifest_dict_;
+  base::Value::Dict manifest_dict_;
 };
 
 // Tests no requirements.
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 33cd6309..13c985e8 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -141,12 +141,12 @@
 
 // Computes the |extension_id| from the given parameters. On success, returns
 // true. On failure, populates |error| and returns false.
-bool ComputeExtensionID(const base::DictionaryValue& manifest,
+bool ComputeExtensionID(const base::DictAdapterForMigration& manifest,
                         const base::FilePath& path,
                         int creation_flags,
                         std::u16string* error,
                         ExtensionId* extension_id) {
-  if (const base::Value* public_key = manifest.FindKey(keys::kPublicKey)) {
+  if (const base::Value* public_key = manifest.Find(keys::kPublicKey)) {
     std::string public_key_bytes;
     if (!public_key->is_string() ||
         !Extension::ParsePEMKeyBytes(public_key->GetString(),
@@ -222,11 +222,12 @@
 }
 
 // static
-scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
-                                           ManifestLocation location,
-                                           const base::DictionaryValue& value,
-                                           int flags,
-                                           std::string* utf8_error) {
+scoped_refptr<Extension> Extension::Create(
+    const base::FilePath& path,
+    ManifestLocation location,
+    const base::DictAdapterForMigration& value,
+    int flags,
+    std::string* utf8_error) {
   return Extension::Create(path,
                            location,
                            value,
@@ -237,12 +238,13 @@
 
 // TODO(sungguk): Continue removing std::string errors and replacing
 // with std::u16string. See http://crbug.com/71980.
-scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
-                                           ManifestLocation location,
-                                           const base::DictionaryValue& value,
-                                           int flags,
-                                           const std::string& explicit_id,
-                                           std::string* utf8_error) {
+scoped_refptr<Extension> Extension::Create(
+    const base::FilePath& path,
+    ManifestLocation location,
+    const base::DictAdapterForMigration& value,
+    int flags,
+    const std::string& explicit_id,
+    std::string* utf8_error) {
   base::ElapsedTimer timer;
   DCHECK(utf8_error);
   std::u16string error;
@@ -262,18 +264,14 @@
   }
 
   std::unique_ptr<extensions::Manifest> manifest;
+  auto value_clone = base::DictionaryValue::From(
+      base::Value::ToUniquePtrValue(base::Value(value.Clone())));
   if (flags & FOR_LOGIN_SCREEN) {
     manifest = Manifest::CreateManifestForLoginScreen(
-        location,
-        base::DictionaryValue::From(
-            base::Value::ToUniquePtrValue(value.Clone())),
-        std::move(extension_id));
+        location, std::move(value_clone), std::move(extension_id));
   } else {
-    manifest = std::make_unique<Manifest>(
-        location,
-        base::DictionaryValue::From(
-            base::Value::ToUniquePtrValue(value.Clone())),
-        std::move(extension_id));
+    manifest = std::make_unique<Manifest>(location, std::move(value_clone),
+                                          std::move(extension_id));
   }
 
   std::vector<InstallWarning> install_warnings;
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index a184292..dde6bf6 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -32,6 +32,7 @@
 #endif
 
 namespace base {
+class DictAdapterForMigration;
 class DictionaryValue;
 }
 
@@ -155,20 +156,22 @@
   Extension(const Extension&) = delete;
   Extension& operator=(const Extension&) = delete;
 
-  static scoped_refptr<Extension> Create(const base::FilePath& path,
-                                         mojom::ManifestLocation location,
-                                         const base::DictionaryValue& value,
-                                         int flags,
-                                         std::string* error);
+  static scoped_refptr<Extension> Create(
+      const base::FilePath& path,
+      mojom::ManifestLocation location,
+      const base::DictAdapterForMigration& value,
+      int flags,
+      std::string* error);
 
   // In a few special circumstances, we want to create an Extension and give it
   // an explicit id. Most consumers should just use the other Create() method.
-  static scoped_refptr<Extension> Create(const base::FilePath& path,
-                                         mojom::ManifestLocation location,
-                                         const base::DictionaryValue& value,
-                                         int flags,
-                                         const ExtensionId& explicit_id,
-                                         std::string* error);
+  static scoped_refptr<Extension> Create(
+      const base::FilePath& path,
+      mojom::ManifestLocation location,
+      const base::DictAdapterForMigration& value,
+      int flags,
+      const ExtensionId& explicit_id,
+      std::string* error);
 
   // Valid schemes for web extent URLPatterns.
   static const int kValidWebExtentSchemes;
diff --git a/extensions/renderer/binding_generating_native_handler.cc b/extensions/renderer/binding_generating_native_handler.cc
index ce599f4..c9d27a040 100644
--- a/extensions/renderer/binding_generating_native_handler.cc
+++ b/extensions/renderer/binding_generating_native_handler.cc
@@ -83,7 +83,8 @@
     v8::Local<v8::Value> argv[] = {v8_api_name};
     v8::Local<v8::Value> binding_instance_value;
     v8::MicrotasksScope microtasks_scope(
-        v8_context->GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
+        v8_context->GetIsolate(), v8_context->GetMicrotaskQueue(),
+        v8::MicrotasksScope::kDoNotRunMicrotasks);
     // TODO(devlin): We should not be using v8::Function::Call() directly here.
     // Instead, we should use JSRunner once it's used outside native bindings.
     if (!create_binding->Call(v8_context, binding, std::size(argv), argv)
@@ -108,7 +109,8 @@
   v8::Local<v8::Value> compiled_schema;
   {
     v8::MicrotasksScope microtasks_scope(
-        v8_context->GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
+        v8_context->GetIsolate(), v8_context->GetMicrotaskQueue(),
+        v8::MicrotasksScope::kDoNotRunMicrotasks);
     // TODO(devlin): We should not be using v8::Function::Call() directly here.
     // Instead, we should use JSRunner once it's used outside native bindings.
     if (!generate->Call(v8_context, binding_instance, 0, nullptr)
diff --git a/extensions/renderer/bindings/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
index 142a44f..a7afe4d 100644
--- a/extensions/renderer/bindings/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -275,7 +275,8 @@
 
   v8::Isolate* isolate = context->GetIsolate();
   v8::MicrotasksScope microtasks_scope(
-      isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
+      isolate, context->GetMicrotaskQueue(),
+      v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   if (error.empty()) {
     v8::Local<v8::Value> result;
diff --git a/extensions/renderer/extension_js_runner.cc b/extensions/renderer/extension_js_runner.cc
index d15b259..5e3c4ab 100644
--- a/extensions/renderer/extension_js_runner.cc
+++ b/extensions/renderer/extension_js_runner.cc
@@ -46,7 +46,7 @@
   v8::Isolate* isolate = context->GetIsolate();
   DCHECK(context == isolate->GetCurrentContext());
 
-  v8::MicrotasksScope microtasks(isolate,
+  v8::MicrotasksScope microtasks(isolate, context->GetMicrotaskQueue(),
                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   v8::Local<v8::Object> global = context->Global();
diff --git a/extensions/renderer/safe_builtins.cc b/extensions/renderer/safe_builtins.cc
index 22e89a5..fae59d8 100644
--- a/extensions/renderer/safe_builtins.cc
+++ b/extensions/renderer/safe_builtins.cc
@@ -186,7 +186,9 @@
           info[2]->IsObject() &&  // args
           info[3]->IsInt32() &&   // first_arg_index
           info[4]->IsInt32());    // args_length
+    v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
     v8::MicrotasksScope microtasks(info.GetIsolate(),
+                                   context->GetMicrotaskQueue(),
                                    v8::MicrotasksScope::kDoNotRunMicrotasks);
     v8::Local<v8::Function> function = info[0].As<v8::Function>();
     v8::Local<v8::Object> recv;
@@ -207,7 +209,6 @@
     int first_arg_index = info[3].As<v8::Int32>()->Value();
     int args_length = info[4].As<v8::Int32>()->Value();
 
-    v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
     int argc = args_length - first_arg_index;
     std::unique_ptr<v8::Local<v8::Value>[]> argv(
         new v8::Local<v8::Value>[argc]);
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index d856f08..dcdd44a 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -291,7 +291,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   v8::HandleScope handle_scope(isolate());
   v8::Context::Scope scope(v8_context());
-  v8::MicrotasksScope microtasks(isolate(),
+  v8::MicrotasksScope microtasks(isolate(), v8_context()->GetMicrotaskQueue(),
                                  v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::Object> global = v8_context()->Global();
   if (web_frame_) {
@@ -550,8 +550,8 @@
     return v8::Undefined(isolate());
   }
 
-  v8::MicrotasksScope microtasks(
-      isolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
+  v8::MicrotasksScope microtasks(isolate(), v8_context()->GetMicrotaskQueue(),
+                                 v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::TryCatch try_catch(isolate());
   try_catch.SetCaptureMessage(true);
   v8::ScriptOrigin origin(isolate(), v8_helpers::ToV8StringUnsafe(
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index c3ab9da9..6327be5 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -55,11 +55,6 @@
     #`use_official_google_api_keys` was explicitly set to true and will fail to
     # build if the file is missing.
     use_official_google_api_keys = true
-
-    # TODO(crbug.com/1294931): Remove this override when fixing the issue.
-    if (is_fuchsia) {
-      use_official_google_api_keys = false
-    }
   } else {
     # Check if the key file exists.
     check_internal_result =
diff --git a/ios/chrome/browser/sync/sync_service_factory_unittest.cc b/ios/chrome/browser/sync/sync_service_factory_unittest.cc
index 2d3e9184..9fad64c 100644
--- a/ios/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/ios/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -53,7 +53,7 @@
  protected:
   // Returns the collection of default datatypes.
   syncer::ModelTypeSet DefaultDatatypes() {
-    static_assert(42 == syncer::GetNumModelTypes(),
+    static_assert(43 == syncer::GetNumModelTypes(),
                   "When adding a new type, you probably want to add it here as "
                   "well (assuming it is already enabled).");
 
@@ -78,6 +78,9 @@
     datatypes.Put(syncer::PREFERENCES);
     datatypes.Put(syncer::PRIORITY_PREFERENCES);
     datatypes.Put(syncer::READING_LIST);
+    if (base::FeatureList::IsEnabled(syncer::kSyncSegmentationDataType)) {
+      datatypes.Put(syncer::SEGMENTATION);
+    }
     // TODO(crbug.com/919489) Add SECURITY_EVENTS data type once it is enabled.
     datatypes.Put(syncer::SESSIONS);
     datatypes.Put(syncer::PROXY_TABS);
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index d898aa1..625b83ae 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -508,7 +508,8 @@
 
 // Tests that the position of the collection view is restored when navigating
 // back to the NTP.
-- (void)testPositionRestored {
+// TODO(crbug.com/1364725): Re-enable test after fixing the test failure.
+- (void)DISABLED_testPositionRestored {
   [self addMostVisitedTile];
 
   // Add suggestions to be able to scroll on iPad.
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index d6d7a37..1594946 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-f38a8f003eaa0529f41c39ef89992f8a874b0a5a
\ No newline at end of file
+41b99b27bfd6780db9527dba15b96d747097604c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index e3118dc2..4f16d8c 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-846fcf651d96e06dd692197a51338f437522041f
\ No newline at end of file
+7ee130db21651b87124ac6dbee579f815d1fcd10
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 34595f3..184c2824 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-5dc796d6d88214d693783958cfd90457d2c33537
\ No newline at end of file
+85861226e1845e497d36d4ee7b7c9ad7dbcad8a5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 7961104..5ac8e01e 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-1e256610365ffceafca6385c42989ecba29fedf9
\ No newline at end of file
+58a43c1c957d5801942af8544a3431466e51ef83
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 916d0790..f07765b3 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-30f9c067d2c5dd7f11772ad87fa1b30ded294d06
\ No newline at end of file
+37c7961be73058cfc484135a53c090819d34f464
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 649cb4a..8683eef 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b7384d271dd061cc697f0d55d3cea95b80fec4c0
\ No newline at end of file
+a95ce3b67de477578cc665a551158c801ed981a2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 21dc00d..e63a7717 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-14d12c8e80190e266070271f6b067925f5ee1896
\ No newline at end of file
+4d10d859fda92c6aebf3e93978471f3c56c3206b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index d74c544d..76a9761 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-69426fb5336094108a04cc3714fae485a452ec61
\ No newline at end of file
+465e3f571785d6ca6d5fc02034a118bbb26e822c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index 87a5f445..70ec021 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-9fb7c1cb99135f5f817ea19eed8b37491748a4dd
\ No newline at end of file
+f487ba26fd9339143451a268d7819dc3be64cf26
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index bdfb0c5..f2365e88 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-0ae74e40ec78feca8dba9f62f5b177369e3d10b2
\ No newline at end of file
+62ec1a3533e642f50e057cd43ad448429f278f75
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index f743f2a5..718635e 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2aad958e79bef7e091169afdd3a837fc4115a645
\ No newline at end of file
+cd9a9b9980e3eb7c5fed7d4bf0cb0987de95d7cd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 86782d2c..5b9679c2 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-61b225b35ea1ce3772e2fd82936bc093e60d5f3d
\ No newline at end of file
+3fe631affa823b5470a33f923e963b547020b5f5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 27e0857..4521cc51 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2931b4faf0b5afc67e39230ccfb314b15d1bcd49
\ No newline at end of file
+68a35c8454595a83d879e67c9d602f61b3cffe30
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 0bb59d5..261b0b0 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-6fe36274fb2afce6699109377148f8d3c628ef98
\ No newline at end of file
+4ae6527f1998c39c7cb9448a6eb43f77ff220ff8
\ No newline at end of file
diff --git a/media/media_options.gni b/media/media_options.gni
index b75ffaf..4650e50 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -205,8 +205,8 @@
   # Enables the use of library CDMs that implements the interface defined at
   # media/cdm/api/content_decryption_module.h. If true, the actually library CDM
   # will be hosted in the mojo CDM service running in the CDM (utility) process.
-  # Used for all desktop platforms except Fuchsia (crbug.com/1265618).
-  enable_library_cdms = toolkit_views && !is_fuchsia && !is_castos
+  # Used for all desktop platforms.
+  enable_library_cdms = toolkit_views && !is_castos
 }
 
 declare_args() {
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index a9ff250..07e4288 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -3011,6 +3011,40 @@
   return StartProbing(network, peer_address);
 }
 
+std::unique_ptr<quic::QuicPathValidationContext>
+QuicChromiumClientSession::CreateContextForMultiPortPath() {
+  if (!connection()->connection_migration_use_new_cid()) {
+    return nullptr;
+  }
+
+  // Create and configure socket on default network
+  std::unique_ptr<DatagramClientSocket> probing_socket =
+      stream_factory_->CreateSocket(net_log_.net_log(), net_log_.source());
+  if (stream_factory_->ConfigureSocket(
+          probing_socket.get(), ToIPEndPoint(peer_address()), default_network_,
+          session_key_.socket_tag()) != OK) {
+    return nullptr;
+  }
+
+  // Create new packet writer and reader on the probing socket.
+  auto probing_writer = std::make_unique<QuicChromiumPacketWriter>(
+      probing_socket.get(), task_runner_);
+  auto probing_reader = std::make_unique<QuicChromiumPacketReader>(
+      probing_socket.get(), clock_, this, yield_after_packets_,
+      yield_after_duration_, net_log_);
+
+  probing_reader->StartReading();
+  path_validation_writer_delegate_.set_network(default_network_);
+  path_validation_writer_delegate_.set_peer_address(peer_address());
+  probing_writer->set_delegate(&path_validation_writer_delegate_);
+  IPEndPoint local_address;
+  probing_socket->GetLocalAddress(&local_address);
+  return std::make_unique<QuicChromiumPathValidationContext>(
+      ToQuicSocketAddress(local_address), peer_address(), default_network_,
+      std::move(probing_socket), std::move(probing_writer),
+      std::move(probing_reader));
+}
+
 ProbingResult QuicChromiumClientSession::StartProbing(
     handles::NetworkHandle network,
     const quic::QuicSocketAddress& peer_address) {
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 54edb82..c594635 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -695,6 +695,8 @@
   void OnPathDegrading() override;
   void OnForwardProgressMadeAfterPathDegrading() override;
   void OnKeyUpdate(quic::KeyUpdateReason reason) override;
+  std::unique_ptr<quic::QuicPathValidationContext>
+  CreateContextForMultiPortPath() override;
 
   // QuicChromiumPacketReader::Visitor methods:
   bool OnReadError(int result, const DatagramClientSocket* socket) override;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 70c1595..65eaa56 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -4653,6 +4653,134 @@
   EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
 }
 
+TEST_P(QuicStreamFactoryTest, MultiPortSession) {
+  if (!version_.HasIetfQuicFrames()) {
+    // Path validator is only supported in IETF QUIC.
+    return;
+  }
+  SetIetfConnectionMigrationFlagsAndConnectionOptions();
+  // Turning on MPQC will implicitly turn on port migration.
+  quic_params_->connection_options.push_back(quic::kMPQC);
+  socket_factory_ = std::make_unique<TestPortMigrationSocketFactory>();
+  Initialize();
+
+  ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+  // Using a testing task runner so that we can control time.
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get());
+
+  MockQuicData quic_data1(version_);
+  quic_data1.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(1));
+  quic_data1.AddWrite(
+      SYNCHRONOUS,
+      ConstructGetRequestPacket(
+          3, GetNthClientInitiatedBidirectionalStreamId(0), true, true));
+  quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause
+  quic_data1.AddRead(
+      ASYNC,
+      ConstructOkResponsePacket(
+          2, GetNthClientInitiatedBidirectionalStreamId(0), false, false));
+  quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+  quic_data1.AddWrite(
+      SYNCHRONOUS,
+      client_maker_.MakeAckAndDataPacket(
+          4, /*include_version=*/false, GetQpackDecoderStreamId(),
+          /*largest_received=*/2, /*smallest_received=*/1, /*fin=*/false,
+          StreamCancellationQpackDecoderInstruction(0)));
+  quic_data1.AddWrite(
+      SYNCHRONOUS, client_maker_.MakeRstPacket(
+                       5, false, GetNthClientInitiatedBidirectionalStreamId(0),
+                       quic::QUIC_STREAM_CANCELLED));
+  quic_data1.AddSocketDataToFactory(socket_factory_.get());
+
+  // Set up the second socket data provider that is used for multi-port
+  MockQuicData quic_data2(version_);
+  quic::QuicConnectionId cid_on_new_path =
+      quic::test::TestConnectionId(12345678);
+
+  client_maker_.set_connection_id(cid_on_new_path);
+  // Connectivity probe to be sent on the new path.
+  quic_data2.AddWrite(SYNCHRONOUS,
+                      client_maker_.MakeConnectivityProbingPacket(2, true));
+  quic_data2.AddRead(ASYNC, ERR_IO_PENDING);  // Pause
+  // Connectivity probe to receive from the server.
+  quic_data2.AddRead(ASYNC,
+                     server_maker_.MakeConnectivityProbingPacket(1, false));
+
+  quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+  quic_data2.AddSocketDataToFactory(socket_factory_.get());
+
+  // Create request and QuicHttpStream.
+  QuicStreamRequest request(factory_.get());
+  EXPECT_EQ(ERR_IO_PENDING,
+            request.Request(
+                scheme_host_port_, version_, privacy_mode_, DEFAULT_PRIORITY,
+                SocketTag(), NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
+                /*use_dns_aliases=*/true, /*require_dns_https_alpn=*/false,
+                /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_,
+                failed_on_default_network_callback_, callback_.callback()));
+  EXPECT_THAT(callback_.WaitForResult(), IsOk());
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
+  EXPECT_TRUE(stream.get());
+
+  // Cause QUIC stream to be created.
+  HttpRequestInfo request_info;
+  request_info.method = "GET";
+  request_info.url = url_;
+  request_info.traffic_annotation =
+      MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+  stream->RegisterRequest(&request_info);
+  EXPECT_EQ(OK, stream->InitializeStream(true, DEFAULT_PRIORITY, net_log_,
+                                         CompletionOnceCallback()));
+
+  // Ensure that session is alive and active.
+  QuicChromiumClientSession* session = GetActiveSession(scheme_host_port_);
+  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+  EXPECT_TRUE(HasActiveSession(scheme_host_port_));
+  // Manually initialize the connection's self address. In real life, the
+  // initialization will be done during crypto handshake.
+  IPEndPoint ip;
+  session->GetDefaultSocket()->GetLocalAddress(&ip);
+  quic::test::QuicConnectionPeer::SetSelfAddress(session->connection(),
+                                                 ToQuicSocketAddress(ip));
+
+  // This will trigger multi-port path creation.
+  MaybeMakeNewConnectionIdAvailableToSession(cid_on_new_path, session);
+
+  // Send GET request on stream.
+  HttpResponseInfo response;
+  HttpRequestHeaders request_headers;
+  EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+                                    callback_.callback()));
+
+  // Resume quic data and a connectivity probe response will be read on the new
+  // socket.
+  quic_data2.Resume();
+
+  // The response is received on the default path.
+  quic_data1.Resume();
+  // Response headers are received over the new port.
+  EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
+  EXPECT_EQ(200, response.headers->response_code());
+
+  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+  EXPECT_TRUE(HasActiveSession(scheme_host_port_));
+  EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+  // The periodic probing is handled and tested in quiche.
+  EXPECT_TRUE(quic::test::QuicConnectionPeer::GetMultiPortProbingAlarm(
+                  session->connection())
+                  ->IsSet());
+
+  stream.reset();
+  EXPECT_TRUE(quic_data1.AllReadDataConsumed());
+  EXPECT_TRUE(quic_data1.AllWriteDataConsumed());
+  EXPECT_TRUE(quic_data2.AllReadDataConsumed());
+  EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
+}
+
 TEST_P(QuicStreamFactoryTest,
        MigratePortOnPathDegrading_WithoutNetworkHandle_PathValidator) {
   if (!version_.HasIetfQuicFrames()) {
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 5d754a7e..2446869d 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -12,6 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -499,9 +500,9 @@
   initiator_ = initiator;
 }
 
-void URLRequest::set_method(const std::string& method) {
+void URLRequest::set_method(base::StringPiece method) {
   DCHECK(!is_pending_);
-  method_ = method;
+  method_ = std::string(method);
 }
 
 #if BUILDFLAG(ENABLE_REPORTING)
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 18db4ce..778a965 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -14,6 +14,7 @@
 #include "base/containers/flat_set.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece_forward.h"
 #include "base/supports_user_data.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
@@ -346,11 +347,12 @@
   // This method may only be called before Start().
   void set_initiator(const absl::optional<url::Origin>& initiator);
 
-  // The request method, as an uppercase string.  "GET" is the default value.
-  // The request method may only be changed before Start() is called and
-  // should only be assigned an uppercase value.
+  // The request method.  "GET" is the default value. The request method may
+  // only be changed before Start() is called. Request methods are
+  // case-sensitive, so standard HTTP methods like GET or POST should be
+  // specified in uppercase.
   const std::string& method() const { return method_; }
-  void set_method(const std::string& method);
+  void set_method(base::StringPiece method);
 
 #if BUILDFLAG(ENABLE_REPORTING)
   // Reporting upload nesting depth of this request.
@@ -953,7 +955,7 @@
   bool force_main_frame_for_same_site_cookies_ = false;
   absl::optional<url::Origin> initiator_;
   GURL delegate_redirect_url_;
-  std::string method_;  // "GET", "POST", etc. Should be all uppercase.
+  std::string method_;  // "GET", "POST", etc. Case-sensitive.
   std::string referrer_;
   ReferrerPolicy referrer_policy_ =
       ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 0a622f7f..e2a68e8 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -572,6 +572,12 @@
       }
     }
 
+    if (rv == OK && request_info_.method == "CONNECT") {
+      // CONNECT has different kinds of targets than other methods (RFC 9110,
+      // section 9.3.6), which are incompatible with URLRequest.
+      rv = ERR_METHOD_NOT_SUPPORTED;
+    }
+
     if (rv == OK) {
       transaction_->SetConnectedCallback(base::BindRepeating(
           &URLRequestHttpJob::NotifyConnectedCallback, base::Unretained(this)));
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 4892eb28..43aa79a 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -3988,7 +3988,7 @@
       std::unique_ptr<URLRequest> r(default_context().CreateRequest(
           test_server_.GetURL("/echo"), DEFAULT_PRIORITY, &d,
           TRAFFIC_ANNOTATION_FOR_TESTS));
-      r->set_method(method.c_str());
+      r->set_method(method);
 
       r->set_upload(CreateSimpleUploadData(uploadBytes.get()));
 
@@ -8451,9 +8451,6 @@
   HTTPRedirectMethodTest(url, "PUT", "GET", true);
   HTTPRedirectMethodTest(url, "HEAD", "HEAD", false);
 
-  HTTPRedirectOriginHeaderTest(url, "CONNECT", "GET", std::string());
-  HTTPRedirectOriginHeaderTest(https_redirect_url, "CONNECT", "GET",
-                               std::string());
   HTTPRedirectOriginHeaderTest(url, "DELETE", "GET", std::string());
   HTTPRedirectOriginHeaderTest(https_redirect_url, "DELETE", "GET",
                                std::string());
@@ -13009,6 +13006,18 @@
   EXPECT_EQ("/auth-basic", r->auth_challenge_info()->path);
 }
 
+TEST_F(URLRequestTestHTTP, ConnectNoSupported) {
+  ASSERT_TRUE(http_test_server()->Start());
+  TestDelegate delegate;
+  std::unique_ptr<URLRequest> r(default_context().CreateRequest(
+      http_test_server()->GetURL("/"), DEFAULT_PRIORITY, &delegate,
+      TRAFFIC_ANNOTATION_FOR_TESTS));
+  r->set_method("CONNECT");
+  r->Start();
+  delegate.RunUntilComplete();
+  EXPECT_EQ(ERR_METHOD_NOT_SUPPORTED, delegate.request_status());
+}
+
 class URLRequestDnsAliasTest : public TestWithTaskEnvironment {
  protected:
   URLRequestDnsAliasTest() {
diff --git a/services/device/generic_sensor/platform_sensor_fusion.cc b/services/device/generic_sensor/platform_sensor_fusion.cc
index c8f2560a..d08aa3b 100644
--- a/services/device/generic_sensor/platform_sensor_fusion.cc
+++ b/services/device/generic_sensor/platform_sensor_fusion.cc
@@ -4,8 +4,6 @@
 
 #include "services/device/generic_sensor/platform_sensor_fusion.h"
 
-#include <algorithm>
-
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/memory/raw_ptr.h"
@@ -47,7 +45,7 @@
     const auto& types = fusion_algorithm_->source_types();
     DCHECK(!types.empty());
     // Make sure there are no dups.
-    DCHECK(std::adjacent_find(types.begin(), types.end()) == types.end());
+    DCHECK(base::ranges::adjacent_find(types) == types.end());
     DCHECK(result_callback_);
     DCHECK(reading_buffer_);
     DCHECK(provider_);
diff --git a/testing/buildbot/chromium.rust.json b/testing/buildbot/chromium.rust.json
index d3f3ce15..1795656 100644
--- a/testing/buildbot/chromium.rust.json
+++ b/testing/buildbot/chromium.rust.json
@@ -209,6 +209,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "base_unittests",
@@ -221,6 +226,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "gnrt_unittests",
@@ -233,6 +243,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "rust_gtest_interop_unittests",
@@ -246,6 +261,11 @@
         "name": "test_cpp_including_rust_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_cpp_including_rust_unittests",
@@ -259,6 +279,11 @@
         "name": "test_serde_json_lenient",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_serde_json_lenient",
@@ -275,6 +300,11 @@
         "name": "autocxx_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "autocxx_tests",
@@ -289,6 +319,11 @@
         "name": "build_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "build_rust_tests",
@@ -303,6 +338,11 @@
         "name": "mojo_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "mojo_rust_tests",
@@ -326,6 +366,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "base_unittests",
@@ -338,6 +383,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "gnrt_unittests",
@@ -350,6 +400,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "rust_gtest_interop_unittests",
@@ -363,6 +418,11 @@
         "name": "test_cpp_including_rust_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_cpp_including_rust_unittests",
@@ -376,6 +436,11 @@
         "name": "test_serde_json_lenient",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_serde_json_lenient",
@@ -392,6 +457,11 @@
         "name": "autocxx_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "autocxx_tests",
@@ -406,6 +476,11 @@
         "name": "build_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "build_rust_tests",
@@ -420,6 +495,11 @@
         "name": "mojo_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "mojo_rust_tests",
@@ -443,6 +523,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "base_unittests",
@@ -455,6 +540,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "gnrt_unittests",
@@ -467,6 +557,11 @@
         },
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "rust_gtest_interop_unittests",
@@ -480,6 +575,11 @@
         "name": "test_cpp_including_rust_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_cpp_including_rust_unittests",
@@ -493,6 +593,11 @@
         "name": "test_serde_json_lenient",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "test_serde_json_lenient",
@@ -509,6 +614,11 @@
         "name": "autocxx_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "autocxx_tests",
@@ -523,6 +633,11 @@
         "name": "build_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "build_rust_tests",
@@ -537,6 +652,11 @@
         "name": "mojo_rust_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "mojo_rust_tests",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 4ce3966..a2e4fc2 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5572,6 +5572,9 @@
           'rust_build_tests',
           'rust_autocxx_tests',
         ],
+        'mixins': [
+          'linux-bionic'
+        ],
         'test_suites': {
           'gtest_tests': 'rust_gtests',
           'isolated_scripts': 'rust_native_tests',
@@ -5585,6 +5588,9 @@
           'rust_build_tests',
           'rust_autocxx_tests',
         ],
+        'mixins': [
+          'linux-bionic'
+        ],
         'test_suites': {
           'gtest_tests': 'rust_gtests',
           'isolated_scripts': 'rust_native_tests',
@@ -5598,6 +5604,9 @@
           'rust_build_tests',
           'rust_autocxx_tests',
         ],
+        'mixins': [
+          'linux-bionic'
+        ],
         'test_suites': {
           'gtest_tests': 'rust_gtests',
           'isolated_scripts': 'rust_native_tests',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8a906c7..f7c1742 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6650,7 +6650,7 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "nesting": "10"
+                        "nesting": "15"
                     },
                     "enable_features": [
                         "MaxUnthrottledTimeoutNestingLevel"
@@ -10861,11 +10861,16 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "min_gms_core_version_no_dots": "222612000",
-                        "stage": "0"
+                        "api_error_list_version": "1",
+                        "fallback_on_user_affecting_read_operations": "true",
+                        "ignored_api_errors": "11005,11006",
+                        "min_gms_core_version_no_dots": "223012000",
+                        "retriable_api_errors": "7,17,20,22"
                     },
                     "enable_features": [
-                        "UnifiedPasswordManagerAndroid"
+                        "UnifiedPasswordManagerAndroid",
+                        "UnifiedPasswordManagerErrorMessages",
+                        "UnifiedPasswordManagerReenrollment"
                     ]
                 }
             ]
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 96e7f3f..1dcfe45 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1220,7 +1220,7 @@
              "MaxUnthrottledTimeoutNestingLevel",
              base::FEATURE_DISABLED_BY_DEFAULT);
 const base::FeatureParam<int> kMaxUnthrottledTimeoutNestingLevelParam{
-    &kMaxUnthrottledTimeoutNestingLevel, "nesting", 10};
+    &kMaxUnthrottledTimeoutNestingLevel, "nesting", 15};
 bool IsMaxUnthrottledTimeoutNestingLevelEnabled() {
   auto policy = GetUnthrottledNestedTimeoutPolicyOverride();
   if (policy != UnthrottledNestedTimeoutPolicyOverride::kNoOverride)
@@ -1609,10 +1609,6 @@
              "FastPathPaintPropertyUpdates",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kWildcardSubdomainsInPermissionsPolicy,
-             "WildcardSubdomainsInPermissionsPolicy",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kThreadedBodyLoader,
              "ThreadedBodyLoader",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -1632,5 +1628,23 @@
              "WebRtcCombinedNetworkAndWorkerThread",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Allow process isolation of iframes with the 'sandbox' attribute set. Whether
+// or not such an iframe will be isolated may depend on options specified with
+// the attribute. Note: At present, only iframes with origin-restricted
+// sandboxes are isolated.
+BASE_FEATURE(kIsolateSandboxedIframes,
+             "IsolateSandboxedIframes",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+const base::FeatureParam<IsolateSandboxedIframesGrouping>::Option
+    isolated_sandboxed_iframes_grouping_types[] = {
+        {IsolateSandboxedIframesGrouping::kPerSite, "per-site"},
+        {IsolateSandboxedIframesGrouping::kPerOrigin, "per-origin"},
+        {IsolateSandboxedIframesGrouping::kPerDocument, "per-document"}};
+const base::FeatureParam<IsolateSandboxedIframesGrouping>
+    kIsolateSandboxedIframesGroupingParam{
+        &kIsolateSandboxedIframes, "grouping",
+        IsolateSandboxedIframesGrouping::kPerSite,
+        &isolated_sandboxed_iframes_grouping_types};
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/common/permissions/permission_utils.cc b/third_party/blink/common/permissions/permission_utils.cc
index c8b01c2..c5de113 100644
--- a/third_party/blink/common/permissions/permission_utils.cc
+++ b/third_party/blink/common/permissions/permission_utils.cc
@@ -190,7 +190,7 @@
       return PermissionType::NFC;
     case PermissionName::STORAGE_ACCESS:
       return PermissionType::STORAGE_ACCESS_GRANT;
-    case PermissionName::WINDOW_PLACEMENT:
+    case PermissionName::WINDOW_MANAGEMENT:
       return PermissionType::WINDOW_PLACEMENT;
     case PermissionName::LOCAL_FONTS:
       return PermissionType::LOCAL_FONTS;
diff --git a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc
index 4244136..7ad2f84e 100644
--- a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc
+++ b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc
@@ -4,10 +4,8 @@
 
 #include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
 
-#include "base/feature_list.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "services/network/public/cpp/cors/origin_access_entry.h"
-#include "third_party/blink/public/common/features.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -41,9 +39,7 @@
   // subdomain wildcard if there is a exactly one `*` and it's after the scheme
   // and before the rest of the host. Invalid origins return an instance of
   // OriginWithPossibleWildcards with an opaque origin member.
-  if (base::FeatureList::IsEnabled(
-          features::kWildcardSubdomainsInPermissionsPolicy) &&
-      type == NodeType::kHeader &&
+  if (type == NodeType::kHeader &&
       (wildcard_pos = allowlist_entry.find("://*.")) != std::string::npos &&
       allowlist_entry.find('*') == allowlist_entry.rfind('*')) {
     // We need a copy as erase modifies the original.
@@ -90,13 +86,7 @@
 
 bool OriginWithPossibleWildcards::DoesMatchOrigin(
     const url::Origin& match_origin) const {
-  // TODO(crbug.com/1345994): Merge logic with IsSubdomainOfHost where possible.
   if (has_subdomain_wildcard) {
-    // Only try to match at all if wildcard matching is enabled.
-    if (!base::FeatureList::IsEnabled(
-            features::kWildcardSubdomainsInPermissionsPolicy)) {
-      return false;
-    }
     // This function won't match https://*.foo.com with https://foo.com.
     if (origin == match_origin) {
       return false;
diff --git a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc
index 621b2d2..404f0b6 100644
--- a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc
+++ b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc
@@ -5,34 +5,16 @@
 #include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
 
 #include "base/test/gtest_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
 namespace blink {
 
-class OriginWithPossibleWildcardsTest : public testing::TestWithParam<bool> {
- public:
-  void SetUp() override {
-    scoped_feature_list_.InitWithFeatureState(
-        features::kWildcardSubdomainsInPermissionsPolicy,
-        HasWildcardSubdomainsInPermissionsPolicy());
-  }
-
-  bool HasWildcardSubdomainsInPermissionsPolicy() { return GetParam(); }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-INSTANTIATE_TEST_SUITE_P(All, OriginWithPossibleWildcardsTest, testing::Bool());
-
-TEST_P(OriginWithPossibleWildcardsTest, DoesMatchOrigin) {
+TEST(OriginWithPossibleWildcardsTest, DoesMatchOrigin) {
   // Tuple of {origin to test, origin in policy, w/ wildcard, result,
   // description}.
   const auto& values = {
@@ -78,23 +60,20 @@
                       url::Origin::Create(GURL("https://foo.com")), true, false,
                       "Same origin, w/ wildcard"),
       std::make_tuple(url::Origin::Create(GURL("https://bar.foo.com")),
-                      url::Origin::Create(GURL("https://foo.com")), true,
-                      HasWildcardSubdomainsInPermissionsPolicy(),
+                      url::Origin::Create(GURL("https://foo.com")), true, true,
                       "Subdomain matches, w/ wildcard"),
       std::make_tuple(url::Origin::Create(GURL("http://bar.foo.com")),
                       url::Origin::Create(GURL("https://foo.com")), true, false,
                       "Different scheme, w/ wildcard"),
       std::make_tuple(url::Origin::Create(GURL("https://baz.bar.foo.com")),
-                      url::Origin::Create(GURL("https://foo.com")), true,
-                      HasWildcardSubdomainsInPermissionsPolicy(),
+                      url::Origin::Create(GURL("https://foo.com")), true, true,
                       "Sub-subdomain matches, w/ wildcard"),
       std::make_tuple(url::Origin::Create(GURL("https://foo.com")),
                       url::Origin::Create(GURL("https://bar.foo.com")), true,
                       false, "Subdomain doesn't match, w/ wildcard"),
       std::make_tuple(url::Origin::Create(GURL("https://bar.foo.com")),
                       url::Origin::Create(GURL("https://foo.com:443")), true,
-                      HasWildcardSubdomainsInPermissionsPolicy(),
-                      "Ignore default port, w/ wildcard"),
+                      true, "Ignore default port, w/ wildcard"),
       std::make_tuple(url::Origin(),
                       url::Origin::Create(GURL("https://foo.com")), true, false,
                       "Opaque to origin, w/ wildcard"),
@@ -121,7 +100,7 @@
   }
 }
 
-TEST_P(OriginWithPossibleWildcardsTest, Parse) {
+TEST(OriginWithPossibleWildcardsTest, Parse) {
   // Tuple of {serialized value, type, origin, wildcard, description}.
   const auto& values = {
       std::make_tuple("https://foo.com",
@@ -134,10 +113,7 @@
                       "Origin without subdomain wildcard in attribute"),
       std::make_tuple(
           "https://*.foo.com", OriginWithPossibleWildcards::NodeType::kHeader,
-          HasWildcardSubdomainsInPermissionsPolicy() ? "https://foo.com"
-                                                     : "https://%2A.foo.com",
-          HasWildcardSubdomainsInPermissionsPolicy(),
-          "Origin with subdomain wildcard in header"),
+          "https://foo.com", true, "Origin with subdomain wildcard in header"),
       std::make_tuple("https://*.foo.com",
                       OriginWithPossibleWildcards::NodeType::kAttribute,
                       "https://%2A.foo.com", false,
@@ -173,10 +149,7 @@
           "Origin with only private tld host wildcard in attribute"),
       std::make_tuple("https://*.foo.appspot.com",
                       OriginWithPossibleWildcards::NodeType::kHeader,
-                      HasWildcardSubdomainsInPermissionsPolicy()
-                          ? "https://foo.appspot.com"
-                          : "https://%2A.foo.appspot.com",
-                      HasWildcardSubdomainsInPermissionsPolicy(),
+                      "https://foo.appspot.com", true,
                       "Origin with private tld host wildcard in header"),
       std::make_tuple("https://*.foo.appspot.com",
                       OriginWithPossibleWildcards::NodeType::kAttribute,
@@ -184,10 +157,7 @@
                       "Origin with private tld host wildcard in attribute"),
       std::make_tuple("https://*.example.test",
                       OriginWithPossibleWildcards::NodeType::kHeader,
-                      HasWildcardSubdomainsInPermissionsPolicy()
-                          ? "https://example.test"
-                          : "https://%2A.example.test",
-                      HasWildcardSubdomainsInPermissionsPolicy(),
+                      "https://example.test", true,
                       "Origin with unknown tld host wildcard in header"),
       std::make_tuple("https://*.example.test",
                       OriginWithPossibleWildcards::NodeType::kAttribute,
@@ -228,7 +198,7 @@
   }
 }
 
-TEST_P(OriginWithPossibleWildcardsTest, Serialize) {
+TEST(OriginWithPossibleWildcardsTest, Serialize) {
   // Tuple of {origin, wildcard, serialized value, description}.
   const auto& values = {
       std::make_tuple("https://foo.com", false, "https://foo.com",
@@ -249,7 +219,7 @@
   }
 }
 
-TEST_P(OriginWithPossibleWildcardsTest, Constructors) {
+TEST(OriginWithPossibleWildcardsTest, Constructors) {
   OriginWithPossibleWildcards a;
   OriginWithPossibleWildcards b(url::Origin(), false);
   OriginWithPossibleWildcards c(b);
@@ -261,7 +231,7 @@
   EXPECT_EQ(a, b);
 }
 
-TEST_P(OriginWithPossibleWildcardsTest, Opaque) {
+TEST(OriginWithPossibleWildcardsTest, Opaque) {
   EXPECT_DCHECK_DEATH(OriginWithPossibleWildcards(url::Origin(), true));
   OriginWithPossibleWildcards original(url::Origin(), false);
   original.has_subdomain_wildcard = true;
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 11d35671..e739ed13 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -850,10 +850,6 @@
 // applied directly instead of using the property tree builder.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kFastPathPaintPropertyUpdates);
 
-// If enabled, wildcard subdomains are supported in permissions policies.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(
-    kWildcardSubdomainsInPermissionsPolicy);
-
 // If enabled, reads and decodes navigation body data off the main thread.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kThreadedBodyLoader);
 
@@ -872,6 +868,24 @@
 // Combine WebRTC Network and Worker threads. More info at crbug.com/1373439.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kWebRtcCombinedNetworkAndWorkerThread);
 
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kIsolateSandboxedIframes);
+enum class IsolateSandboxedIframesGrouping {
+  // In this grouping, all isolated sandboxed iframes whose URLs share the same
+  // site in a given BrowsingInstance will share a process.
+  kPerSite,
+  // In this grouping, all isolated sandboxed iframes from a given
+  // BrowsingInstance whose URLs share the same origin will be isolated in an
+  // origin-keyed process.
+  kPerOrigin,
+  // Unlike the other two modes, which group sandboxed frames per-site or
+  // per-origin, this one doesn't do any grouping at all and uses one process
+  // per document.
+  kPerDocument,
+};
+BLINK_COMMON_EXPORT extern const base::FeatureParam<
+    IsolateSandboxedIframesGrouping>
+    kIsolateSandboxedIframesGroupingParam;
+
 }  // namespace features
 }  // namespace blink
 
diff --git a/third_party/blink/public/mojom/permissions/permission.mojom b/third_party/blink/public/mojom/permissions/permission.mojom
index cf00630..8721ae5 100644
--- a/third_party/blink/public/mojom/permissions/permission.mojom
+++ b/third_party/blink/public/mojom/permissions/permission.mojom
@@ -28,7 +28,7 @@
   SYSTEM_WAKE_LOCK,
   NFC,
   STORAGE_ACCESS,
-  WINDOW_PLACEMENT,
+  WINDOW_MANAGEMENT,
   LOCAL_FONTS,
   DISPLAY_CAPTURE,
 };
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 74072583..f9a3a06 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -1428,28 +1428,58 @@
   wtf_size_t auto_repeat_insertion_point =
       computed_grid_track_list.auto_repeat_insertion_point;
 
-  // If the element is a grid container, the resolved value is the used value,
-  // specifying track sizes in pixels and expanding the repeat() notation.
   if (is_layout_grid) {
     const auto* grid = ToInterface<LayoutNGGridInterface>(layout_object);
-    OrderedNamedLinesCollectorInGridLayout collector(
-        computed_grid_track_list.ordered_named_grid_lines,
-        computed_grid_track_list.auto_repeat_ordered_named_grid_lines,
-        auto_repeat_insertion_point,
-        grid->AutoRepeatCountForDirection(direction),
-        auto_repeat_track_sizes.size());
-    auto getTrackSize = [&](const LayoutUnit& v) {
-      return ZoomAdjustedPixelValue(v, style);
-    };
-    // Named grid line indices are relative to the explicit grid, but we are
-    // including all tracks. So we need to subtract the number of leading
-    // implicit tracks in order to get the proper line index.
-    int offset = -base::checked_cast<int>(
-        grid->ExplicitGridStartForDirection(direction));
-    PopulateGridTrackList(list, collector,
-                          grid->TrackSizesForComputedStyle(direction),
-                          getTrackSize, offset);
-    return list;
+    if (computed_grid_track_list.IsSubgriddedAxis()) {
+      // If the track list is subgridded, return the word 'subgrid', followed by
+      // the specified named grid lines in brackets. Empty brackets are also
+      // valid.
+      list->Append(
+          *MakeGarbageCollected<CSSIdentifierValue>(CSSValueID::kSubgrid));
+
+      wtf_size_t subgrid_line_names_start =
+          grid->ExplicitGridStartForDirection(direction);
+      wtf_size_t subgrid_line_names_end =
+          grid->ExplicitGridEndForDirection(direction);
+      for (wtf_size_t i = subgrid_line_names_start; i <= subgrid_line_names_end;
+           ++i) {
+        auto iter = computed_grid_track_list.ordered_named_grid_lines.find(i);
+
+        cssvalue::CSSBracketedValueList* value_list =
+            MakeGarbageCollected<cssvalue::CSSBracketedValueList>();
+
+        if (iter != computed_grid_track_list.ordered_named_grid_lines.end()) {
+          for (auto named_grid_line : iter->value) {
+            value_list->Append(*MakeGarbageCollected<CSSCustomIdentValue>(
+                named_grid_line.line_name));
+          }
+        }
+        list->Append(*value_list);
+      }
+      return list;
+    } else {
+      // If the element is a grid container, the resolved value is the used
+      // value, specifying track sizes in pixels and expanding the repeat()
+      // notation.
+      OrderedNamedLinesCollectorInGridLayout collector(
+          computed_grid_track_list.ordered_named_grid_lines,
+          computed_grid_track_list.auto_repeat_ordered_named_grid_lines,
+          auto_repeat_insertion_point,
+          grid->AutoRepeatCountForDirection(direction),
+          auto_repeat_track_sizes.size());
+      auto getTrackSize = [&](const LayoutUnit& v) {
+        return ZoomAdjustedPixelValue(v, style);
+      };
+      // Named grid line indices are relative to the explicit grid, but we are
+      // including all tracks. So we need to subtract the number of leading
+      // implicit tracks in order to get the proper line index.
+      int offset = -base::checked_cast<int>(
+          grid->ExplicitGridStartForDirection(direction));
+      PopulateGridTrackList(list, collector,
+                            grid->TrackSizesForComputedStyle(direction),
+                            getTrackSize, offset);
+      return list;
+    }
   }
 
   // Otherwise, the resolved value is the computed value, preserving repeat().
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index c28f7f9..e2cd4b4 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1015,9 +1015,8 @@
     bool is_first_repeat = false) {
   DCHECK(value.IsGridLineNamesValue());
 
-  // TODO(ansollan): Serialize subgrid's empty lines.
   for (auto& named_grid_line_value : To<CSSValueList>(value)) {
-    String named_grid_line =
+    AtomicString named_grid_line =
         To<CSSCustomIdentValue>(*named_grid_line_value).Value();
     NamedGridLinesMap::AddResult result =
         named_grid_lines.insert(named_grid_line, Vector<wtf_size_t>());
diff --git a/third_party/blink/renderer/core/css/transition.css b/third_party/blink/renderer/core/css/transition.css
index 2a33056..404abc0e 100644
--- a/third_party/blink/renderer/core/css/transition.css
+++ b/third_party/blink/renderer/core/css/transition.css
@@ -11,7 +11,12 @@
 
 html::page-transition {
   position: fixed;
-  inset: 0;
+  top: 0;
+  left: 0;
+
+  /* Size will be set dynamically to correctly account for UI such as
+     virtual-keyboards */
+
   pointer-events: none;
 }
 
diff --git a/third_party/blink/renderer/core/document_transition/document_transition.h b/third_party/blink/renderer/core/document_transition/document_transition.h
index 5e61b0b..f13e7d6 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition.h
+++ b/third_party/blink/renderer/core/document_transition/document_transition.h
@@ -135,6 +135,10 @@
 
   bool IsIdle() const { return state_ == State::kIdle; }
 
+  bool IsRootTransitioning() const {
+    return style_tracker_ && style_tracker_->IsRootTransitioning();
+  }
+
   // In physical pixels. See comments on equivalent methods in
   // DocumentTransitionStyleTracker for info.
   gfx::Rect GetSnapshotViewportRect() const;
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_style_builder.cc b/third_party/blink/renderer/core/document_transition/document_transition_style_builder.cc
index 72b8880c..c696f80 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_style_builder.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition_style_builder.cc
@@ -156,10 +156,23 @@
   AddContainerStyles(tag, rule_builder.ReleaseString());
 }
 
-void DocumentTransitionStyleBuilder::AddRootStyles(const String& rules) {
+void DocumentTransitionStyleBuilder::AddRootStyles(
+    const gfx::RectF& snapshot_viewport_rect_css) {
   builder_.Append(kTransitionRootName);
   builder_.Append("{ ");
-  builder_.Append(rules);
+  builder_.AppendFormat(
+      R"CSS(
+        width: %.3fpx;
+        height: %.3fpx;
+      )CSS",
+      snapshot_viewport_rect_css.width(), snapshot_viewport_rect_css.height());
+  if (!snapshot_viewport_rect_css.OffsetFromOrigin().IsZero()) {
+    builder_.AppendFormat(
+        R"CSS(
+          transform: translate(%.3fpx, %.3fpx);
+        )CSS",
+        snapshot_viewport_rect_css.x(), snapshot_viewport_rect_css.y());
+  }
   builder_.Append(" }");
 }
 
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_style_builder.h b/third_party/blink/renderer/core/document_transition/document_transition_style_builder.h
index e0367613..6b05019 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_style_builder.h
+++ b/third_party/blink/renderer/core/document_transition/document_transition_style_builder.h
@@ -37,7 +37,7 @@
                           const ContainerProperties& properties,
                           WritingMode writing_mode);
 
-  void AddRootStyles(const String& rules);
+  void AddRootStyles(const gfx::RectF& snapshot_viewport_rect_css);
 
   String Build();
 
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_style_tracker.cc b/third_party/blink/renderer/core/document_transition/document_transition_style_tracker.cc
index 6cc1e8e..44e73d2 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_style_tracker.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition_style_tracker.cc
@@ -65,27 +65,6 @@
   return kAnimationUAStyles;
 }
 
-absl::optional<String> GetSnapshotViewportOffsetTransform(
-    const gfx::Vector2d& offset,
-    float device_pixel_ratio) {
-  if (!offset.x() && !offset.y())
-    return absl::nullopt;
-
-  // Since we're using the offset in style, convert from physical pixels to CSS
-  // pixels.
-  gfx::Vector2dF css_offset =
-      gfx::ScaleVector2d(offset, 1.f / device_pixel_ratio);
-
-  // The root is translated up and left so that the coordinate space for all
-  // children has its origin at the point that is the top-left when all UI is
-  // hidden. This requires non-root shared elements to be shifted back down and
-  // right.
-  DCHECK_LE(css_offset.x(), 0.f);
-  DCHECK_LE(css_offset.y(), 0.f);
-  return String::Format("transform: translate(%.3fpx, %.3fpx);", css_offset.x(),
-                        css_offset.y());
-}
-
 absl::optional<String> ComputeInsetDifference(PhysicalRect reference_rect,
                                               const LayoutRect& target_rect,
                                               float device_pixel_ratio) {
@@ -987,29 +966,31 @@
   DCHECK(document.View());
   DCHECK(document.GetPage());
   DCHECK(document.GetFrame());
-
-  if (!document.GetFrame()->IsOutermostMainFrame())
-    return gfx::Outsets();
-
-  Page& page = *document.GetPage();
+  DCHECK(document.GetLayoutView());
 
   int top = 0;
   int right = 0;
   int bottom = 0;
   int left = 0;
 
-  // TODO(bokan): This assumes any shown ratio implies controls are shown. We
-  // many need to do some synchronization to make this work seamlessly with URL
-  // bar animations.
-  BrowserControls& controls = page.GetBrowserControls();
-  if (page.GetBrowserControls().TopShownRatio()) {
-    top += controls.TopHeight() - controls.TopMinHeight();
-    bottom += controls.BottomHeight() - controls.BottomMinHeight();
+  if (document.GetFrame()->IsOutermostMainFrame()) {
+    // TODO(bokan): This assumes any shown ratio implies controls are shown. We
+    // many need to do some synchronization to make this work seamlessly with
+    // URL bar animations.
+    BrowserControls& controls = document.GetPage()->GetBrowserControls();
+    if (controls.TopShownRatio())
+      top += controls.TopHeight() - controls.TopMinHeight();
+    if (controls.BottomShownRatio())
+      bottom += controls.BottomHeight() - controls.BottomMinHeight();
   }
 
   // TODO(bokan): Account for virtual-keyboard
 
-  // TODO(bokan): Account for scrollbars.
+  // TODO(bokan): Handle left-hand side vertical scrollbars.
+
+  LocalFrameView& view = *document.View();
+  right += view.LayoutViewport()->VerticalScrollbarWidth();
+  bottom += view.LayoutViewport()->HorizontalScrollbarHeight();
 
   gfx::Outsets outsets;
   outsets.set_top(top);
@@ -1027,11 +1008,11 @@
 
   LocalFrameView& view = *document_->View();
 
-  // Start with the full FrameView size, i.e. the position: fixed viewport and
+  // Start with the FrameView size, i.e. the position: fixed viewport, and
   // expand the viewport by any insetting UI such as the mobile URL bar,
-  // virtual-keyboard, etc. Note: the FrameView size already includes
-  // scrollbars.
-  gfx::Rect snapshot_viewport_rect(view.Size());
+  // virtual-keyboard, scrollbars, etc.
+  gfx::Rect snapshot_viewport_rect(
+      view.LayoutViewport()->ExcludeScrollbars(view.Size()));
   snapshot_viewport_rect.Outset(GetFixedToSnapshotViewportOutsets(*document_));
 
   return snapshot_viewport_rect;
@@ -1039,8 +1020,14 @@
 
 gfx::Vector2d DocumentTransitionStyleTracker::GetRootSnapshotPaintOffset()
     const {
+  DCHECK(document_->GetLayoutView());
+  DCHECK(document_->View());
+
   gfx::Outsets outsets = GetFixedToSnapshotViewportOutsets(*document_);
-  return gfx::Vector2d(outsets.left(), outsets.top());
+  int left = outsets.left();
+  int top = outsets.top();
+
+  return gfx::Vector2d(left, top);
 }
 
 void DocumentTransitionStyleTracker::InvalidateStyle() {
@@ -1144,14 +1131,19 @@
                                  ->StyleRef()
                                  .EffectiveZoom();
 
-  // Position the root container behind any viewport insetting widgets (such
-  // as the URL bar) so that it's stable across a transition.
-  absl::optional<String> snapshot_viewport_offset =
-      GetSnapshotViewportOffsetTransform(
-          GetSnapshotViewportRect().OffsetFromOrigin(), device_pixel_ratio);
-  if (snapshot_viewport_offset) {
-    builder.AddRootStyles(*snapshot_viewport_offset);
-  }
+  // Size and position the root container behind any viewport insetting widgets
+  // (such as the URL bar) so that it's stable across a transition. This rect
+  // is called the "snapshot viewport".  Since this is applied in style,
+  // convert from physical pixels to CSS pixels.
+  gfx::RectF snapshot_viewport_css_pixels = gfx::ScaleRect(
+      gfx::RectF(GetSnapshotViewportRect()), 1.f / device_pixel_ratio);
+
+  // If adjusted, the root is always translated up and left underneath any UI
+  // so the direction must always be negative.
+  DCHECK_LE(snapshot_viewport_css_pixels.x(), 0.f);
+  DCHECK_LE(snapshot_viewport_css_pixels.y(), 0.f);
+
+  builder.AddRootStyles(snapshot_viewport_css_pixels);
 
   for (auto& root_tag : AllRootTags()) {
     // This is case 3 above.
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 83a62e2..4c1364e1 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -293,7 +293,9 @@
       HTMLMediaElement&) = 0;
 
   virtual void DidCommitDocumentReplacementNavigation(DocumentLoader*) = 0;
-  virtual void DispatchDidClearWindowObjectInMainWorld() = 0;
+  virtual void DispatchDidClearWindowObjectInMainWorld(
+      v8::Isolate* isolate,
+      v8::MicrotaskQueue* microtask_queue) = 0;
   virtual void DocumentElementAvailable() = 0;
   virtual void RunScriptsAtDocumentElementAvailable() = 0;
   virtual void RunScriptsAtDocumentReady(bool document_is_empty) = 0;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 7b726508..ff373fdfa 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -191,9 +191,17 @@
   }
 }
 
-void LocalFrameClientImpl::DispatchDidClearWindowObjectInMainWorld() {
+void LocalFrameClientImpl::DispatchDidClearWindowObjectInMainWorld(
+    v8::Isolate* isolate,
+    v8::MicrotaskQueue* microtask_queue) {
   if (web_frame_->Client()) {
-    web_frame_->Client()->DidClearWindowObject();
+    // Do not run microtasks while invoking the callback.
+    {
+      v8::MicrotasksScope microtasks(isolate, microtask_queue,
+
+                                     v8::MicrotasksScope::kDoNotRunMicrotasks);
+      web_frame_->Client()->DidClearWindowObject();
+    }
     Document* document = web_frame_->GetFrame()->GetDocument();
     if (document) {
       const Settings* const settings = web_frame_->GetFrame()->GetSettings();
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index c974fa2..2fe4b1c 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -72,7 +72,9 @@
   // Notifies the WebView delegate that the JS window object has been cleared,
   // giving it a chance to bind native objects to the window before script
   // parsing begins.
-  void DispatchDidClearWindowObjectInMainWorld() override;
+  void DispatchDidClearWindowObjectInMainWorld(
+      v8::Isolate* isolate,
+      v8::MicrotaskQueue* microtask_queue) override;
   void DocumentElementAvailable() override;
   void RunScriptsAtDocumentElementAvailable() override;
   void RunScriptsAtDocumentReady(bool document_is_empty) override;
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 58d28da..9afebbe 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -1699,7 +1699,7 @@
   // commit. Processing the data now can lead to unexpected states.
   // TODO(https://crbug.com/1364695): see if this limitation can be removed.
   if (auto* sink = probe::ToCoreProbeSink(GetDocument())) {
-    if (sink->HasAgentsGlobal(CoreProbeSink::kInspectorDOMDebuggerAgent))
+    if (sink->HasAgentsGlobal(CoreProbeSink::kDevToolsSession))
       return false;
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index dc08ce1..7ddf9a9 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -587,10 +587,12 @@
   if (!frame_view_)
     return PhysicalRect();
 
+  // TODO(bokan): This shouldn't be just for the outermost main frame, we
+  // should do it for all frames. crbug.com/1311518.
   if (frame_view_->GetFrame().IsOutermostMainFrame()) {
     auto* supplement =
         DocumentTransitionSupplement::FromIfExists(GetDocument());
-    if (supplement && !supplement->GetTransition()->IsIdle()) {
+    if (supplement && supplement->GetTransition()->IsRootTransitioning()) {
       // If we're capturing a transition snapshot, the root transition needs to
       // produce the snapshot at a known stable size, excluding all insetting
       // UI like mobile URL bars and virtual keyboards.
@@ -622,7 +624,14 @@
   }
 
   rect.offset += location;
-  if (IsScrollContainer())
+
+  // When capturing the root snapshot for a transition, we paint the background
+  // color where the scrollbar would be so keep the clip rect the full ViewRect
+  // size.
+  auto* supplement = DocumentTransitionSupplement::FromIfExists(GetDocument());
+  bool is_in_transition =
+      supplement && supplement->GetTransition()->IsRootTransitioning();
+  if (IsScrollContainer() && !is_in_transition)
     ExcludeScrollbars(rect, overlay_scrollbar_clip_behavior);
 
   return rect;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h
index 87cec8f2..7ffc3ed 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h
@@ -22,8 +22,15 @@
   // Subgrids need to map named lines from every parent grid. This constructor
   // should be used exclusively by subgrids to differentiate such scenario.
   NGGridPlacementData(const ComputedStyle& grid_style,
-                      const NGGridLineResolver& parent_line_resolver)
-      : line_resolver(grid_style, parent_line_resolver) {}
+                      const NGGridLineResolver& parent_line_resolver,
+                      GridArea subgrid_area)
+      : line_resolver(grid_style, parent_line_resolver, subgrid_area),
+        subgridded_column_span_size(subgrid_area.columns.IsTranslatedDefinite()
+                                        ? subgrid_area.SpanSize(kForColumns)
+                                        : kNotFound),
+        subgridded_row_span_size(subgrid_area.rows.IsTranslatedDefinite()
+                                     ? subgrid_area.SpanSize(kForRows)
+                                     : kNotFound) {}
 
   // This constructor only copies inputs to the auto-placement algorithm.
   NGGridPlacementData(const NGGridPlacementData& other)
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index cf6580f..3515bab 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -507,29 +507,30 @@
   const auto& style = node.Style();
 
   bool has_nested_subgrid;
+
   auto& sizing_data = sizing_tree->CreateSizingData(node, parent_sizing_data,
                                                     subgrid_data_in_parent);
   {
+    GridArea subgridded_area_in_parent;
+    if (subgrid_data_in_parent) {
+      subgridded_area_in_parent = subgrid_data_in_parent->resolved_position;
+      if (!subgrid_data_in_parent->is_parallel_with_root_grid) {
+        std::swap(subgridded_area_in_parent.columns,
+                  subgridded_area_in_parent.rows);
+      }
+
+      if (!subgrid_data_in_parent->has_subgridded_columns)
+        subgridded_area_in_parent.columns = GridSpan::IndefiniteGridSpan();
+      if (!subgrid_data_in_parent->has_subgridded_rows)
+        subgridded_area_in_parent.rows = GridSpan::IndefiniteGridSpan();
+    }
+
     // Initialize this grid's placement data.
     auto placement_data =
-        parent_line_resolver ? NGGridPlacementData(style, *parent_line_resolver)
+        parent_line_resolver ? NGGridPlacementData(style, *parent_line_resolver,
+                                                   subgridded_area_in_parent)
                              : NGGridPlacementData(style);
 
-    if (subgrid_data_in_parent) {
-      wtf_size_t column_span_size_in_parent =
-          subgrid_data_in_parent->SpanSize(kForColumns);
-      wtf_size_t row_span_size_in_parent =
-          subgrid_data_in_parent->SpanSize(kForRows);
-
-      if (!subgrid_data_in_parent->is_parallel_with_root_grid)
-        std::swap(column_span_size_in_parent, row_span_size_in_parent);
-
-      if (subgrid_data_in_parent->has_subgridded_columns)
-        placement_data.subgridded_column_span_size = column_span_size_in_parent;
-      if (subgrid_data_in_parent->has_subgridded_rows)
-        placement_data.subgridded_row_span_size = row_span_size_in_parent;
-    }
-
     // TODO(ethavar): Compute automatic repetitions for subgridded axes as
     // described in https://drafts.csswg.org/css-grid-2/#auto-repeat.
     if (!parent_sizing_data) {
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.cc
index fa8a29a..50c0481 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.cc
@@ -28,23 +28,73 @@
 
 NGGridLineResolver::NGGridLineResolver(
     const ComputedStyle& grid_style,
-    const NGGridLineResolver& parent_line_resolver)
-    : style_(&grid_style), is_subgrid_line_resolver_(true) {
-  column_subgrid_merged_grid_line_names_ =
-      grid_style.GridTemplateColumns().named_grid_lines;
-  row_subgrid_merged_grid_line_names_ =
-      grid_style.GridTemplateRows().named_grid_lines;
+    const NGGridLineResolver& parent_line_resolver,
+    GridArea subgrid_area)
+    : style_(&grid_style),
+      subgrid_column_start_line_(subgrid_area.columns.IsTranslatedDefinite()
+                                     ? subgrid_area.StartLine(kForColumns)
+                                     : 0),
+      subgrid_row_start_line_(subgrid_area.rows.IsTranslatedDefinite()
+                                  ? subgrid_area.StartLine(kForRows)
+                                  : 0),
+      column_subgrid_merged_grid_line_names_(
+          grid_style.GridTemplateColumns().named_grid_lines),
+      row_subgrid_merged_grid_line_names_(
+          grid_style.GridTemplateRows().named_grid_lines) {
+  auto MergeNamedGridLinesWithAncestor = [](NamedGridLinesMap& subgrid_map,
+                                            const NamedGridLinesMap& parent_map,
+                                            GridSpan subgrid_span) -> void {
+    // Update `subgrid_map` to a merged map from a parent grid or subgrid map
+    // (`parent_map`). The map is a key-value store with keys as the line name
+    // and the value as an array of ascending indices.
+    for (auto& pair : parent_map) {
+      Vector<wtf_size_t, 16> merged_list;
+      for (const auto& position : pair.value) {
+        // Filter out parent named lines are are out of the subgrid range. Also
+        // offset entries by `subgrid_start_line` before inserting them into the
+        // merged map so they are all relative to offset 0. These are already in
+        // ascending order so there's no need to sort.
+        if ((position >= subgrid_span.StartLine()) &&
+            (position <=
+             (subgrid_span.StartLine() + subgrid_span.IntegerSpan()))) {
+          merged_list.push_back(position - subgrid_span.StartLine());
+        }
+      }
 
-  // Add the parent grid/subgrid's line numbers to the shared line name set.
-  // TODO(kschmi): Merge/filter these lists.
-  for (const auto& pair :
-       parent_line_resolver.ExplicitNamedLinesMap(kForColumns)) {
-    column_subgrid_merged_grid_line_names_.insert(pair.key, pair.value);
+      // If there's a name collision, merge the values and sort. These are from
+      // the subgrid and not the parent container, so they are already relative
+      // to index 0 and don't need to be offset.
+      const auto& existing_entry = subgrid_map.find(pair.key);
+      if (existing_entry != subgrid_map.end()) {
+        for (auto& value : existing_entry->value)
+          merged_list.push_back(value);
+        std::sort(merged_list.begin(), merged_list.end());
+      }
+
+      // Override the existing subgrid's line names map with the new merged list
+      // for this particular line name entry. If `merged_list` list is empty,
+      // (this can happen when all entries for a particular line name are out
+      // of the subgrid range), erase the entry entirely, as
+      // `NGGridNamedLineCollection` doesn't support named line entries without
+      // values.
+      if (merged_list.empty())
+        subgrid_map.erase(pair.key);
+      else
+        subgrid_map.Set(pair.key, merged_list);
+    }
+  };
+
+  if (subgrid_area.columns.IsTranslatedDefinite()) {
+    MergeNamedGridLinesWithAncestor(
+        *column_subgrid_merged_grid_line_names_,
+        parent_line_resolver.ExplicitNamedLinesMap(kForColumns),
+        subgrid_area.columns);
   }
-
-  for (const auto& pair :
-       parent_line_resolver.ExplicitNamedLinesMap(kForRows)) {
-    row_subgrid_merged_grid_line_names_.insert(pair.key, pair.value);
+  if (subgrid_area.rows.IsTranslatedDefinite()) {
+    MergeNamedGridLinesWithAncestor(
+        *row_subgrid_merged_grid_line_names_,
+        parent_line_resolver.ExplicitNamedLinesMap(kForRows),
+        subgrid_area.rows);
   }
 }
 
@@ -134,14 +184,15 @@
     int last_line,
     NGGridNamedLineCollection& lines_collection) const {
   int start, end;
+  const int span_position = position.SpanPosition();
   if (side == kRowStartSide || side == kColumnStartSide) {
-    start = LookBackForNamedGridLine(opposite_line - 1, position.SpanPosition(),
+    start = LookBackForNamedGridLine(opposite_line - 1, span_position,
                                      last_line, lines_collection);
     end = opposite_line;
   } else {
     start = opposite_line;
-    end = LookAheadForNamedGridLine(opposite_line + 1, position.SpanPosition(),
-                                    last_line, lines_collection);
+    end = LookAheadForNamedGridLine(opposite_line + 1, span_position, last_line,
+                                    lines_collection);
   }
 
   return GridSpan::UntranslatedDefiniteGridSpan(start, end);
@@ -153,7 +204,7 @@
   if (subgrid_span_size != kNotFound)
     return subgrid_span_size;
 
-  // TODO(kschmi): Refactor with `is_subgrid_line_resolver_` factored in.
+  // TODO(kschmi): Refactor so that `subgrid_span_size` isn't necessary.
   return std::min<wtf_size_t>(std::max(style_->GridTemplateColumns()
                                                .track_sizes.NGTrackList()
                                                .TrackCountWithoutAutoRepeat() +
@@ -168,7 +219,7 @@
   if (subgrid_span_size != kNotFound)
     return subgrid_span_size;
 
-  // TODO(kschmi): Refactor with `is_subgrid_line_resolver_` factored in.
+  // TODO(kschmi): Refactor so that `subgrid_span_size` isn't necessary.
   return std::min<wtf_size_t>(std::max(style_->GridTemplateRows()
                                                .track_sizes.NGTrackList()
                                                .TrackCountWithoutAutoRepeat() +
@@ -194,7 +245,8 @@
     const GridPosition& position,
     wtf_size_t auto_repeat_tracks_count,
     GridPositionSide side,
-    wtf_size_t subgrid_span_size) const {
+    wtf_size_t subgrid_span_size,
+    bool is_subgridded_to_parent) const {
   DCHECK(position.IsSpan());
   DCHECK(!position.NamedGridLine().IsNull());
   // Negative positions are not allowed per the specification and should have
@@ -204,7 +256,6 @@
   GridTrackSizingDirection track_direction = DirectionFromSide(side);
   const auto& implicit_grid_line_names = ImplicitNamedLinesMap(track_direction);
   const auto& explicit_grid_line_names = ExplicitNamedLinesMap(track_direction);
-
   const auto& computed_grid_track_list = ComputedGridTrackList(track_direction);
 
   wtf_size_t last_line = ExplicitGridSizeForSide(side, auto_repeat_tracks_count,
@@ -213,7 +264,7 @@
   NGGridNamedLineCollection lines_collection(
       position.NamedGridLine(), track_direction, implicit_grid_line_names,
       explicit_grid_line_names, computed_grid_track_list, last_line,
-      auto_repeat_tracks_count);
+      auto_repeat_tracks_count, is_subgridded_to_parent);
   return DefiniteGridSpanWithNamedSpanAgainstOpposite(
       opposite_line, position, side, last_line, lines_collection);
 }
@@ -234,7 +285,7 @@
 
 const NamedGridLinesMap& NGGridLineResolver::ImplicitNamedLinesMap(
     GridTrackSizingDirection track_direction) const {
-  // TODO(kschmi): Merge implicit list if `is_subgrid_line_resolver_`.
+  // TODO(kschmi): Merge implicit list if it's subgridded.
   return (track_direction == kForColumns)
              ? style_->ImplicitNamedGridColumnLines()
              : style_->ImplicitNamedGridRowLines();
@@ -242,20 +293,19 @@
 
 const NamedGridLinesMap& NGGridLineResolver::ExplicitNamedLinesMap(
     GridTrackSizingDirection track_direction) const {
-  // Subgrids look at the merged map of the parent's grid line names, while
-  // standalone grids should look directly at the style object.
-  if (is_subgrid_line_resolver_) {
-    return (track_direction == kForColumns)
-               ? column_subgrid_merged_grid_line_names_
-               : row_subgrid_merged_grid_line_names_;
-  }
-  return ComputedGridTrackList(track_direction).named_grid_lines;
+  const auto& subgrid_merged_grid_line_names =
+      (track_direction == kForColumns) ? column_subgrid_merged_grid_line_names_
+                                       : row_subgrid_merged_grid_line_names_;
+
+  return subgrid_merged_grid_line_names
+             ? *subgrid_merged_grid_line_names
+             : ComputedGridTrackList(track_direction).named_grid_lines;
 }
 
 const blink::ComputedGridTrackList& NGGridLineResolver::ComputedGridTrackList(
     GridTrackSizingDirection track_direction) const {
-  // TODO(kschmi): Refactor so this isn't necessary when
-  // `is_subgrid_line_resolver_`.
+  // TODO(kschmi): Refactor so this isn't necessary and handle auto-repeats
+  // for subgrids.
   return (track_direction == kForColumns) ? style_->GridTemplateColumns()
                                           : style_->GridTemplateRows();
 }
@@ -265,7 +315,8 @@
     const GridPosition& position,
     GridPositionSide side,
     wtf_size_t auto_repeat_tracks_count,
-    wtf_size_t subgrid_span_size) const {
+    wtf_size_t subgrid_span_size,
+    bool is_subgridded_to_parent) const {
   if (position.IsAuto()) {
     if (side == kColumnStartSide || side == kRowStartSide) {
       return GridSpan::UntranslatedDefiniteGridSpan(opposite_line - 1,
@@ -283,7 +334,7 @@
     // our opposite position.
     return ResolveNamedGridLinePositionAgainstOppositePosition(
         opposite_line, position, auto_repeat_tracks_count, side,
-        subgrid_span_size);
+        subgrid_span_size, is_subgridded_to_parent);
   }
 
   return DefiniteGridSpanWithSpanAgainstOpposite(opposite_line, position, side);
@@ -315,11 +366,12 @@
   return SpanSizeFromPositions(initial_position, final_position);
 }
 
-int NGGridLineResolver::ResolveNamedGridLinePositionFromStyle(
+int NGGridLineResolver::ResolveNamedGridLinePosition(
     const GridPosition& position,
     GridPositionSide side,
     wtf_size_t auto_repeat_tracks_count,
-    wtf_size_t subgrid_span_size) const {
+    wtf_size_t subgrid_span_size,
+    bool is_subgridded_to_parent) const {
   DCHECK(!position.NamedGridLine().IsNull());
 
   wtf_size_t last_line = ExplicitGridSizeForSide(side, auto_repeat_tracks_count,
@@ -330,8 +382,8 @@
   const auto& track_list = ComputedGridTrackList(track_direction);
   NGGridNamedLineCollection lines_collection(
       position.NamedGridLine(), track_direction, implicit_grid_line_names,
-      explicit_grid_line_names, track_list, last_line,
-      auto_repeat_tracks_count);
+      explicit_grid_line_names, track_list, last_line, auto_repeat_tracks_count,
+      is_subgridded_to_parent);
 
   if (position.IsPositive()) {
     return LookAheadForNamedGridLine(0, abs(position.IntegerPosition()),
@@ -342,19 +394,29 @@
                                   last_line, lines_collection);
 }
 
-int NGGridLineResolver::ResolveGridPositionFromStyle(
+int NGGridLineResolver::ResolveGridPosition(
     const GridPosition& position,
     GridPositionSide side,
     wtf_size_t auto_repeat_tracks_count,
     bool is_subgridded_to_parent,
     wtf_size_t subgrid_span_size) const {
+  auto track_direction = DirectionFromSide(side);
+
+  // TODO(kschmi): Remove `subgrid_offset` once `auto_repeat_tracks_count` is
+  // correct.
+  const int subgrid_offset = (track_direction == kForColumns)
+                                 ? subgrid_column_start_line_.value_or(0)
+                                 : subgrid_row_start_line_.value_or(0);
   switch (position.GetType()) {
     case kExplicitPosition: {
       DCHECK(position.IntegerPosition());
 
+      // `ResolveNamedGridLinePosition` already factors in
+      // `subgrid_offset` via `ExplicitGridSizeForSide`.
       if (!position.NamedGridLine().IsNull()) {
-        return ResolveNamedGridLinePositionFromStyle(
-            position, side, auto_repeat_tracks_count, subgrid_span_size);
+        return ResolveNamedGridLinePosition(
+            position, side, auto_repeat_tracks_count, subgrid_span_size,
+            is_subgridded_to_parent);
       }
 
       // Handle <integer> explicit position.
@@ -378,7 +440,6 @@
       wtf_size_t last_line = ExplicitGridSizeForSide(
           side, auto_repeat_tracks_count, subgrid_span_size);
 
-      GridTrackSizingDirection track_direction = DirectionFromSide(side);
       const auto& implicit_grid_line_names =
           ImplicitNamedLinesMap(track_direction);
       const auto& explicit_grid_line_names =
@@ -390,7 +451,7 @@
           implicit_grid_line_names, explicit_grid_line_names, track_list,
           last_line, auto_repeat_tracks_count);
       if (implicit_lines.HasNamedLines())
-        return implicit_lines.FirstPosition();
+        return implicit_lines.FirstPosition() + subgrid_offset;
 
       // Otherwise, if there is a named line with the specified name,
       // contributes the first such line to the grid item's placement.
@@ -399,11 +460,11 @@
           explicit_grid_line_names, track_list, last_line,
           auto_repeat_tracks_count, is_subgridded_to_parent);
       if (explicit_lines.HasNamedLines())
-        return explicit_lines.FirstPosition();
+        return explicit_lines.FirstPosition() + subgrid_offset;
 
       // If none of the above works specs mandate to assume that all the lines
       // in the implicit grid have this name.
-      return last_line + 1;
+      return last_line + subgrid_offset + 1;
     }
     case kAutoPosition:
     case kSpanPosition:
@@ -447,31 +508,31 @@
   if (initial_should_be_resolved_against_opposite_position) {
     // Infer the position from the final_position position ('auto / 1' or 'span
     // 2 / 3' case).
-    int end_line = ResolveGridPositionFromStyle(
+    int end_line = ResolveGridPosition(
         final_position, final_side, auto_repeat_tracks_count,
         is_subgridded_to_parent, subgrid_span_size);
     return ResolveGridPositionAgainstOppositePosition(
         end_line, initial_position, initial_side, auto_repeat_tracks_count,
-        subgrid_span_size);
+        subgrid_span_size, is_subgridded_to_parent);
   }
 
   if (final_should_be_resolved_against_opposite_position) {
     // Infer our position from the initial_position position ('1 / auto' or '3 /
     // span 2' case).
-    int start_line = ResolveGridPositionFromStyle(
+    int start_line = ResolveGridPosition(
         initial_position, initial_side, auto_repeat_tracks_count,
         is_subgridded_to_parent, subgrid_span_size);
     return ResolveGridPositionAgainstOppositePosition(
         start_line, final_position, final_side, auto_repeat_tracks_count,
-        subgrid_span_size);
+        subgrid_span_size, is_subgridded_to_parent);
   }
 
-  int start_line = ResolveGridPositionFromStyle(
+  int start_line = ResolveGridPosition(
       initial_position, initial_side, auto_repeat_tracks_count,
       is_subgridded_to_parent, subgrid_span_size);
-  int end_line = ResolveGridPositionFromStyle(
-      final_position, final_side, auto_repeat_tracks_count,
-      is_subgridded_to_parent, subgrid_span_size);
+  int end_line =
+      ResolveGridPosition(final_position, final_side, auto_repeat_tracks_count,
+                          is_subgridded_to_parent, subgrid_span_size);
 
   if (end_line < start_line)
     std::swap(end_line, start_line);
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 ac8a4f47..07eb2890 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
@@ -5,7 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_LINE_RESOLVER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_LINE_RESOLVER_H_
 
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/style/computed_grid_track_list.h"
+#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/wtf/allocator/allocator.h"
@@ -27,12 +29,13 @@
   NGGridLineResolver() = default;
 
   explicit NGGridLineResolver(const ComputedStyle& grid_style)
-      : style_(&grid_style), is_subgrid_line_resolver_(false) {}
+      : style_(&grid_style) {}
 
   // Subgrids need to map named lines from every parent grid. This constructor
   // should be used exclusively by subgrids to differentiate such scenario.
   explicit NGGridLineResolver(const ComputedStyle& grid_style,
-                              const NGGridLineResolver& parent_line_resolver);
+                              const NGGridLineResolver& parent_line_resolver,
+                              GridArea subgrid_area);
 
   wtf_size_t ExplicitGridColumnCount(
       wtf_size_t auto_repeat_columns_count,
@@ -67,20 +70,22 @@
       const GridPosition& position,
       GridPositionSide side,
       wtf_size_t auto_repeat_tracks_count,
-      wtf_size_t subgrid_span_size) const;
+      wtf_size_t subgrid_span_size,
+      bool is_subgridded_to_parent) const;
 
   GridSpan ResolveNamedGridLinePositionAgainstOppositePosition(
       int opposite_line,
       const GridPosition& position,
       wtf_size_t auto_repeat_tracks_count,
       GridPositionSide side,
-      wtf_size_t subgrid_span_size) const;
+      wtf_size_t subgrid_span_size,
+      bool is_subgridded_to_parent) const;
 
-  int ResolveGridPositionFromStyle(const GridPosition& position,
-                                   GridPositionSide side,
-                                   wtf_size_t auto_repeat_tracks_count,
-                                   bool is_subgridded_to_parent,
-                                   wtf_size_t subgrid_span_size) const;
+  int ResolveGridPosition(const GridPosition& position,
+                          GridPositionSide side,
+                          wtf_size_t auto_repeat_tracks_count,
+                          bool is_subgridded_to_parent,
+                          wtf_size_t subgrid_span_size) const;
 
   wtf_size_t ExplicitGridSizeForSide(GridPositionSide side,
                                      wtf_size_t auto_repeat_tracks_count,
@@ -101,10 +106,11 @@
   wtf_size_t SpanSizeFromPositions(const GridPosition& initial_position,
                                    const GridPosition& final_position) const;
 
-  int ResolveNamedGridLinePositionFromStyle(const GridPosition& position,
-                                            GridPositionSide side,
-                                            wtf_size_t auto_repeat_tracks_count,
-                                            wtf_size_t subgrid_span_size) const;
+  int ResolveNamedGridLinePosition(const GridPosition& position,
+                                   GridPositionSide side,
+                                   wtf_size_t auto_repeat_tracks_count,
+                                   wtf_size_t subgrid_span_size,
+                                   bool is_subgridded_to_parent) const;
 
   void InitialAndFinalPositionsFromStyle(
       const ComputedStyle& grid_item_style,
@@ -121,10 +127,13 @@
 
   scoped_refptr<const ComputedStyle> style_;
 
-  bool is_subgrid_line_resolver_ : 1;
+  // TODO(kschmi) remove these, as they will be unnecessary when the rest of
+  // the line resolution work is completed.
+  absl::optional<wtf_size_t> subgrid_column_start_line_;
+  absl::optional<wtf_size_t> subgrid_row_start_line_;
 
-  NamedGridLinesMap column_subgrid_merged_grid_line_names_;
-  NamedGridLinesMap row_subgrid_merged_grid_line_names_;
+  absl::optional<NamedGridLinesMap> column_subgrid_merged_grid_line_names_;
+  absl::optional<NamedGridLinesMap> row_subgrid_merged_grid_line_names_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index ba841a4..f876e56 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -358,7 +358,9 @@
       HTMLMediaElement&) override;
 
   void DidCommitDocumentReplacementNavigation(DocumentLoader*) override {}
-  void DispatchDidClearWindowObjectInMainWorld() override {}
+  void DispatchDidClearWindowObjectInMainWorld(
+      v8::Isolate* isolate,
+      v8::MicrotaskQueue* microtask_queue) override {}
   void DocumentElementAvailable() override {}
   void RunScriptsAtDocumentElementAvailable() override {}
   void RunScriptsAtDocumentReady(bool) override {}
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index b0c3dfe..bf017fd 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1729,18 +1729,21 @@
       &dispatching_did_clear_window_object_in_main_world_, true);
   // We just cleared the document, not the entire window object, but for the
   // embedder that's close enough.
-  Client()->DispatchDidClearWindowObjectInMainWorld();
+  Client()->DispatchDidClearWindowObjectInMainWorld(
+      window->GetIsolate(), window->GetMicrotaskQueue());
 }
 
 void FrameLoader::DispatchDidClearWindowObjectInMainWorld() {
-  if (!frame_->DomWindow()->CanExecuteScripts(kNotAboutToExecuteScript))
+  LocalDOMWindow* window = frame_->DomWindow();
+  if (!window->CanExecuteScripts(kNotAboutToExecuteScript))
     return;
 
   if (dispatching_did_clear_window_object_in_main_world_)
     return;
   base::AutoReset<bool> in_did_clear_window_object(
       &dispatching_did_clear_window_object_in_main_world_, true);
-  Client()->DispatchDidClearWindowObjectInMainWorld();
+  Client()->DispatchDidClearWindowObjectInMainWorld(
+      window->GetIsolate(), window->GetMicrotaskQueue());
 }
 
 network::mojom::blink::WebSandboxFlags
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 305a123..8f62d7a 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
@@ -61,6 +61,8 @@
 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
 #include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
 #include "third_party/blink/renderer/core/css/style_request.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition.h"
+#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
@@ -702,8 +704,23 @@
 
 gfx::Size PaintLayerScrollableArea::PixelSnappedContentsSize(
     const PhysicalOffset& paint_offset) const {
-  return ToPixelSnappedRect(PhysicalRect(paint_offset, overflow_rect_.size))
-      .size();
+  PhysicalSize size = overflow_rect_.size;
+
+  // If we're capturing a transition snapshot, ensure the content size is
+  // considered at least as large as the container. Otherwise, the snapshot
+  // will be clipped by PendingLayer to the content size.
+  if (IsA<LayoutView>(GetLayoutBox())) {
+    auto* supplement = DocumentTransitionSupplement::FromIfExists(
+        GetLayoutBox()->GetDocument());
+    if (supplement && supplement->GetTransition()->IsRootTransitioning()) {
+      PhysicalSize container_size(
+          supplement->GetTransition()->GetSnapshotViewportRect().size());
+      size.width = std::max(container_size.width, size.width);
+      size.height = std::max(container_size.height, size.height);
+    }
+  }
+
+  return ToPixelSnappedRect(PhysicalRect(paint_offset, size)).size();
 }
 
 void PaintLayerScrollableArea::ContentsResized() {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 466479f..1fae5b6 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -2910,7 +2910,8 @@
   // origin rather than behind the UI.
   if (auto* supplement =
           DocumentTransitionSupplement::FromIfExists(object_.GetDocument())) {
-    if (object_.IsDocumentElement() && !supplement->GetTransition()->IsIdle()) {
+    if (object_.IsDocumentElement() &&
+        supplement->GetTransition()->IsRootTransitioning()) {
       PhysicalOffset offset = PhysicalOffset(
           supplement->GetTransition()->GetRootSnapshotPaintOffset());
       context_.current.paint_offset += offset;
diff --git a/third_party/blink/renderer/core/paint/video_painter_test.cc b/third_party/blink/renderer/core/paint/video_painter_test.cc
index ddc26ba..f1c265d 100644
--- a/third_party/blink/renderer/core/paint/video_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/video_painter_test.cc
@@ -140,8 +140,10 @@
   EXPECT_EQ(gfx::Size(300, 150), layer->bounds());
 }
 
-class MockWebMediaPlayer : public EmptyWebMediaPlayer {
+class MockWebMediaPlayer : public StubWebMediaPlayer {
  public:
+  explicit MockWebMediaPlayer(WebMediaPlayerClient* client)
+      : StubWebMediaPlayer(client) {}
   MOCK_CONST_METHOD0(HasAvailableVideoFrame, bool());
   MOCK_METHOD3(Paint,
                void(cc::PaintCanvas*, const gfx::Rect&, cc::PaintFlags&));
@@ -151,14 +153,17 @@
  public:
   WebMediaPlayer* CreateMediaPlayer(
       const WebMediaPlayerSource&,
-      WebMediaPlayerClient*,
+      WebMediaPlayerClient* client,
       blink::MediaInspectorContext*,
       WebMediaPlayerEncryptedMediaClient*,
       WebContentDecryptionModule*,
       const WebString& sink_id,
       const cc::LayerTreeSettings& settings,
       scoped_refptr<base::TaskRunner> compositor_worker_task_runner) override {
-    return new MockWebMediaPlayer();
+    MockWebMediaPlayer* player = new MockWebMediaPlayer(client);
+    EXPECT_CALL(*player, HasAvailableVideoFrame)
+        .WillRepeatedly(testing::Return(false));
+    return player;
   }
 };
 
@@ -282,6 +287,10 @@
   ASSERT_TRUE(PlayVideo());
 
   // Capture using poster.
+  auto* element = To<HTMLMediaElement>(GetDocument().body()->firstChild());
+  MockWebMediaPlayer* player =
+      static_cast<MockWebMediaPlayer*>(element->GetWebMediaPlayer());
+  EXPECT_CALL(*player, Paint(testing::_, testing::_, testing::_)).Times(0);
   auto record = CapturePaintPreview(/*skip_accelerated_content=*/true);
 
   std::vector<std::pair<GURL, SkRect>> links;
@@ -294,6 +303,7 @@
   EXPECT_EQ(1U, CountImagesOfType(record.get(), cc::ImageType::kGIF));
 
   // Capture using video frame.
+  EXPECT_CALL(*player, Paint(testing::_, testing::_, testing::_));
   record = CapturePaintPreview(/*skip_accelerated_content=*/false);
 
   links.clear();
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc b/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc
index b0091d25..c1617dd 100644
--- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc
+++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc
@@ -8,9 +8,7 @@
 #include <string>
 
 #include "base/ranges/algorithm.h"
-#include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
 #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -140,7 +138,6 @@
   const char* permissions_policy_string;
   const char* self_origin;
   const char* src_origin;
-  const bool subdomain_wildcards;
 
   // Test expectation.
   ParsedPolicyForTest expected_parse_result;
@@ -222,8 +219,6 @@
     }
   }
 
-  base::test::ScopedFeatureList scoped_feature_list_;
-
  public:
   static const PermissionsPolicyParserTestCase kCases[];
 };
@@ -236,7 +231,6 @@
             /* permissions_policy_string */ "",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */ {},
         },
         {
@@ -245,7 +239,6 @@
             /* permissions_policy_string */ "geolocation=self",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -262,7 +255,6 @@
             /* permissions_policy_string */ "geolocation=(self)",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -279,7 +271,6 @@
             /* permissions_policy_string */ "geolocation=*",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -302,7 +293,6 @@
             "payment=self",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -338,7 +328,6 @@
             "payment=(self \"badorigin\")",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -372,7 +361,6 @@
             "geolocation=self,fullscreen=self,payment=self",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ nullptr,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -401,7 +389,6 @@
             /* permissions_policy_string */ "",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */ {},
         },
         {
@@ -410,7 +397,6 @@
             /* permissions_policy_string */ NOT_APPLICABLE,
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -427,7 +413,6 @@
             /* permissions_policy_string */ NOT_APPLICABLE,
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -444,7 +429,6 @@
             /* permissions_policy_string */ "geolocation=*",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -462,7 +446,6 @@
             "geolocation=(\"" ORIGIN_B "\" \"" ORIGIN_C "\")",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -481,7 +464,6 @@
             /* permissions_policy_string */ NOT_APPLICABLE,
             /* self_origin */ ORIGIN_A,
             /* src_origin */ OPAQUE_ORIGIN,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -499,7 +481,6 @@
             /* permissions_policy_string */ "geolocation=9",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ nullptr,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -517,7 +498,6 @@
             /* permissions_policy_string */ "geolocation=1.1",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ nullptr,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -535,7 +515,6 @@
             /* permissions_policy_string */ "geolocation=?0",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ nullptr,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -552,7 +531,6 @@
             /* permissions_policy_string */ "geolocation=\"\"",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ nullptr,
-            /* subdomain_wildcards */ false,
             /* expected_parse_result */
             {
                 {
@@ -564,34 +542,12 @@
             },
         },
         {
-            /* test_name */ "ProperWildcardIncludedWhileFeatureDisabled",
-            /* feature_policy_string */
-            "fullscreen " ORIGIN_A_SUBDOMAIN_WILDCARD,
-            /* permissions_policy_string */
-            "fullscreen=(\"" ORIGIN_A_SUBDOMAIN_WILDCARD "\")",
-            /* self_origin */ ORIGIN_A,
-            /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
-            /* expected_parse_result */
-            {
-                {
-                    mojom::blink::PermissionsPolicyFeature::kFullscreen,
-                    /* matches_all_origins */ false,
-                    /* matches_opaque_src */ false,
-                    {{ORIGIN_A_SUBDOMAIN_ESCAPED,
-                      /*has_subdomain_wildcard=*/false}},
-                },
-            },
-        },
-        {
-            /* test_name */ "ProperWildcardIncludedWhileFeatureEnabledForFeatur"
-                            "ePolicy",
+            /* test_name */ "ProperWildcardIncludedForFeaturePolicy",
             /* feature_policy_string */
             "fullscreen " ORIGIN_A_SUBDOMAIN_WILDCARD,
             /* permissions_policy_string */ NOT_APPLICABLE,
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ true,
             /* expected_parse_result */
             {
                 {
@@ -604,14 +560,12 @@
             },
         },
         {
-            /* test_name */ "ProperWildcardIncludedWhileFeatureEnabledForPermis"
-                            "sionsPolicy",
+            /* test_name */ "ProperWildcardIncludedForPermissionsPolicy",
             /* feature_policy_string */ NOT_APPLICABLE,
             /* permissions_policy_string */
             "fullscreen=(\"" ORIGIN_A_SUBDOMAIN_WILDCARD "\")",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ true,
             /* expected_parse_result */
             {
                 {
@@ -624,7 +578,7 @@
             },
         },
         {
-            /* test_name */ "ImproperWildcardsIncludedWhileFeatureDisabled",
+            /* test_name */ "ImproperWildcardsIncluded",
             /* feature_policy_string */
             "fullscreen *://example.com https://foo.*.example.com "
             "https://*.*.example.com https://example.com:*",
@@ -633,31 +587,6 @@
             "\"https://*.*.example.com\"  \"https://example.com:*\")",
             /* self_origin */ ORIGIN_A,
             /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ false,
-            /* expected_parse_result */
-            {
-                {
-                    mojom::blink::PermissionsPolicyFeature::kFullscreen,
-                    /* matches_all_origins */ false,
-                    /* matches_opaque_src */ false,
-                    {{"https://%2A.%2A.example.com",
-                      /*has_subdomain_wildcard=*/false},
-                     {"https://foo.%2A.example.com",
-                      /*has_subdomain_wildcard=*/false}},
-                },
-            },
-        },
-        {
-            /* test_name */ "ImproperWildcardsIncludedWhileFeatureEnabled",
-            /* feature_policy_string */
-            "fullscreen *://example.com https://foo.*.example.com "
-            "https://*.*.example.com https://example.com:*",
-            /* permissions_policy_string */
-            "fullscreen=(\"*://example.com\" \"https://foo.*.example.com\" "
-            "\"https://*.*.example.com\"  \"https://example.com:*\")",
-            /* self_origin */ ORIGIN_A,
-            /* src_origin */ ORIGIN_B,
-            /* subdomain_wildcards */ true,
             /* expected_parse_result */
             {
                 {
@@ -687,9 +616,6 @@
     return;
 
   ASSERT_NE(test_case.self_origin, nullptr);
-  scoped_feature_list_.InitWithFeatureState(
-      features::kWildcardSubdomainsInPermissionsPolicy,
-      test_case.subdomain_wildcards);
   CheckParsedPolicy(
       ParseFeaturePolicy(test_case.feature_policy_string, test_case.self_origin,
                          test_case.src_origin, logger, test_feature_name_map),
@@ -703,9 +629,6 @@
     return;
 
   ASSERT_NE(test_case.self_origin, nullptr);
-  scoped_feature_list_.InitWithFeatureState(
-      features::kWildcardSubdomainsInPermissionsPolicy,
-      test_case.subdomain_wildcards);
   CheckParsedPolicy(
       ParsePermissionsPolicy(test_case.permissions_policy_string,
                              test_case.self_origin, test_case.src_origin,
diff --git a/third_party/blink/renderer/core/permissions_policy/policy_test.cc b/third_party/blink/renderer/core/permissions_policy/policy_test.cc
index f9a14993..055de97 100644
--- a/third_party/blink/renderer/core/permissions_policy/policy_test.cc
+++ b/third_party/blink/renderer/core/permissions_policy/policy_test.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/test/scoped_feature_list.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/permissions_policy/dom_feature_policy.h"
@@ -26,12 +24,9 @@
 
 using testing::UnorderedElementsAre;
 
-class PolicyTest : public testing::TestWithParam<bool> {
+class PolicyTest : public testing::Test {
  public:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatureState(
-        features::kWildcardSubdomainsInPermissionsPolicy,
-        HasWildcardSubdomainsInPermissionsPolicy());
     page_holder_ = std::make_unique<DummyPageHolder>();
 
     auto origin = SecurityOrigin::CreateFromString(kSelfOrigin);
@@ -53,15 +48,12 @@
 
   DOMFeaturePolicy* GetPolicy() const { return policy_; }
 
-  bool HasWildcardSubdomainsInPermissionsPolicy() { return GetParam(); }
-
   PolicyParserMessageBuffer dummy_logger_ =
       PolicyParserMessageBuffer("", true /* discard_message */);
 
  protected:
   std::unique_ptr<DummyPageHolder> page_holder_;
   Persistent<DOMFeaturePolicy> policy_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 class DOMFeaturePolicyTest : public PolicyTest {
@@ -73,8 +65,6 @@
   }
 };
 
-INSTANTIATE_TEST_SUITE_P(All, DOMFeaturePolicyTest, testing::Bool());
-
 class IFramePolicyTest : public PolicyTest {
  public:
   void SetUp() override {
@@ -85,9 +75,7 @@
   }
 };
 
-INSTANTIATE_TEST_SUITE_P(All, IFramePolicyTest, testing::Bool());
-
-TEST_P(DOMFeaturePolicyTest, TestAllowsFeature) {
+TEST_F(DOMFeaturePolicyTest, TestAllowsFeature) {
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "badfeature"));
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi"));
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi", kSelfOrigin));
@@ -106,15 +94,14 @@
   EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "sync-xhr", kOriginA));
   EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "gyroscope"));
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "gyroscope", kOriginA));
-  EXPECT_EQ(
-      HasWildcardSubdomainsInPermissionsPolicy(),
+  EXPECT_TRUE(
       GetPolicy()->allowsFeature(nullptr, "gyroscope", kOriginASubdomain));
   EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "gyroscope", kOriginB));
   EXPECT_FALSE(
       GetPolicy()->allowsFeature(nullptr, "gyroscope", kOriginBSubdomain));
 }
 
-TEST_P(DOMFeaturePolicyTest, TestGetAllowList) {
+TEST_F(DOMFeaturePolicyTest, TestGetAllowList) {
   EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "camera"),
               UnorderedElementsAre(kSelfOrigin, kOriginA, kOriginB));
   EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "payment"),
@@ -128,14 +115,12 @@
   EXPECT_TRUE(GetPolicy()->getAllowlistForFeature(nullptr, "midi").empty());
   EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "sync-xhr"),
               UnorderedElementsAre("*"));
-  EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "gyroscope"),
-              UnorderedElementsAre(kSelfOrigin, kOriginB,
-                                   HasWildcardSubdomainsInPermissionsPolicy()
-                                       ? "https://*.example.com"
-                                       : "https://%2A.example.com"));
+  EXPECT_THAT(
+      GetPolicy()->getAllowlistForFeature(nullptr, "gyroscope"),
+      UnorderedElementsAre(kSelfOrigin, kOriginB, "https://*.example.com"));
 }
 
-TEST_P(DOMFeaturePolicyTest, TestAllowedFeatures) {
+TEST_F(DOMFeaturePolicyTest, TestAllowedFeatures) {
   Vector<String> allowed_features = GetPolicy()->allowedFeatures(nullptr);
   EXPECT_TRUE(allowed_features.Contains("fullscreen"));
   EXPECT_TRUE(allowed_features.Contains("payment"));
@@ -149,7 +134,7 @@
   EXPECT_TRUE(allowed_features.Contains("sync-xhr"));
 }
 
-TEST_P(IFramePolicyTest, TestAllowsFeature) {
+TEST_F(IFramePolicyTest, TestAllowsFeature) {
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "badfeature"));
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi"));
   EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi", kSelfOrigin));
@@ -176,7 +161,7 @@
       GetPolicy()->allowsFeature(nullptr, "gyroscope", kOriginBSubdomain));
 }
 
-TEST_P(IFramePolicyTest, TestGetAllowList) {
+TEST_F(IFramePolicyTest, TestGetAllowList) {
   EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "camera"),
               UnorderedElementsAre(kSelfOrigin));
   EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "payment"),
@@ -194,7 +179,7 @@
               UnorderedElementsAre(kSelfOrigin));
 }
 
-TEST_P(IFramePolicyTest, TestSameOriginAllowedFeatures) {
+TEST_F(IFramePolicyTest, TestSameOriginAllowedFeatures) {
   Vector<String> allowed_features = GetPolicy()->allowedFeatures(nullptr);
   // These features are allowed in a same origin context, and not restricted by
   // the parent document's policy.
@@ -211,7 +196,7 @@
   EXPECT_FALSE(allowed_features.Contains("badfeature"));
 }
 
-TEST_P(IFramePolicyTest, TestCrossOriginAllowedFeatures) {
+TEST_F(IFramePolicyTest, TestCrossOriginAllowedFeatures) {
   // Update the iframe's policy, given a new origin.
   GetPolicy()->UpdateContainerPolicy(
       ParsedPermissionsPolicy(), SecurityOrigin::CreateFromString(kOriginA));
@@ -229,7 +214,7 @@
   EXPECT_FALSE(allowed_features.Contains("badfeature"));
 }
 
-TEST_P(IFramePolicyTest, TestCombinedPolicyOnOriginA) {
+TEST_F(IFramePolicyTest, TestCombinedPolicyOnOriginA) {
   ParsedPermissionsPolicy container_policy =
       PermissionsPolicyParser::ParseAttribute(
           "geolocation 'src'; payment 'none'; midi; camera 'src'; gyroscope "
@@ -255,7 +240,7 @@
   EXPECT_FALSE(allowed_features.Contains("badfeature"));
 }
 
-TEST_P(IFramePolicyTest, TestCombinedPolicyOnOriginASubdomain) {
+TEST_F(IFramePolicyTest, TestCombinedPolicyOnOriginASubdomain) {
   ParsedPermissionsPolicy container_policy =
       PermissionsPolicyParser::ParseAttribute(
           "geolocation 'src'; payment 'none'; midi; camera 'src'; gyroscope "
@@ -273,16 +258,15 @@
   // These are allowed by the attribute, but still blocked by the parent policy.
   EXPECT_FALSE(allowed_features.Contains("midi"));
   EXPECT_FALSE(allowed_features.Contains("camera"));
-  // These features are allowed if subdomain wildcard matching is on.
-  EXPECT_EQ(HasWildcardSubdomainsInPermissionsPolicy(),
-            allowed_features.Contains("gyroscope"));
+  // These features are allowed via wildcard matching.
+  EXPECT_TRUE(allowed_features.Contains("gyroscope"));
   // "sync-xhr" is still implicitly allowed on all origins.
   EXPECT_TRUE(allowed_features.Contains("sync-xhr"));
   // This feature does not exist, so should not be advertised as allowed.
   EXPECT_FALSE(allowed_features.Contains("badfeature"));
 }
 
-TEST_P(IFramePolicyTest, TestCombinedPolicyOnOriginB) {
+TEST_F(IFramePolicyTest, TestCombinedPolicyOnOriginB) {
   ParsedPermissionsPolicy container_policy =
       PermissionsPolicyParser::ParseAttribute(
           "geolocation 'src'; payment 'none'; midi; camera 'src'; gyroscope "
@@ -307,7 +291,7 @@
   EXPECT_FALSE(allowed_features.Contains("badfeature"));
 }
 
-TEST_P(IFramePolicyTest, TestCombinedPolicyOnOriginBSubdomain) {
+TEST_F(IFramePolicyTest, TestCombinedPolicyOnOriginBSubdomain) {
   ParsedPermissionsPolicy container_policy =
       PermissionsPolicyParser::ParseAttribute(
           "geolocation 'src'; payment 'none'; midi; camera 'src'; gyroscope "
diff --git a/third_party/blink/renderer/core/style/ordered_named_grid_lines.h b/third_party/blink/renderer/core/style/ordered_named_grid_lines.h
index 9040ca79..5f169db 100644
--- a/third_party/blink/renderer/core/style/ordered_named_grid_lines.h
+++ b/third_party/blink/renderer/core/style/ordered_named_grid_lines.h
@@ -7,13 +7,12 @@
 
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
 struct NamedGridLine {
-  explicit NamedGridLine(const String line_name,
+  explicit NamedGridLine(const AtomicString& line_name,
                          bool is_in_repeat = false,
                          bool is_first_repeat = false)
       : line_name(line_name),
@@ -25,9 +24,9 @@
            is_first_repeat == other.is_first_repeat;
   }
 
-  String line_name;
-  bool is_in_repeat;
-  bool is_first_repeat;
+  AtomicString line_name;
+  bool is_in_repeat : 1;
+  bool is_first_repeat : 1;
 };
 
 using OrderedNamedGridLines =
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index 00eb640c..b51c212 100644
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -235,6 +235,7 @@
 
  private:
   friend class ThreadedWorkletTest;
+  FRIEND_TEST_ALL_PREFIXES(ThreadedWorkletTest, NestedRunLoopTermination);
 
   std::unique_ptr<WorkerThread> CreateWorkerThread() final {
     return std::make_unique<ThreadedWorkletThreadForTest>(WorkletObjectProxy());
@@ -281,6 +282,16 @@
   }
   Document& GetDocument() { return page_->GetDocument(); }
 
+  void WaitForReady(WorkerThread* worker_thread) {
+    base::WaitableEvent child_waitable;
+    PostCrossThreadTask(
+        *worker_thread->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
+        CrossThreadBindOnce(&base::WaitableEvent::Signal,
+                            CrossThreadUnretained(&child_waitable)));
+
+    child_waitable.Wait();
+  }
+
  private:
   std::unique_ptr<DummyPageHolder> page_;
   Persistent<ThreadedWorkletMessagingProxyForTest> messaging_proxy_;
@@ -404,4 +415,40 @@
   test::EnterRunLoop();
 }
 
+TEST_F(ThreadedWorkletTest, NestedRunLoopTermination) {
+  MessagingProxy()->Start();
+
+  ThreadedWorkletMessagingProxyForTest* second_messaging_proxy =
+      MakeGarbageCollected<ThreadedWorkletMessagingProxyForTest>(
+          GetExecutionContext());
+
+  // Get a nested event loop where the first one is on the stack
+  // and the second is still alive.
+  second_messaging_proxy->Start();
+
+  // Wait until the workers are setup and ready to accept work before we
+  // pause them.
+  WaitForReady(GetWorkerThread());
+  WaitForReady(second_messaging_proxy->GetWorkerThread());
+
+  // Pause the second worker, then the first.
+  second_messaging_proxy->GetWorkerThread()->Pause();
+  GetWorkerThread()->Pause();
+
+  // Resume then terminate the second worker.
+  second_messaging_proxy->GetWorkerThread()->Resume();
+  second_messaging_proxy->GetWorkerThread()->Terminate();
+  second_messaging_proxy = nullptr;
+
+  // Now resume the first worker.
+  GetWorkerThread()->Resume();
+
+  // Make sure execution still works without crashing.
+  PostCrossThreadTask(
+      *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
+      CrossThreadBindOnce(&ThreadedWorkletThreadForTest::TestTaskRunner,
+                          CrossThreadUnretained(GetWorkerThread())));
+  test::EnterRunLoop();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index b20c2286..8bf05b2 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -30,7 +30,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/auto_reset.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
@@ -598,6 +597,7 @@
     const absl::optional<WorkerBackingThreadStartupData>& thread_startup_data,
     std::unique_ptr<WorkerDevToolsParams> devtools_params) {
   DCHECK(IsCurrentThread());
+  backing_thread_weak_factory_.emplace(this);
   worker_reporting_proxy_.WillInitializeWorkerContext();
   {
     TRACE_EVENT0("blink.worker", "WorkerThread::InitializeWorkerContext");
@@ -739,11 +739,13 @@
     SetThreadState(ThreadState::kReadyToShutdown);
   }
 
+  backing_thread_weak_factory_ = absl::nullopt;
   if (pause_or_freeze_count_ > 0) {
     DCHECK(nested_runner_);
     pause_or_freeze_count_ = 0;
     nested_runner_->QuitNow();
   }
+  pause_handle_.reset();
 
   if (WorkerThreadDebugger* debugger = WorkerThreadDebugger::From(GetIsolate()))
     debugger->WorkerThreadDestroyed(this);
@@ -888,8 +890,7 @@
   if (pause_or_freeze_count_ > 1)
     return;
 
-  std::unique_ptr<scheduler::WorkerScheduler::PauseHandle> pause_handle =
-      GetScheduler()->Pause();
+  pause_handle_ = GetScheduler()->Pause();
   {
     // Since the nested message loop runner needs to be created and destroyed on
     // the same thread we allocate and destroy a new message loop runner each
@@ -897,13 +898,20 @@
     // the worker thread such that the resume/terminate can quit this runner.
     std::unique_ptr<Platform::NestedMessageLoopRunner> nested_runner =
         Platform::Current()->CreateNestedMessageLoopRunner();
-    base::AutoReset<Platform::NestedMessageLoopRunner*> nested_runner_autoreset(
-        &nested_runner_, nested_runner.get());
+    auto weak_this = backing_thread_weak_factory_->GetWeakPtr();
+    nested_runner_ = nested_runner.get();
     nested_runner->Run();
+
+    // Careful `this` may be destroyed.
+    if (!weak_this) {
+      return;
+    }
+    nested_runner_ = nullptr;
   }
   GlobalScope()->SetDefersLoadingForResourceFetchers(LoaderFreezeMode::kNone);
   GlobalScope()->SetIsInBackForwardCache(false);
   GlobalScope()->SetLifecycleState(mojom::blink::FrameLifecycleState::kRunning);
+  pause_handle_.reset();
 }
 
 void WorkerThread::ResumeOnWorkerThread() {
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
index 7254460e..298c36e 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -31,6 +31,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/single_thread_task_runner.h"
@@ -82,7 +83,7 @@
 // abstract class. Multiple WorkerThreads may share one WorkerBackingThread for
 // worklets.
 //
-// WorkerThread start and termination must be initiated on the main thread and
+// WorkerThread start and termination must be initiated on the parent thread and
 // an actual task is executed on the worker thread.
 //
 // When termination starts, (debugger) tasks on WorkerThread are handled as
@@ -105,7 +106,7 @@
   ~WorkerThread() override;
 
   // Starts the underlying thread and creates the global scope. Called on the
-  // main thread.
+  // parent thread.
   // Startup data for WorkerBackingThread is absl::nullopt if |this| doesn't own
   // the underlying WorkerBackingThread.
   // TODO(nhiroki): We could separate WorkerBackingThread initialization from
@@ -117,14 +118,14 @@
              std::unique_ptr<WorkerDevToolsParams>);
 
   // Posts a task to evaluate a top-level classic script on the worker thread.
-  // Called on the main thread after Start().
+  // Called on the parent thread after Start().
   void EvaluateClassicScript(const KURL& script_url,
                              const String& source_code,
                              std::unique_ptr<Vector<uint8_t>> cached_meta_data,
                              const v8_inspector::V8StackTraceId& stack_id);
 
   // Posts a task to fetch and run a top-level classic script on the worker
-  // thread. Called on the main thread after Start().
+  // thread. Called on the parent thread after Start().
   void FetchAndRunClassicScript(
       const KURL& script_url,
       std::unique_ptr<WorkerMainScriptLoadParameters>
@@ -136,7 +137,7 @@
       const v8_inspector::V8StackTraceId& stack_id);
 
   // Posts a task to fetch and run a top-level module script on the worker
-  // thread. Called on the main thread after Start().
+  // thread. Called on the parent thread after Start().
   void FetchAndRunModuleScript(
       const KURL& script_url,
       std::unique_ptr<WorkerMainScriptLoadParameters>
@@ -158,7 +159,7 @@
   // Terminates the worker thread. Subclasses of WorkerThread can override this
   // to do cleanup. The default behavior is to call Terminate() and
   // synchronously call EnsureScriptExecutionTerminates() to ensure the thread
-  // is quickly terminated. Called on the main thread.
+  // is quickly terminated. Called on the parent thread.
   virtual void TerminateForTesting();
 
   // Thread::TaskObserver.
@@ -185,7 +186,7 @@
   void DebuggerTaskStarted();
   void DebuggerTaskFinished();
 
-  // Callable on both the main thread and the worker thread.
+  // Callable on both the parent thread and the worker thread.
   const base::UnguessableToken& GetDevToolsWorkerToken() const {
     return devtools_worker_token_;
   }
@@ -330,7 +331,7 @@
   // already shutting down. Does not terminate if a debugger task is running,
   // because the debugger task is guaranteed to finish and it heavily uses V8
   // API calls which would crash after forcible script termination. Called on
-  // the main thread.
+  // the parent thread.
   void EnsureScriptExecutionTerminates(ExitCode) LOCKS_EXCLUDED(lock_);
 
   // These are called in this order during worker thread startup.
@@ -417,7 +418,7 @@
   // A unique identifier among all WorkerThreads.
   const int worker_thread_id_;
 
-  // Set on the main thread.
+  // Set on the parent thread.
   bool requested_to_terminate_ GUARDED_BY(lock_) = false;
 
   ThreadState thread_state_ GUARDED_BY(lock_) = ThreadState::kNotStarted;
@@ -451,7 +452,7 @@
                                     TaskTypeTraits>;
   TaskRunnerHashMap worker_task_runners_;
 
-  // This lock protects shared states between the main thread and the worker
+  // This lock protects shared states between the parent thread and the worker
   // thread. See thread-safety annotations (e.g., GUARDED_BY) in this header
   // file.
   base::Lock lock_;
@@ -460,6 +461,10 @@
   // only on the worker thread.
   int pause_or_freeze_count_ = 0;
 
+  // The `PauseHandle` needs to be destroyed before the scheduler is destroyed
+  // otherwise we will hit a DCHECK.
+  std::unique_ptr<scheduler::WorkerScheduler::PauseHandle> pause_handle_;
+
   // A nested message loop for handling pausing. Pointer is not owned. Used only
   // on the worker thread.
   Platform::NestedMessageLoopRunner* nested_runner_ = nullptr;
@@ -485,6 +490,12 @@
   // a pointer to a member in this list.
   HashSet<std::unique_ptr<InterruptData>> pending_interrupts_ GUARDED_BY(lock_);
 
+  // Since the WorkerThread is allocated and deallocated on the parent thread,
+  // we need a WeakPtrFactory that is allocated and cleared on the backing
+  // thread.
+  absl::optional<base::WeakPtrFactory<WorkerThread>>
+      backing_thread_weak_factory_;
+
   THREAD_CHECKER(parent_thread_checker_);
 };
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
index 6a415ec..9468801 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
@@ -86,7 +86,7 @@
     readonly attribute boolean? canTrickleIceCandidates;
     void restartIce();
     [CallWith=ScriptState] RTCConfiguration getConfiguration();
-    [CallWith=ScriptState, RaisesException] void setConfiguration(RTCConfiguration configuration);
+    [CallWith=ScriptState, RaisesException] void setConfiguration(optional RTCConfiguration configuration = {});
     void close();
     attribute EventHandler onnegotiationneeded;
     attribute EventHandler onicecandidate;
diff --git a/third_party/blink/renderer/modules/peerconnection/testing/mock_peer_connection_interface.h b/third_party/blink/renderer/modules/peerconnection/testing/mock_peer_connection_interface.h
index 39140cc..e7b01c1 100644
--- a/third_party/blink/renderer/modules/peerconnection/testing/mock_peer_connection_interface.h
+++ b/third_party/blink/renderer/modules/peerconnection/testing/mock_peer_connection_interface.h
@@ -15,194 +15,13 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/webrtc/api/peer_connection_interface.h"
 #include "third_party/webrtc/api/scoped_refptr.h"
+#include "third_party/webrtc/api/test/mock_peerconnectioninterface.h"
 #include "third_party/webrtc/rtc_base/ref_count.h"
 
 namespace blink {
 
 class MockPeerConnectionInterface
-    : public rtc::RefCountedObject<webrtc::PeerConnectionInterface> {
- public:
-  // PeerConnectionInterface
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::StreamCollectionInterface>,
-              local_streams,
-              (),
-              (override));
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::StreamCollectionInterface>,
-              remote_streams,
-              (),
-              (override));
-  MOCK_METHOD(bool, AddStream, (webrtc::MediaStreamInterface*), (override));
-  MOCK_METHOD(void, RemoveStream, (webrtc::MediaStreamInterface*), (override));
-  MOCK_METHOD(
-      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpSenderInterface>>,
-      AddTrack,
-      (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>,
-       const std::vector<std::string>&),
-      (override));
-  MOCK_METHOD(webrtc::RTCError,
-              RemoveTrackOrError,
-              (rtc::scoped_refptr<webrtc::RtpSenderInterface>),
-              (override));
-  MOCK_METHOD(
-      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>,
-      AddTransceiver,
-      (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>),
-      (override));
-  MOCK_METHOD(
-      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>,
-      AddTransceiver,
-      (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>,
-       const webrtc::RtpTransceiverInit&),
-      (override));
-  MOCK_METHOD(
-      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>,
-      AddTransceiver,
-      (cricket::MediaType),
-      (override));
-  MOCK_METHOD(
-      webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>,
-      AddTransceiver,
-      (cricket::MediaType, const webrtc::RtpTransceiverInit&),
-      (override));
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::RtpSenderInterface>,
-              CreateSender,
-              (const std::string&, const std::string&),
-              (override));
-  MOCK_METHOD(std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>>,
-              GetSenders,
-              (),
-              (const override));
-  MOCK_METHOD(std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>,
-              GetReceivers,
-              (),
-              (const override));
-  MOCK_METHOD(std::vector<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>,
-              GetTransceivers,
-              (),
-              (const override));
-  MOCK_METHOD(bool,
-              GetStats,
-              (webrtc::StatsObserver*,
-               webrtc::MediaStreamTrackInterface*,
-               StatsOutputLevel),
-              (override));
-  MOCK_METHOD(void, GetStats, (webrtc::RTCStatsCollectorCallback*), (override));
-  MOCK_METHOD(void,
-              GetStats,
-              (rtc::scoped_refptr<webrtc::RtpSenderInterface>,
-               rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback>),
-              (override));
-  MOCK_METHOD(void,
-              GetStats,
-              (rtc::scoped_refptr<webrtc::RtpReceiverInterface>,
-               rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback>),
-              (override));
-  MOCK_METHOD(void, ClearStatsCache, (), (override));
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::SctpTransportInterface>,
-              GetSctpTransport,
-              (),
-              (const override));
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::DataChannelInterface>,
-              CreateDataChannel,
-              (const std::string&, const webrtc::DataChannelInit*),
-              (override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              local_description,
-              (),
-              (const override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              remote_description,
-              (),
-              (const override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              current_local_description,
-              (),
-              (const override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              current_remote_description,
-              (),
-              (const override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              pending_local_description,
-              (),
-              (const override));
-  MOCK_METHOD(const webrtc::SessionDescriptionInterface*,
-              pending_remote_description,
-              (),
-              (const override));
-  MOCK_METHOD(void, RestartIce, (), (override));
-  MOCK_METHOD(void,
-              CreateOffer,
-              (webrtc::CreateSessionDescriptionObserver*,
-               const RTCOfferAnswerOptions&),
-              (override));
-  MOCK_METHOD(void,
-              CreateAnswer,
-              (webrtc::CreateSessionDescriptionObserver*,
-               const RTCOfferAnswerOptions&),
-              (override));
-  MOCK_METHOD(void,
-              SetLocalDescription,
-              (webrtc::SetSessionDescriptionObserver*,
-               webrtc::SessionDescriptionInterface*),
-              (override));
-  MOCK_METHOD(void,
-              SetRemoteDescription,
-              (webrtc::SetSessionDescriptionObserver*,
-               webrtc::SessionDescriptionInterface*),
-              (override));
-  MOCK_METHOD(
-      void,
-      SetRemoteDescription,
-      (std::unique_ptr<webrtc::SessionDescriptionInterface>,
-       rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>),
-      (override));
-  MOCK_METHOD(PeerConnectionInterface::RTCConfiguration,
-              GetConfiguration,
-              (),
-              (override));
-  MOCK_METHOD(webrtc::RTCError,
-              SetConfiguration,
-              (const PeerConnectionInterface::RTCConfiguration&),
-              (override));
-  MOCK_METHOD(bool,
-              AddIceCandidate,
-              (const webrtc::IceCandidateInterface*),
-              (override));
-  MOCK_METHOD(bool,
-              RemoveIceCandidates,
-              (const std::vector<cricket::Candidate>&),
-              (override));
-  MOCK_METHOD(webrtc::RTCError,
-              SetBitrate,
-              (const webrtc::BitrateSettings&),
-              (override));
-  MOCK_METHOD(void, SetAudioPlayout, (bool), (override));
-  MOCK_METHOD(void, SetAudioRecording, (bool), (override));
-  MOCK_METHOD(rtc::scoped_refptr<webrtc::DtlsTransportInterface>,
-              LookupDtlsTransportByMid,
-              (const std::string&),
-              (override));
-  MOCK_METHOD(SignalingState, signaling_state, (), (override));
-  MOCK_METHOD(IceConnectionState, ice_connection_state, (), (override));
-  MOCK_METHOD(IceConnectionState,
-              standardized_ice_connection_state,
-              (),
-              (override));
-  MOCK_METHOD(PeerConnectionState, peer_connection_state, (), (override));
-  MOCK_METHOD(IceGatheringState, ice_gathering_state, (), (override));
-  MOCK_METHOD(absl::optional<bool>, can_trickle_ice_candidates, (), (override));
-  MOCK_METHOD(bool,
-              StartRtcEventLog,
-              (std::unique_ptr<webrtc::RtcEventLogOutput>, int64_t),
-              (override));
-  MOCK_METHOD(bool,
-              StartRtcEventLog,
-              (std::unique_ptr<webrtc::RtcEventLogOutput>),
-              (override));
-  MOCK_METHOD(void, StopRtcEventLog, (), (override));
-  MOCK_METHOD(void, Close, (), (override));
-};
+    : public rtc::RefCountedObject<webrtc::MockPeerConnectionInterface> {};
 
 static_assert(!std::is_abstract<MockPeerConnectionInterface>::value, "");
 
diff --git a/third_party/blink/renderer/modules/permissions/permission_utils.cc b/third_party/blink/renderer/modules/permissions/permission_utils.cc
index 6e060bc9..81a9cb4 100644
--- a/third_party/blink/renderer/modules/permissions/permission_utils.cc
+++ b/third_party/blink/renderer/modules/permissions/permission_utils.cc
@@ -95,7 +95,7 @@
       return "nfc";
     case PermissionName::STORAGE_ACCESS:
       return "storage_access";
-    case PermissionName::WINDOW_PLACEMENT:
+    case PermissionName::WINDOW_MANAGEMENT:
       return "window_placement";
     case PermissionName::LOCAL_FONTS:
       return "local_fonts";
@@ -280,7 +280,7 @@
       exception_state.ThrowTypeError("Window Placement is not enabled.");
       return nullptr;
     }
-    return CreatePermissionDescriptor(PermissionName::WINDOW_PLACEMENT);
+    return CreatePermissionDescriptor(PermissionName::WINDOW_MANAGEMENT);
   }
   if (name == "local-fonts") {
     if (!RuntimeEnabledFeatures::FontAccessEnabled(
diff --git a/third_party/blink/renderer/modules/screen_enumeration/window_screens.cc b/third_party/blink/renderer/modules/screen_enumeration/window_screens.cc
index 03a69bc..dbd476bb 100644
--- a/third_party/blink/renderer/modules/screen_enumeration/window_screens.cc
+++ b/third_party/blink/renderer/modules/screen_enumeration/window_screens.cc
@@ -71,7 +71,7 @@
   }
 
   auto permission_descriptor = CreatePermissionDescriptor(
-      mojom::blink::PermissionName::WINDOW_PLACEMENT);
+      mojom::blink::PermissionName::WINDOW_MANAGEMENT);
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   auto callback = WTF::BindOnce(&WindowScreens::OnPermissionRequestComplete,
                                 WrapPersistent(this), WrapPersistent(resolver));
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index 672a82f..ecf1b5a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -41,72 +41,52 @@
 #include "third_party/blink/renderer/platform/scheduler/public/main_thread.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
 namespace blink {
 
 namespace {
 
-void CreateContextProvider(
-    const KURL& url,
-    base::WaitableEvent* waitable_event,
-    std::unique_ptr<WebGraphicsContext3DProvider>* created_context_provider) {
+void CreateContextProviderOnMainThread(
+    ExecutionContext* execution_context,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    CrossThreadOnceFunction<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
+        callback) {
   DCHECK(IsMainThread());
-  *created_context_provider =
-      Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url);
-  waitable_event->Signal();
-}
-
-std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProviderOnMainThread(
-    const KURL& url) {
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      Thread::MainThread()->GetDeprecatedTaskRunner();
-
-  base::WaitableEvent waitable_event;
-  std::unique_ptr<WebGraphicsContext3DProvider> created_context_provider;
+  const KURL& url = execution_context->Url();
   PostCrossThreadTask(
       *task_runner, FROM_HERE,
-      CrossThreadBindOnce(&CreateContextProvider, url,
-                          CrossThreadUnretained(&waitable_event),
-                          CrossThreadUnretained(&created_context_provider)));
-
-  waitable_event.Wait();
-  return created_context_provider;
+      CrossThreadBindOnce(
+          std::move(callback),
+          Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url)));
 }
 
-std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProvider(
-    ExecutionContext& execution_context) {
-  const KURL& url = execution_context.Url();
-  std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
+void EnsureDawnControlClientInitialized(
+    ExecutionContext* execution_context,
+    base::OnceCallback<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
+        callback) {
   if (IsMainThread()) {
-    context_provider =
-        Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url);
+    const KURL& url = execution_context->Url();
+    std::move(callback).Run(
+        Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url));
   } else {
-    context_provider = CreateContextProviderOnMainThread(url);
+    // Posts a task to the main thread to create context provider
+    // because the current RendererBlinkPlatformImpl and viz::Gpu
+    // APIs allow to create it only on the main thread.
+    // When it is created, posts it back to the current thread
+    // and call the callback with it.
+    // TODO(takahiro): Directly create context provider on Workers threads
+    //                 if RendererBlinkPlatformImpl and viz::Gpu will start to
+    //                 allow the context provider creation on Workers.
+    PostCrossThreadTask(
+        *Thread::MainThread()->GetDeprecatedTaskRunner(), FROM_HERE,
+        CrossThreadBindOnce(&CreateContextProviderOnMainThread,
+                            WrapCrossThreadPersistent(execution_context),
+                            execution_context->GetTaskRunner(TaskType::kWebGPU),
+                            CrossThreadBindOnce(std::move(callback))));
   }
-
-  // Note that we check for API blocking *after* creating the context. This is
-  // because context creation synchronizes against GpuProcessHost lifetime in
-  // the browser process, and GpuProcessHost destruction is what updates API
-  // blocking state on a GPU process crash. See https://crbug.com/1215907#c10
-  // for more details.
-  bool blocked = true;
-  mojo::Remote<mojom::blink::GpuDataManager> gpu_data_manager;
-  Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
-      gpu_data_manager.BindNewPipeAndPassReceiver());
-  gpu_data_manager->Are3DAPIsBlockedForUrl(url, &blocked);
-  if (blocked) {
-    return nullptr;
-  }
-
-  // TODO(kainino): we will need a better way of accessing the GPU interface
-  // from multiple threads than BindToCurrentSequence et al.
-  if (context_provider && !context_provider->BindToCurrentSequence()) {
-    // TODO(crbug.com/973017): Collect GPU info and surface context creation
-    // error.
-    return nullptr;
-  }
-  return context_provider;
 }
 
 [[maybe_unused]] void AddConsoleWarning(ExecutionContext* execution_context,
@@ -287,34 +267,95 @@
       .Record(context->UkmRecorder());
 }
 
-ScriptPromise GPU::requestAdapter(ScriptState* script_state,
-                                  const GPURequestAdapterOptions* options) {
-  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = resolver->Promise();
-  ExecutionContext* execution_context = ExecutionContext::From(script_state);
+std::unique_ptr<WebGraphicsContext3DProvider> CheckContextProvider(
+    const KURL& url,
+    std::unique_ptr<WebGraphicsContext3DProvider> context_provider) {
+  // Note that we check for API blocking *after* creating the context. This is
+  // because context creation synchronizes against GpuProcessHost lifetime in
+  // the browser process, and GpuProcessHost destruction is what updates API
+  // blocking state on a GPU process crash. See https://crbug.com/1215907#c10
+  // for more details.
+  bool blocked = true;
+  mojo::Remote<mojom::blink::GpuDataManager> gpu_data_manager;
+  Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+      gpu_data_manager.BindNewPipeAndPassReceiver());
+  gpu_data_manager->Are3DAPIsBlockedForUrl(url, &blocked);
+  if (blocked) {
+    return nullptr;
+  }
 
+  // TODO(kainino): we will need a better way of accessing the GPU interface
+  // from multiple threads than BindToCurrentSequence et al.
+  if (context_provider && !context_provider->BindToCurrentSequence()) {
+    // TODO(crbug.com/973017): Collect GPU info and surface context creation
+    // error.
+    return nullptr;
+  }
+
+  return context_provider;
+}
+
+void GPU::RequestAdapterImpl(ScriptState* script_state,
+                             const GPURequestAdapterOptions* options,
+                             ScriptPromiseResolver* resolver) {
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
   if (!dawn_control_client_ || dawn_control_client_->IsContextLost()) {
+    dawn_control_client_initialized_callbacks_.push_back(WTF::BindOnce(
+        [](GPU* gpu, ScriptState* script_state,
+           const GPURequestAdapterOptions* options,
+           ScriptPromiseResolver* resolver) {
+          if (gpu->dawn_control_client_ &&
+              !gpu->dawn_control_client_->IsContextLost()) {
+            gpu->RequestAdapterImpl(script_state, options, resolver);
+          } else {
+            // Failed to create context provider, won't be able to request
+            // adapter
+            // TODO(crbug.com/973017): Collect GPU info and surface context
+            // creation error.
+            resolver->Resolve(v8::Null(script_state->GetIsolate()));
+          }
+        },
+        WrapPersistent(this), WrapPersistent(script_state),
+        WrapPersistent(options), WrapPersistent(resolver)));
+
+    // Returning since the task to create the control client from a previous
+    // call to EnsureDawnControlClientInitialized should be already running
+    if (dawn_control_client_initialized_callbacks_.size() > 1) {
+      return;
+    }
+
     // TODO(natlee@microsoft.com): if GPU process is lost, wait for the GPU
     // process to come back instead of rejecting right away
-    std::unique_ptr<WebGraphicsContext3DProvider> context_provider =
-        CreateContextProvider(*execution_context);
 
-    if (!context_provider) {
-      // Failed to create context provider, won't be able to request adapter
-      // TODO(crbug.com/973017): Collect GPU info and surface context creation
-      // error.
-      resolver->Resolve(v8::Null(script_state->GetIsolate()));
-      return promise;
-    } else {
-      context_provider->WebGPUInterface()->SetWebGPUExecutionContextToken(
-          GetExecutionContextToken(execution_context));
+    EnsureDawnControlClientInitialized(
+        execution_context,
+        WTF::BindOnce(
+            [](GPU* gpu, ExecutionContext* execution_context,
+               std::unique_ptr<WebGraphicsContext3DProvider> context_provider) {
+              const KURL& url = execution_context->Url();
+              context_provider =
+                  CheckContextProvider(url, std::move(context_provider));
+              if (context_provider) {
+                context_provider->WebGPUInterface()
+                    ->SetWebGPUExecutionContextToken(
+                        GetExecutionContextToken(execution_context));
 
-      // Make a new DawnControlClientHolder with the context provider we just
-      // made and set the lost context callback
-      dawn_control_client_ = DawnControlClientHolder::Create(
-          std::move(context_provider),
-          execution_context->GetTaskRunner(TaskType::kWebGPU));
-    }
+                // Make a new DawnControlClientHolder with the context provider
+                // we just made and set the lost context callback
+                gpu->dawn_control_client_ = DawnControlClientHolder::Create(
+                    std::move(context_provider),
+                    execution_context->GetTaskRunner(TaskType::kWebGPU));
+              }
+
+              WTF::Vector<base::OnceCallback<void()>> callbacks =
+                  std::move(gpu->dawn_control_client_initialized_callbacks_);
+              for (auto& callback : callbacks) {
+                std::move(callback).Run();
+              }
+            },
+            WrapPersistent(this), WrapPersistent(execution_context)));
+
+    return;
   }
 
   DCHECK_NE(dawn_control_client_, nullptr);
@@ -332,7 +373,13 @@
       *execution_context->GetAgent()->event_loop());
 
   UseCounter::Count(execution_context, WebFeature::kWebGPU);
+}
 
+ScriptPromise GPU::requestAdapter(ScriptState* script_state,
+                                  const GPURequestAdapterOptions* options) {
+  auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise promise = resolver->Promise();
+  RequestAdapterImpl(script_state, options, resolver);
   return promise;
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.h b/third_party/blink/renderer/modules/webgpu/gpu.h
index 827d8dc..c699aa0 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu.h
@@ -8,6 +8,7 @@
 #include <dawn/webgpu.h>
 
 #include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
@@ -105,7 +106,21 @@
                                        const GPURequestAdapterOptions* options,
                                        GPUAdapter* adapter) const;
 
+  void OnContextProviderCreated(
+      const KURL& url,
+      ScriptState* script_state,
+      const GPURequestAdapterOptions* options,
+      ScriptPromiseResolver* resolver,
+      ExecutionContext* execution_context,
+      std::unique_ptr<WebGraphicsContext3DProvider> context_provider);
+
+  void RequestAdapterImpl(ScriptState* script_state,
+                          const GPURequestAdapterOptions* options,
+                          ScriptPromiseResolver* resolver);
+
   scoped_refptr<DawnControlClientHolder> dawn_control_client_;
+  WTF::Vector<base::OnceCallback<void()>>
+      dawn_control_client_initialized_callbacks_;
   HeapHashSet<WeakMember<GPUBuffer>> mappable_buffers_;
   // Mappable buffers remove themselves from this set on destruction.
   // It is boxed in a scoped_refptr so GPUBuffer can access it in its
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
index 32df292..69a153a9 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc
@@ -7,6 +7,7 @@
 #include <hb.h>
 
 #include "base/logging.h"
+#include "base/ranges/algorithm.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
@@ -411,9 +412,8 @@
 
   void Finish(unsigned from, unsigned to) {
     std::sort(cluster_starts_.begin(), cluster_starts_.end());
-    DCHECK_EQ(
-        std::adjacent_find(cluster_starts_.begin(), cluster_starts_.end()),
-        cluster_starts_.end());
+    DCHECK_EQ(base::ranges::adjacent_find(cluster_starts_),
+              cluster_starts_.end());
     DVLOG(4) << "  Cluster starts: " << base::make_span(cluster_starts_);
     if (!cluster_starts_.empty()) {
       // 'from' may point inside a cluster; the least seen index may be larger.
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 5ebd1f1..b6da23bd 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -347,7 +347,7 @@
       continue;
     auto& feedback =
         timing_details.find(frame_token)->value.presentation_feedback;
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX)
     // TODO: On Linux failure flag is unreliable, and perfectly rendered frames
     // are reported as failures all the time.
     bool presentation_failure = false;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index de5e6e97..ee01a0c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -4025,10 +4025,6 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-template-computed-nogrid.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/independent-formatting-context.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/item-percentage-height-001.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-001.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-002.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-003.html [ Failure ]
-crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-004.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-005.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-006.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/line-names-007.html [ Failure ]
@@ -4037,6 +4033,8 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-002.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-003.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-004.html [ Failure ]
+crbug.com/618969 external/wpt/css/css-grid/subgrid/parent-repeat-auto-fit-001.html [ Failure ]
+crbug.com/618969 external/wpt/css/css-grid/subgrid/parent-repeat-auto-fit-002.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/repeat-auto-fill-001.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/repeat-auto-fill-002.html [ Failure ]
 crbug.com/618969 external/wpt/css/css-grid/subgrid/repeat-auto-fill-003.html [ Failure ]
@@ -6665,6 +6663,7 @@
 crbug.com/1304956 storage/indexeddb/dont-wedge.html [ Failure Pass ]
 
 # Sheriff 2022-03-15
+crbug.com/626703 external/wpt/scroll-to-text-fragment/force-load-at-top.html [ Pass Timeout ]
 crbug.com/1269534 fast/spatial-navigation/snav-zero-margin-content.html [ Failure Pass ]
 crbug.com/1295980 virtual/fenced-frame-mparch/wpt_internal/fenced_frame/user-activation.https.html [ Failure Pass Timeout ]
 crbug.com/1295980 virtual/fenced-frame-shadow-dom/wpt_internal/fenced_frame/user-activation.https.html [ Failure Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index f120845..267642c 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -698,12 +698,6 @@
     "args": ["--disable-features=PrefersReducedMotionClientHintHeader"]
   },
   {
-    "prefix": "disable-wildcard-subdomains-in-permissions-policy",
-    "platforms": ["Linux", "Mac", "Win"],
-    "bases": ["external/wpt/permissions-policy/"],
-    "args": ["--disable-features=WildcardSubdomainsInPermissionsPolicy"]
-  },
-  {
     "prefix": "storage-access-api",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [ "external/wpt/storage-access-api" ],
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html
new file mode 100644
index 0000000..22727e39
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_all_cookies-default-samesite.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_all_cookies method w/ default SameSite</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+  document.cookie = "test0=0";
+  const cookies = await test_driver.get_all_cookies();
+  assert_equals(cookies.length, 1);
+  let cookieMap = new Map();
+  for (const cookie of cookies) {
+    cookieMap.set(cookie["name"], cookie);
+  }
+  assert_equals(cookieMap.get("test0")["name"], "test0");
+  assert_equals(cookieMap.get("test0")["value"], "0");
+  assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+}, "Get all cookies w/ default SameSite");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html
new file mode 100644
index 0000000..405473c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/get_named_cookie-default-samesite.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver get_named_cookie method  w/ default SameSite</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+promise_test(async t => {
+  document.cookie = "test0=0";
+  const cookie = await test_driver.get_named_cookie("test0");
+  assert_equals(cookie["name"], "test0");
+  assert_equals(cookie["value"], "0");
+  assert_equals(cookie["sameSite"], "Lax");
+}, "Get Named cookie  w/ default SameSite");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009-ref.html
new file mode 100644
index 0000000..103a359
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009-ref.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: subgrid line names are not inherited to a non-subgridded axis</title>
+  <link rel="author" title="Kurt Catti-Schmidt" href="mailto:kschmi@microsoft.com">
+  <link rel="help" href="https://drafts.csswg.org/css-grid-2">
+  <style>
+    html,body {
+      color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
+    }
+
+    div > div { background: grey; grid-column:2 / span 2; }
+
+    i {
+      grid-row: 1;
+      counter-increment: i;
+    }
+    i::before { content: counter(i, decimal); }
+
+    x { background: silver; }
+      </style>
+</head>
+<body>
+
+<div style="display:grid;">
+  <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][d][e]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:1 / 4;">
+      <x style="grid-column:c">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][d][e]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c / 4;">
+      <x style="grid-column:span 1">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c 2 / 4;">
+      <x style="grid-column:4">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c 2 / 4;">
+      <x style="grid-column:span 1">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c-1 / c 3;">
+      <x style="grid-column:span 1">x</x>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009.html
new file mode 100644
index 0000000..bd8a776
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/line-names-009.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: subgrid line names are not inherited to a non-subgridded axis</title>
+  <link rel="author" title="Kurt Catti-Schmidt" href="mailto:kschmi@microsoft.com">
+  <link rel="help" href="https://drafts.csswg.org/css-grid-2">
+  <link rel="match" href="line-names-009-ref.html">
+  <style>
+    html,body {
+      color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
+    }
+
+    div > div { background: grey; grid-column:2 / span 2; }
+
+    i {
+      grid-row: 1;
+      counter-increment: i;
+    }
+    i::before { content: counter(i, decimal); }
+
+    x { background: silver; }
+  </style>
+</head>
+<body>
+
+<div style="display:grid;">
+  <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][d][e]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:1 / 4;">
+      <x style="grid-column:c">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][d][e]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c / 4;">
+      <x style="grid-column:span c">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c 2 / 4;">
+      <x style="grid-column:c 2">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c 2 / 4;">
+      <x style="grid-column:span c 2">x</x>
+    </div>
+  </div>
+</div>
+
+<div style="display:grid;">
+<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
+  <div style="display:grid; grid:auto/subgrid [a][b][c][c][c]; grid-column:2 / 9;">
+    <div style="display:grid; grid:subgrid/auto; grid-column:c-1 / c 3;">
+      <x style="grid-column:span c">x</x>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/duration-with-target-low.html b/third_party/blink/web_tests/external/wpt/event-timing/duration-with-target-low.html
new file mode 100644
index 0000000..11a8c3a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/event-timing/duration-with-target-low.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<meta charset=utf-8 />
+<title>Event Timing: PerformanceObserver with a durationThreshold way smaller than processingDelay</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=resources/event-timing-test-utils.js></script>
+<div id='myDiv'>Click me</div>
+<script>
+promise_test(async t => {
+  return testDurationWithDurationThreshold(t, 'myDiv', numEntries=5, durThreshold=300, processingDelay=0);
+}, "PerformanceObserver with durationThreshold of 300 and processingDelay of 0 doesn't see any entries in the observer");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/large-duration-threshold.html b/third_party/blink/web_tests/external/wpt/event-timing/large-duration-threshold.html
index 5665d42..4eed8d97 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/large-duration-threshold.html
+++ b/third_party/blink/web_tests/external/wpt/event-timing/large-duration-threshold.html
@@ -10,7 +10,7 @@
 <div id='myDiv'>Click me</div>
 <script>
 promise_test(async t => {
-  return testDuration(t, 'myDiv', numEntries=2, dur=125, fastDur=70, slowDur=140);
+  return testDuration(t, 'myDiv', numEntries=2, dur=125, slowDur=140);
 }, "PerformanceObserver observes events according to its durationThreshold");
 </script>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/medium-duration-threshold.html b/third_party/blink/web_tests/external/wpt/event-timing/medium-duration-threshold.html
index a827f22..a2f79cf6 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/medium-duration-threshold.html
+++ b/third_party/blink/web_tests/external/wpt/event-timing/medium-duration-threshold.html
@@ -10,7 +10,7 @@
 <div id='myDiv'>Click me</div>
 <script>
 promise_test(async t => {
-  return testDuration(t, 'myDiv', numEntries=3, dur=50, fastDur=20, slowDur=70);
+  return testDuration(t, 'myDiv', numEntries=3, dur=50, slowDur=70);
 }, "PerformanceObserver observes events according to its durationThreshold");
 </script>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/min-duration-threshold.html b/third_party/blink/web_tests/external/wpt/event-timing/min-duration-threshold.html
index 443b38a2..b7382f9 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/min-duration-threshold.html
+++ b/third_party/blink/web_tests/external/wpt/event-timing/min-duration-threshold.html
@@ -10,7 +10,7 @@
 <div id='myDiv'>Click me</div>
 <script>
 promise_test(async t => {
-  return testDuration(t, 'myDiv', numEntries=5, dur=0, fastDur=0, slowDur=20);
+  return testDuration(t, 'myDiv', numEntries=5, dur=0, slowDur=20);
 }, "PerformanceObserver with durationThreshold of 0 sees events of duration >= 16");
 </script>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-test-utils.js b/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-test-utils.js
index ab3f110c..fc4d1ae 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-test-utils.js
+++ b/third_party/blink/web_tests/external/wpt/event-timing/resources/event-timing-test-utils.js
@@ -5,10 +5,12 @@
   const element = document.getElementById(id);
   const clickHandler = () => {
     mainThreadBusy(delay);
-    if (callback)
+    if (callback) {
       callback();
+    }
     element.removeEventListener("pointerdown", clickHandler);
   };
+
   element.addEventListener("pointerdown", clickHandler);
   await test_driver.click(element);
 }
@@ -81,17 +83,15 @@
   // attempt to check that the duration is appropriately checked by:
   // * Asserting that entries received have a duration which is the smallest multiple of 8
   //   that is greater than or equal to |dur|.
-  // * Issuing |numEntries| entries that are fast, of duration |slowDur|.
-  // * Issuing |numEntries| entries that are slow, of duration |fastDur|.
-  // * Asserting that at least |numEntries| entries are received (at least the slow ones).
+  // * Issuing |numEntries| entries that has duration greater than |slowDur|.
+  // * Asserting that exactly |numEntries| entries are received.
   // Parameters:
   // |t|          - the test harness.
   // |dur|        - the durationThreshold for the PerformanceObserver.
   // |id|         - the ID of the element to be clicked.
-  // |numEntries| - the number of slow and number of fast entries.
+  // |numEntries| - the number of entries.
   // |slowDur|    - the min duration of a slow entry.
-  // |fastDur|    - the min duration of a fast entry.
-async function testDuration(t, id, numEntries, dur, fastDur, slowDur) {
+async function testDuration(t, id, numEntries, dur, slowDur) {
   assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.');
   const observerPromise = new Promise(async resolve => {
     let minDuration = Math.ceil(dur / 8) * 8;
@@ -106,29 +106,62 @@
         });
       });
       numEntriesReceived += pointerDowns.length;
-      // Note that we may receive more entries if the 'fast' click events turn out slower
-      // than expected.
-      if (numEntriesReceived >= numEntries)
+      // All the entries should be received since the slowDur is higher
+      // than the duration threshold.
+      if (numEntriesReceived === numEntries)
         resolve();
     }).observe({type: "event", durationThreshold: dur});
   });
   const clicksPromise = new Promise(async resolve => {
     for (let index = 0; index < numEntries; index++) {
-      // Add some fast click events.
+      // Add some click events that has at least slowDur for duration.
       await clickOnElementAndDelay(id, slowDur);
-      // Add some slow click events.
-      if (fastDur > 0) {
-        await clickOnElementAndDelay(id, fastDur);
-      } else {
-        // We can just directly call test_driver when |fastDur| is 0.
-        await test_driver.click(document.getElementById(id));
-      }
     }
     resolve();
   });
   return Promise.all([observerPromise, clicksPromise]);
 }
 
+  // Add a PerformanceObserver and observe with a durationThreshold of |durThreshold|. This test will
+  // attempt to check that the duration is appropriately checked by:
+  // * Asserting that entries received have a duration which is the smallest multiple of 8
+  //   that is greater than or equal to |durThreshold|.
+  // * Issuing |numEntries| entries that have at least |processingDelay| as duration.
+  // * Asserting that the entries we receive has duration greater than or equals to the
+  //   duration threshold we setup
+  // Parameters:
+  // |t|                     - the test harness.
+  // |id|                    - the ID of the element to be clicked.
+  // |durThreshold|          - the durationThreshold for the PerformanceObserver.
+  // |numEntries|            - the number of slow and number of fast entries.
+  // |processingDelay|       - the event duration we add on each event.
+  async function testDurationWithDurationThreshold(t, id, numEntries, durThreshold, processingDelay) {
+    assert_implements(window.PerformanceEventTiming, 'Event Timing is not supported.');
+    const observerPromise = new Promise(async resolve => {
+      let minDuration = Math.ceil(durThreshold / 8) * 8;
+      // Exposed events must always have a minimum duration of 16.
+      minDuration = Math.max(minDuration, 16);
+      new PerformanceObserver(t.step_func(list => {
+        const pointerDowns = list.getEntriesByName('pointerdown');
+        pointerDowns.forEach(p => {
+        assert_greater_than_equal(p.duration, minDuration,
+          "The entry's duration should be greater than or equal to " + minDuration + " ms.");
+        });
+        resolve();
+      })).observe({type: "event", durationThreshold: durThreshold});
+    });
+    for (let index = 0; index < numEntries; index++) {
+      // These clicks are expected to be ignored, unless the test has some extra delays.
+      // In that case, the test will verify the event duration to ensure the event duration is
+      // greater than the duration threshold
+      await clickOnElementAndDelay(id, processingDelay);
+    }
+    // Send click with event duration equals to or greater than |durThreshold|, so the
+    // observer promise can be resolved
+    await clickOnElementAndDelay(id, durThreshold);
+    return observerPromise;
+  }
+
 // Apply events that trigger an event of the given |eventType| to be dispatched to the
 // |target|. Some of these assume that the target is not on the top left corner of the
 // screen, which means that (0, 0) of the viewport is outside of the |target|.
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
index 8545d06..a145e52 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.html
@@ -31,7 +31,8 @@
   assert_equals(cookieMap.get("test0")["secure"], false);
   assert_equals(cookieMap.get("test0")["httpOnly"], false);
   assert_equals(cookieMap.get("test0")["expiry"], undefined);
-  assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test1 [Expires in 10 days]
   assert_equals(cookieMap.get("test1")["name"], "test1");
@@ -41,7 +42,8 @@
   assert_equals(cookieMap.get("test1")["secure"], false);
   assert_equals(cookieMap.get("test1")["httpOnly"], false);
   assert_equals(cookieMap.get("test1")["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
-  assert_equals(cookieMap.get("test1")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test2 [Path /]
   assert_equals(cookieMap.get("test2")["name"], "test2");
@@ -51,7 +53,8 @@
   assert_equals(cookieMap.get("test2")["secure"], false);
   assert_equals(cookieMap.get("test2")["httpOnly"], false);
   assert_equals(cookieMap.get("test2")["expiry"], undefined);
-  assert_equals(cookieMap.get("test2")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test3 [HttpOnly]
   assert_equals(cookieMap.get("test3")["name"], "test3");
@@ -61,7 +64,8 @@
   assert_equals(cookieMap.get("test3")["secure"], false);
   assert_equals(cookieMap.get("test3")["httpOnly"], true);
   assert_equals(cookieMap.get("test3")["expiry"], undefined);
-  assert_equals(cookieMap.get("test3")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test4 [Secure] Omitted
 
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
index 08ab8cc3..e3402780 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_all_cookies.sub.https.html
@@ -31,7 +31,8 @@
   assert_equals(cookieMap.get("test0")["secure"], false);
   assert_equals(cookieMap.get("test0")["httpOnly"], false);
   assert_equals(cookieMap.get("test0")["expiry"], undefined);
-  assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test1 [Expires in 10 days]
   assert_equals(cookieMap.get("test1")["name"], "test1");
@@ -41,7 +42,8 @@
   assert_equals(cookieMap.get("test1")["secure"], false);
   assert_equals(cookieMap.get("test1")["httpOnly"], false);
   assert_equals(cookieMap.get("test1")["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
-  assert_equals(cookieMap.get("test1")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test2 [Path /]
   assert_equals(cookieMap.get("test2")["name"], "test2");
@@ -51,7 +53,8 @@
   assert_equals(cookieMap.get("test2")["secure"], false);
   assert_equals(cookieMap.get("test2")["httpOnly"], false);
   assert_equals(cookieMap.get("test2")["expiry"], undefined);
-  assert_equals(cookieMap.get("test2")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test3 [HttpOnly]
   assert_equals(cookieMap.get("test3")["name"], "test3");
@@ -61,7 +64,8 @@
   assert_equals(cookieMap.get("test3")["secure"], false);
   assert_equals(cookieMap.get("test3")["httpOnly"], true);
   assert_equals(cookieMap.get("test3")["expiry"], undefined);
-  assert_equals(cookieMap.get("test3")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test4 [Secure]
   assert_equals(cookieMap.get("test4")["name"], "test4");
@@ -71,7 +75,8 @@
   assert_equals(cookieMap.get("test4")["secure"], true);
   assert_equals(cookieMap.get("test4")["httpOnly"], false);
   assert_equals(cookieMap.get("test4")["expiry"], undefined);
-  assert_equals(cookieMap.get("test4")["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookieMap.get("test0")["sameSite"], "Lax");
 
   // test5 [SameSite Strict]
   assert_equals(cookieMap.get("test5")["name"], "test5");
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
index c3a8eed..3cbc784 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.html
@@ -26,7 +26,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test1 [Expires in 10 days]
   cookie = await test_driver.get_named_cookie("test1");
@@ -37,7 +38,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test2 [Path /]
   cookie = await test_driver.get_named_cookie("test2");
@@ -48,7 +50,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test3 [HttpOnly]
   cookie = await test_driver.get_named_cookie("test3");
@@ -59,7 +62,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], true);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test4 [Secure] Omitted
   try {
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
index d316d4e..d0d8612a 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/get_named_cookie.sub.https.html
@@ -26,7 +26,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test1 [Expires in 10 days]
   cookie = await test_driver.get_named_cookie("test1");
@@ -37,7 +38,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], Math.floor(kTenDaysFromNow.getTime()/1000));
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test2 [Path /]
   cookie = await test_driver.get_named_cookie("test2");
@@ -48,7 +50,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test3 [HttpOnly]
   cookie = await test_driver.get_named_cookie("test3");
@@ -59,7 +62,8 @@
   assert_equals(cookie["secure"], false);
   assert_equals(cookie["httpOnly"], true);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test4 [Secure]
   cookie = await test_driver.get_named_cookie("test4");
@@ -70,7 +74,8 @@
   assert_equals(cookie["secure"], true);
   assert_equals(cookie["httpOnly"], false);
   assert_equals(cookie["expiry"], undefined);
-  assert_equals(cookie["sameSite"], "Lax");
+  // The 'default lax' behavior varies by browser.
+  // assert_equals(cookie["sameSite"], "Lax");
 
   // test5 [SameSite Strict]
   cookie = await test_driver.get_named_cookie("test5");
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
index c9ca12c2..19ec66a 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 499 tests; 483 PASS, 16 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 499 tests; 484 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS Test driver for asyncInitCertificate
@@ -41,7 +41,7 @@
 PASS RTCPeerConnection interface: attribute canTrickleIceCandidates
 PASS RTCPeerConnection interface: operation restartIce()
 PASS RTCPeerConnection interface: operation getConfiguration()
-FAIL RTCPeerConnection interface: operation setConfiguration(optional RTCConfiguration) assert_equals: property has wrong .length expected 0 but got 1
+PASS RTCPeerConnection interface: operation setConfiguration(optional RTCConfiguration)
 PASS RTCPeerConnection interface: operation close()
 PASS RTCPeerConnection interface: attribute onnegotiationneeded
 PASS RTCPeerConnection interface: attribute onicecandidate
diff --git a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/README.md b/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/README.md
deleted file mode 100644
index 31860a83..0000000
--- a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Tests with WildcardSubdomainsInPermissionsPolicy enabled.
diff --git a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/README.txt b/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/README.txt
deleted file mode 100644
index 31860a83..0000000
--- a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tests with WildcardSubdomainsInPermissionsPolicy enabled.
diff --git a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub-expected.txt b/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub-expected.txt
deleted file mode 100644
index 23dbddc..0000000
--- a/third_party/blink/web_tests/virtual/disable-wildcard-subdomains-in-permissions-policy/external/wpt/permissions-policy/permissions-policy-header-policy-allowed-for-wildcard.https.sub-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test allowlist is [self wildcard_origin]. assert_array_equals: expected property 0 to be "https://*.web-platform.test:8444" but got "https://%2A.web-platform.test:8444" (expected array ["https://*.web-platform.test:8444", "https://web-platform.test:8444"] got ["https://%2A.web-platform.test:8444", "https://web-platform.test:8444"])
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is allowed on same-origin subframe
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is allowed on same-origin subframe even with allow attribute
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is disallowed on cross-origin subframe
-FAIL Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is allowed on cross-origin subframe allow attribute assert_true: fullscreen expected true got false
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is disallowed on another cross-origin subframe
-FAIL Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is allowed on another cross-origin subframe allow attribute assert_true: fullscreen expected true got false
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is disallowed on cross-origin subframe with wildcard allow attribute
-PASS Permissions-Policy: fullscreen=("https://*.web-platform.test:8444") -- test fullscreen is disallowed on another cross-origin subframe with wildcard allow attribute
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/document-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt b/third_party/blink/web_tests/virtual/document-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
index 95e3f8f..06613e3 100644
--- a/third_party/blink/web_tests/virtual/document-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/document-transition-wide-gamut/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
@@ -101,28 +101,56 @@
                                         value : 0px
                                     }
                                     [2] : {
-                                        name : right
-                                        value : 0px
-                                    }
-                                    [3] : {
-                                        name : bottom
-                                        value : 0px
-                                    }
-                                    [4] : {
                                         name : left
                                         value : 0px
                                     }
-                                    [5] : {
+                                    [3] : {
                                         name : pointer-events
                                         value : none
                                     }
                                 ]
                                 shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [1] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
                                     [0] : {
-                                        name : inset
-                                        value : 0px
+                                        text : html::page-transition
                                     }
                                 ]
+                                text : html::page-transition
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : width
+                                        value : 800px
+                                    }
+                                    [1] : {
+                                        name : height
+                                        value : 600px
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
                             }
                             supports : [
                             ]
@@ -1672,28 +1700,56 @@
                                 value : 0px
                             }
                             [2] : {
-                                name : right
-                                value : 0px
-                            }
-                            [3] : {
-                                name : bottom
-                                value : 0px
-                            }
-                            [4] : {
                                 name : left
                                 value : 0px
                             }
-                            [5] : {
+                            [3] : {
                                 name : pointer-events
                                 value : none
                             }
                         ]
                         shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [1] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
                             [0] : {
-                                name : inset
-                                value : 0px
+                                text : html::page-transition
                             }
                         ]
+                        text : html::page-transition
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : width
+                                value : 800px
+                            }
+                            [1] : {
+                                name : height
+                                value : 600px
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
                     }
                     supports : [
                     ]
diff --git a/third_party/blink/web_tests/virtual/document-transition/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt b/third_party/blink/web_tests/virtual/document-transition/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
index 95e3f8f..06613e3 100644
--- a/third_party/blink/web_tests/virtual/document-transition/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
+++ b/third_party/blink/web_tests/virtual/document-transition/inspector-protocol/css/css-get-styles-for-document-transition-expected.txt
@@ -101,28 +101,56 @@
                                         value : 0px
                                     }
                                     [2] : {
-                                        name : right
-                                        value : 0px
-                                    }
-                                    [3] : {
-                                        name : bottom
-                                        value : 0px
-                                    }
-                                    [4] : {
                                         name : left
                                         value : 0px
                                     }
-                                    [5] : {
+                                    [3] : {
                                         name : pointer-events
                                         value : none
                                     }
                                 ]
                                 shorthandEntries : [
+                                ]
+                            }
+                            supports : [
+                            ]
+                        }
+                    }
+                    [1] : {
+                        matchingSelectors : [
+                            [0] : 0
+                        ]
+                        rule : {
+                            containerQueries : [
+                            ]
+                            layers : [
+                            ]
+                            media : [
+                            ]
+                            origin : user-agent
+                            scopes : [
+                            ]
+                            selectorList : {
+                                selectors : [
                                     [0] : {
-                                        name : inset
-                                        value : 0px
+                                        text : html::page-transition
                                     }
                                 ]
+                                text : html::page-transition
+                            }
+                            style : {
+                                cssProperties : [
+                                    [0] : {
+                                        name : width
+                                        value : 800px
+                                    }
+                                    [1] : {
+                                        name : height
+                                        value : 600px
+                                    }
+                                ]
+                                shorthandEntries : [
+                                ]
                             }
                             supports : [
                             ]
@@ -1672,28 +1700,56 @@
                                 value : 0px
                             }
                             [2] : {
-                                name : right
-                                value : 0px
-                            }
-                            [3] : {
-                                name : bottom
-                                value : 0px
-                            }
-                            [4] : {
                                 name : left
                                 value : 0px
                             }
-                            [5] : {
+                            [3] : {
                                 name : pointer-events
                                 value : none
                             }
                         ]
                         shorthandEntries : [
+                        ]
+                    }
+                    supports : [
+                    ]
+                }
+            }
+            [1] : {
+                matchingSelectors : [
+                    [0] : 0
+                ]
+                rule : {
+                    containerQueries : [
+                    ]
+                    layers : [
+                    ]
+                    media : [
+                    ]
+                    origin : user-agent
+                    scopes : [
+                    ]
+                    selectorList : {
+                        selectors : [
                             [0] : {
-                                name : inset
-                                value : 0px
+                                text : html::page-transition
                             }
                         ]
+                        text : html::page-transition
+                    }
+                    style : {
+                        cssProperties : [
+                            [0] : {
+                                name : width
+                                value : 800px
+                            }
+                            [1] : {
+                                name : height
+                                value : 600px
+                            }
+                        ]
+                        shorthandEntries : [
+                        ]
                     }
                     supports : [
                     ]
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/content-with-clip-root.html b/third_party/blink/web_tests/wpt_internal/document-transition/content-with-clip-root.html
index fa57a3b..1aa2d060 100644
--- a/third_party/blink/web_tests/wpt_internal/document-transition/content-with-clip-root.html
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/content-with-clip-root.html
@@ -41,7 +41,6 @@
 }
 
 html::page-transition-container(root) {
-  position: fixed;
   top: -50vh;
   bottom: 50vh;
 }
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars-ref.html b/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars-ref.html
new file mode 100644
index 0000000..b84efaa
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Shared transitions: incoming viewport has scrollbars (ref)</title>
+<link rel="help" href="https://github.com/WICG/shared-element-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+  html, body {
+    width: 100%;
+    height: 100%;
+    background-color: lightpink;
+  }
+  body {
+    margin: 50px;
+  }
+  div {
+    background-image:
+      linear-gradient(45deg, #000 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, #000 25%, lightgreen 25%);
+    background-size: 200px 200px;
+    background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+    width: 200%;
+    height: 200%;
+  }
+</style>
+<div></div>
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars.html b/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars.html
new file mode 100644
index 0000000..eb112b2d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/new-content-has-scrollbars.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>Shared transitions: incoming viewport has scrollbars</title>
+<link rel="help" href="https://github.com/WICG/shared-element-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="new-content-has-scrollbars-ref.html">
+<meta name=fuzzy content="new-content-has-scrollbars-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  html, body {
+    width: 100%;
+    height: 100%;
+    background-color: lightpink;
+  }
+  html {
+    overflow: hidden;
+  }
+  body {
+    /* Margin to make sure background color is correctly drawn into the snapshot. */
+    margin: 50px;
+  }
+  div {
+    /* Draw a checkerboard pattern to make sure the snapshot is captured at the
+     * full size, rather than scaled. */
+    background-image:
+      linear-gradient(45deg, #000 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, #000 25%, lightgreen 25%);
+    background-size: 200px 200px;
+    background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+    width: 200%;
+    height: 200%;
+  }
+
+  /* We're verifying what we capture, so just display the old contents for 5 minutes.  */
+  html::page-transition-incoming-image(root) { animation: unset; opacity: 0; }
+  html::page-transition-outgoing-image(root) {
+    animation-duration: 3s;
+    animation-timing-function: steps(1, end);
+    opacity: 1;
+  }
+</style>
+
+<div></div>
+<script>
+// Ensure a root snapshot captured in the absence of scrollbars is displayed at
+// full size when rendered in the incoming viewport which is inset by
+// scrollbars. The content must not be scaled-to-fit.
+async function runTest() {
+  let t = document.createDocumentTransition();
+  t.start(() => {
+    document.documentElement.style.overflow = "unset";
+    requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+  });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars-ref.html b/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars-ref.html
new file mode 100644
index 0000000..4c7d9760
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Shared transitions: outgoing viewport has scrollbars (ref)</title>
+<link rel="help" href="https://github.com/WICG/shared-element-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<style>
+  html, body {
+    width: 100%;
+    height: 100%;
+    background-color: lightpink;
+  }
+  html {
+    overflow: hidden;
+  }
+  body {
+    margin: 50px;
+  }
+  div {
+    background-image:
+      linear-gradient(45deg, #000 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, #000 25%, lightgreen 25%);
+    background-size: 200px 200px;
+    background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+    width: 200%;
+    height: 200%;
+  }
+</style>
+<div></div>
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars.html b/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars.html
new file mode 100644
index 0000000..b5314f8d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/old-content-has-scrollbars.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<html class=reftest-wait>
+<title>Shared transitions: outgoing viewport has scrollbars</title>
+<link rel="help" href="https://github.com/WICG/shared-element-transitions">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7859">
+<link rel="author" href="mailto:bokan@chromium.org">
+<link rel="match" href="old-content-has-scrollbars-ref.html">
+<meta name=fuzzy content="old-content-has-scrollbars-ref.html:0-40;0-30000">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  html, body {
+    width: 100%;
+    height: 100%;
+    background-color: lightpink;
+  }
+  body {
+    /* Margin to make sure background color is correctly drawn into the snapshot. */
+    margin: 50px;
+  }
+  div {
+    /* Draw a checkerboard pattern to make sure the snapshot is captured at the
+     * full size, rather than scaled. */
+    background-image:
+      linear-gradient(45deg, #000 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, transparent 75%, #000 75%),
+      linear-gradient(45deg, #000 25%, lightgreen 25%);
+    background-size: 200px 200px;
+    background-position: 0 0, 0 0, -100px -100px, 100px 100px;
+    width: 200%;
+    height: 200%;
+  }
+
+  /* We're verifying what we capture, so just display the old contents for 5 minutes.  */
+  html::page-transition-incoming-image(root) { animation: unset; opacity: 0; }
+  html::page-transition-outgoing-image(root) {
+    animation-duration: 300s;
+    animation-timing-function: steps(1, end);
+    opacity: 1;
+  }
+</style>
+
+<div></div>
+<script>
+// Ensure a root snapshot captured on a page with scrollbars uses the full
+// viewport size (including scrollbars). Areas obscured by scrollbars should be
+// filled with background and content; the snapshot should not be scaled-to-fit.
+async function runTest() {
+  let t = document.createDocumentTransition();
+  t.start(() => {
+    document.querySelector('div').remove();
+    document.documentElement.style.overflow = "hidden";
+    requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+  });
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
+
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js
index 5237e93..c8731eb 100644
--- a/third_party/closure_compiler/externs/accessibility_private.js
+++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -265,6 +265,7 @@
   ENHANCED_NETWORK_VOICES: 'enhancedNetworkVoices',
   GOOGLE_TTS_LANGUAGE_PACKS: 'googleTtsLanguagePacks',
   DICTATION_PUMPKIN_PARSING: 'dictationPumpkinParsing',
+  DICTATION_MORE_COMMANDS: 'dictationMoreCommands',
   SELECT_TO_SPEAK_VOICE_SWITCHING: 'selectToSpeakVoiceSwitching',
 };
 
diff --git a/third_party/d3/OWNERS b/third_party/d3/OWNERS
index 81967977..1bef084 100644
--- a/third_party/d3/OWNERS
+++ b/third_party/d3/OWNERS
@@ -1,2 +1 @@
-chrisha@chromium.org
 zentaro@chromium.org
diff --git a/third_party/dom_distiller_js/BUILD.gn b/third_party/dom_distiller_js/BUILD.gn
index 7096af7..81b46bc 100644
--- a/third_party/dom_distiller_js/BUILD.gn
+++ b/third_party/dom_distiller_js/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/LICENSE b/third_party/dom_distiller_js/LICENSE
index 085efa7..3a8aeb9 100644
--- a/third_party/dom_distiller_js/LICENSE
+++ b/third_party/dom_distiller_js/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2014 The Chromium Authors. All rights reserved.
+Copyright 2014 The Chromium Authors
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
diff --git a/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py b/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py
index a65f08f..6c044001 100755
--- a/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py
+++ b/third_party/dom_distiller_js/protoc_plugins/json_values_converter.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/protoc_plugins/json_values_converter_tests.py b/third_party/dom_distiller_js/protoc_plugins/json_values_converter_tests.py
index 0318983..54ae94fe 100755
--- a/third_party/dom_distiller_js/protoc_plugins/json_values_converter_tests.py
+++ b/third_party/dom_distiller_js/protoc_plugins/json_values_converter_tests.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Copyright (c) 2016 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/protoc_plugins/util/plugin_protos.py b/third_party/dom_distiller_js/protoc_plugins/util/plugin_protos.py
index 352591c..2c03e6835 100644
--- a/third_party/dom_distiller_js/protoc_plugins/util/plugin_protos.py
+++ b/third_party/dom_distiller_js/protoc_plugins/util/plugin_protos.py
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/protoc_plugins/util/types.py b/third_party/dom_distiller_js/protoc_plugins/util/types.py
index b82b8500..f33e01b 100644
--- a/third_party/dom_distiller_js/protoc_plugins/util/types.py
+++ b/third_party/dom_distiller_js/protoc_plugins/util/types.py
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/protoc_plugins/util/writer.py b/third_party/dom_distiller_js/protoc_plugins/util/writer.py
index a56e9cb..9ee673a 100644
--- a/third_party/dom_distiller_js/protoc_plugins/util/writer.py
+++ b/third_party/dom_distiller_js/protoc_plugins/util/writer.py
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/test_sample.proto b/third_party/dom_distiller_js/test_sample.proto
index bceb5c7..30167fe 100644
--- a/third_party/dom_distiller_js/test_sample.proto
+++ b/third_party/dom_distiller_js/test_sample.proto
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/third_party/dom_distiller_js/update_domdistiller_js.sh b/third_party/dom_distiller_js/update_domdistiller_js.sh
index 4cd40433..50417d1 100755
--- a/third_party/dom_distiller_js/update_domdistiller_js.sh
+++ b/third_party/dom_distiller_js/update_domdistiller_js.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 #
diff --git a/third_party/grpc/BUILD.gn b/third_party/grpc/BUILD.gn
index 1fd7a2e..986d256 100644
--- a/third_party/grpc/BUILD.gn
+++ b/third_party/grpc/BUILD.gn
@@ -54,6 +54,10 @@
     "-Wno-shadow",
     "-Wno-unreachable-code-return",
     "-Wno-unreachable-code-break",
+
+    # TODO(crbug.com/1372394): Remove after integrating
+    # https://github.com/grpc/grpc/pull/31306
+    "-Wno-thread-safety-analysis",
   ]
 
   if (is_android) {
diff --git a/third_party/grpc/template/BUILD.chromium.gn.template b/third_party/grpc/template/BUILD.chromium.gn.template
index 991c94c..b30a7db 100644
--- a/third_party/grpc/template/BUILD.chromium.gn.template
+++ b/third_party/grpc/template/BUILD.chromium.gn.template
@@ -15,11 +15,12 @@
 
     # TODO(169395837): Somehow gRPC symbols cannot be found on Android.
     # Keep using static linking for now.
-    # In windows and mac use static linking.
+    # In windows, mac and iOS use static linking.
     # Use static linking on Chrome OS as a workaround for the symbol lookup
     # error(crbug/1241330) due to a gRPC version mismatch between what Chrome
     # uses and what CrOS provides.
-    grpc_use_static_linking = is_android || is_win || is_chromeos || is_mac
+    grpc_use_static_linking =
+        is_android || is_win || is_chromeos || is_mac || is_ios
   }
 
   if (is_android) {
@@ -58,6 +59,10 @@
       "-Wno-shadow",
       "-Wno-unreachable-code-return",
       "-Wno-unreachable-code-break",
+
+      # TODO(crbug.com/1372394): Remove after integrating
+      # https://github.com/grpc/grpc/pull/31306
+      "-Wno-thread-safety-analysis",
     ]
 
     if (is_android) {
diff --git a/tools/android/test_health/README.md b/tools/android/test_health/README.md
index b10e50d9..9267322 100644
--- a/tools/android/test_health/README.md
+++ b/tools/android/test_health/README.md
@@ -11,7 +11,7 @@
 The `get_test_health.py` script extracts Java test health from a Git repository.
 The script defaults to the Chromium repository containing this script itself.
 The test health data includes a listing of tests that are disabled (annotated as
-`@DisabledTest`), conditionally-disabled (`@DisableIf`) or flaky (`@FlakyTest`).
+`@DisabledTest`) or conditionally-disabled (`@DisableIf`).
 The script exports the data in newline-delimited JSON
 ([JSON Lines](http://jsonlines.org)) format so that it can be easily
 [ingested into BigQuery][bq-load-gcs-json].
@@ -43,8 +43,8 @@
 ### Java Test Utilities
 
 The `java_test_utils` module contains utility functions to extract counts of
-test cases annotated with `@DisabledTest`, `@DisableIf` and `@FlakyTest`, as
-well as the Java package name, from the source code of Java test files.
+test cases annotated with `@DisabledTest` and `@DisableIf`, as well as the
+Java package name, from the source code of Java test files.
 
 ### Other Modules
 
diff --git a/tools/android/test_health/java_test_utils.py b/tools/android/test_health/java_test_utils.py
index 1082bd7..a1cd9f138 100644
--- a/tools/android/test_health/java_test_utils.py
+++ b/tools/android/test_health/java_test_utils.py
@@ -32,7 +32,6 @@
 
 _DISABLED_TEST_ANNOTATION = 'DisabledTest'
 _DISABLE_IF_TEST_ANNOTATION = 'DisableIf'
-_FLAKY_TEST_ANNOTATION = 'FlakyTest'
 
 _DISABLE_IF_TEST_PATTERN = re.compile(_DISABLE_IF_TEST_ANNOTATION + r'\.\w+')
 
@@ -47,7 +46,7 @@
     disable_if_tests_count: int
     """The number of test cases annotated with @DisableIf."""
     flaky_tests_count: int
-    """The number of test cases annotated with @FlakyTest."""
+    """The number of test cases annotated with the removed @FlakyTest, now always 0."""
 
 
 def get_java_test_health(test_path: pathlib.Path) -> JavaTestHealth:
@@ -108,7 +107,7 @@
         java_package=_get_java_package_name(java_ast),
         disabled_tests_count=annotation_counter[_DISABLED_TEST_ANNOTATION],
         disable_if_tests_count=annotation_counter[_DISABLE_IF_TEST_ANNOTATION],
-        flaky_tests_count=annotation_counter[_FLAKY_TEST_ANNOTATION])
+        flaky_tests_count=0)
 
 
 def _get_java_package_name(java_ast: CompilationUnit) -> Optional[str]:
@@ -137,8 +136,6 @@
             counter[_DISABLED_TEST_ANNOTATION] += 1
         elif re.fullmatch(_DISABLE_IF_TEST_PATTERN, annotation.name):
             counter[_DISABLE_IF_TEST_ANNOTATION] += 1
-        elif annotation.name == _FLAKY_TEST_ANNOTATION:
-            counter[_FLAKY_TEST_ANNOTATION] += 1
 
     return counter
 
diff --git a/tools/android/test_health/java_test_utils_unittest.py b/tools/android/test_health/java_test_utils_unittest.py
index b290b62..1cdce9e 100755
--- a/tools/android/test_health/java_test_utils_unittest.py
+++ b/tools/android/test_health/java_test_utils_unittest.py
@@ -33,13 +33,11 @@
                        'SampleDisabledTest.java')
 _DISABLE_IF_TEST_PATH = (_TEST_FILES_PATH / 'disabled_tests' /
                          'SampleDisableIfTest.java')
-_FLAKY_TEST_PATH = _TEST_FILES_PATH / 'flaky_tests' / 'SampleFlakyTest.java'
 
 _BASE_JAVA_PACKAGE = 'org.chromium.chrome.browser.test_health'
 _JAVA_PACKAGE_HEALTHY_TESTS = _BASE_JAVA_PACKAGE + '.healthy_tests'
 _JAVA_PACKAGE_UNHEALTHY_TESTS = _BASE_JAVA_PACKAGE + '.unhealthy_tests'
 _JAVA_PACKAGE_DISABLED_TESTS = _BASE_JAVA_PACKAGE + '.disabled_tests'
-_JAVA_PACKAGE_FLAKY_TESTS = _BASE_JAVA_PACKAGE + '.flaky_tests'
 
 
 class TestJavaTestHealthStats(unittest.TestCase):
@@ -70,7 +68,7 @@
                          test_health.java_package)
         self.assertEqual(1, test_health.disabled_tests_count)
         self.assertEqual(1, test_health.disable_if_tests_count)
-        self.assertEqual(1, test_health.flaky_tests_count)
+        self.assertEqual(0, test_health.flaky_tests_count)
 
     def test_get_java_test_health_stats_disabled_tests(self):
         test_health = java_test_utils.get_java_test_health(_DISABLED_TEST_PATH)
@@ -91,14 +89,6 @@
         self.assertEqual(2, test_health.disable_if_tests_count)
         self.assertEqual(0, test_health.flaky_tests_count)
 
-    def test_get_java_test_health_stats_flaky_tests(self):
-        test_health = java_test_utils.get_java_test_health(_FLAKY_TEST_PATH)
-
-        self.assertEqual(_JAVA_PACKAGE_FLAKY_TESTS, test_health.java_package)
-        self.assertEqual(0, test_health.disabled_tests_count)
-        self.assertEqual(0, test_health.disable_if_tests_count)
-        self.assertEqual(2, test_health.flaky_tests_count)
-
     def test_get_java_test_health_invalid_test_syntax(self):
         expected_filename = str(
             _INVALID_SYNTAX_TEST_PATH.relative_to(_CHROMIUM_SRC_PATH))
diff --git a/tools/android/test_health/test_health_extractor.py b/tools/android/test_health/test_health_extractor.py
index c1f5251..aac763e 100644
--- a/tools/android/test_health/test_health_extractor.py
+++ b/tools/android/test_health/test_health_extractor.py
@@ -65,7 +65,7 @@
                          ) -> List[TestHealthInfo]:
     """Gets test health information and stats for a Git repository.
 
-    This function checks for Java tests annotated as disabled or flaky but could
+    This function checks for Java tests annotated as disabled but could
     be extended to check other metrics or languages in the future.
 
     Args:
diff --git a/tools/android/test_health/test_health_extractor_unittest.py b/tools/android/test_health/test_health_extractor_unittest.py
index ab05ae3d2..5318ddb 100755
--- a/tools/android/test_health/test_health_extractor_unittest.py
+++ b/tools/android/test_health/test_health_extractor_unittest.py
@@ -31,7 +31,7 @@
     _UNHEALTHY_TESTS_PATH /
     'InvalidSyntaxTest.java').relative_to(_TEST_FILES_PATH)
 
-_IGNORED_DIRS = ('disabled_tests', 'flaky_tests', 'unhealthy_tests')
+_IGNORED_DIRS = ('disabled_tests', 'unhealthy_tests')
 
 _BASE_JAVA_PACKAGE = 'org.chromium.chrome.browser.test_health'
 _JAVA_PACKAGE_HEALTHY_TESTS = _BASE_JAVA_PACKAGE + '.healthy_tests'
@@ -74,12 +74,12 @@
                 java_package=_JAVA_PACKAGE_UNHEALTHY_TESTS,
                 disabled_tests_count=1,
                 disable_if_tests_count=1,
-                flaky_tests_count=1),
+                flaky_tests_count=0),
             git_repo_info=_CHROMIUM_REPO_INFO)
 
         test_health_infos = test_health_extractor.get_repo_test_health(
             test_dir=_TEST_FILES_PATH,
-            ignored_dirs=('disabled_tests', 'flaky_tests', 'healthy_tests'),
+            ignored_dirs=('disabled_tests', 'healthy_tests'),
             ignored_files={str(_INVALID_SYNTAX_TEST_PATH)})
 
         self.assertEqual(expected_test_health_info, test_health_infos[0])
@@ -101,8 +101,7 @@
         with self.assertLogs(level=logging.WARNING) as logging_cm:
             test_health_infos = test_health_extractor.get_repo_test_health(
                 test_dir=_TEST_FILES_PATH,
-                ignored_dirs=('disabled_tests', 'flaky_tests',
-                              'healthy_tests'),
+                ignored_dirs=('disabled_tests', 'healthy_tests'),
                 ignored_files={
                     str((_UNHEALTHY_TESTS_PATH /
                          'SampleTest.java').relative_to(_TEST_FILES_PATH))
diff --git a/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/flaky_tests/SampleFlakyTest.java b/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/flaky_tests/SampleFlakyTest.java
deleted file mode 100644
index 327844b..0000000
--- a/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/flaky_tests/SampleFlakyTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.test_health.flaky_tests;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.BaseJUnit4ClassRunner;
-
-import java.util.Random;
-
-/** A sample Java test with flaky test cases. */
-@SmallTest
-@RunWith(BaseJUnit4ClassRunner.class)
-public class SampleFlakyTest {
-    @FlakyTest(message = "Flaky since value is sometimes false.")
-    @Test
-    public void testFalseIsTrue() {
-        Random random = new Random();
-
-        boolean value = random.nextBoolean();
-
-        Assert.assertTrue(value);
-    }
-
-    @FlakyTest
-    @Test
-    public void testTrueIsFalse() {
-        // Flaky since value is sometimes true.
-        Random random = new Random();
-
-        boolean value = random.nextBoolean();
-
-        Assert.assertFalse(value);
-    }
-}
diff --git a/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/unhealthy_tests/SampleTest.java b/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/unhealthy_tests/SampleTest.java
index 3d60625..cc7f969 100644
--- a/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/unhealthy_tests/SampleTest.java
+++ b/tools/android/test_health/testdata/javatests/org/chromium/chrome/browser/test_health/unhealthy_tests/SampleTest.java
@@ -13,9 +13,6 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.FlakyTest;
-
-import java.util.Random;
 
 /** A sample Java test. */
 @SmallTest
@@ -42,14 +39,4 @@
     public void testDisableIfTest() {
         Assert.assertTrue(false);
     }
-
-    @FlakyTest
-    @Test
-    public void testFlakyTest() {
-        Random random = new Random();
-
-        boolean value = random.nextBoolean();
-
-        Assert.assertFalse(value);
-    }
 }
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 4b44cd26..764d487 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -1019,15 +1019,20 @@
         # results on
         # https://chromium-review.googlesource.com/c/chromium/src/+/3702739/4
         # Maybe it should work for builtins too?
-        ('armv7-unknown-linux-gnueabihf',
-         compiler_rt_cmake_flags(sanitizers=True, profile=True) + [
-             'CMAKE_SYSROOT=%s' % sysroot_arm,
-         ]))
-    runtimes_triples_args.append(
-        ('aarch64-unknown-linux-gnu',
-         compiler_rt_cmake_flags(sanitizers=True, profile=True) + [
-             'CMAKE_SYSROOT=%s' % sysroot_arm64,
-         ]))
+        (
+            'armv7-unknown-linux-gnueabihf',
+            compiler_rt_cmake_flags(sanitizers=True, profile=True) + [
+                'CMAKE_SYSROOT=%s' % sysroot_arm,
+                # Can't run tests on x86 host.
+                'LLVM_INCLUDE_TESTS=OFF',
+            ]))
+    runtimes_triples_args.append((
+        'aarch64-unknown-linux-gnu',
+        compiler_rt_cmake_flags(sanitizers=True, profile=True) + [
+            'CMAKE_SYSROOT=%s' % sysroot_arm64,
+            # Can't run tests on x86 host.
+            'LLVM_INCLUDE_TESTS=OFF',
+        ]))
   elif sys.platform == 'win32':
     runtimes_triples_args.append(
         ('i386-pc-windows-msvc',
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 01f27f9..8b0842c 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -474,6 +474,10 @@
     "META": {"sizes": {"includes": [10]}},
     "includes": [2665],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/lens/resources.grd": {
+    "META": {"sizes": {"includes": [10]}},
+    "includes": [2675],
+  },
   # END chrome/ WebUI resources section
 
   # START chrome/ miscellaneous section.
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 12903c68..d093ce1 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -3619,6 +3619,9 @@
 </action>
 
 <action name="AppList_ShowPlayStoreQueryResults">
+  <obsolete>
+    Deprecated in M108. App List search no longer shows tile results.
+  </obsolete>
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <description>
@@ -3660,6 +3663,7 @@
 </action>
 
 <action name="AppList_ZeroStateOpenInstalledApp">
+  <obsolete>Deprecated in M108. Launcher zero state has been removed.</obsolete>
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <description>User opens a suggested installed app in zero state.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ebc6183e..f8f36a345 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21688,6 +21688,7 @@
   <int value="24" label="SMART_SELECT_BTWN_INCL"/>
   <int value="25" label="NAV_NEXT_SENT"/>
   <int value="26" label="NAV_PREV_SENT"/>
+  <int value="27" label="DELETE_ALL_TEXT"/>
 </enum>
 
 <enum name="CrosDictationToggleDictationMethod">
@@ -56726,6 +56727,7 @@
   <int value="-2112547309" label="ClickToCallReceiver:enabled"/>
   <int value="-2111273398" label="SendTabToSelfManageDevicesLink:enabled"/>
   <int value="-2111196530" label="EnableAssistantLauncherUI:disabled"/>
+  <int value="-2108866112" label="FeedHeaderStickToTop:enabled"/>
   <int value="-2108564200" label="AutofillUpstream:disabled"/>
   <int value="-2106960993" label="HarfBuzzPDFSubsetter:disabled"/>
   <int value="-2106763275" label="ArcRtVcpuQuadCore:enabled"/>
@@ -56820,6 +56822,7 @@
   <int value="-2054612904" label="BuiltInModuleInfra:enabled"/>
   <int value="-2053860791" label="XGEOVisibleNetworks:enabled"/>
   <int value="-2053062676" label="EnableNeuralPalmAdaptiveHold:enabled"/>
+  <int value="-2050829390" label="LensRegionSearchStaticPage:enabled"/>
   <int value="-2050039250"
       label="JourneysOnDeviceClusteringContentClustering:enabled"/>
   <int value="-2048927838" label="AutoplayWhitelistSettings:enabled"/>
@@ -56943,6 +56946,7 @@
   <int value="-1991935790" label="ShareCrowLaunchTab:enabled"/>
   <int value="-1990678808" label="SafetyCheckUnusedSitePermissions:disabled"/>
   <int value="-1990614981" label="StoragePressureUI:disabled"/>
+  <int value="-1990583427" label="FeedHeaderStickToTop:disabled"/>
   <int value="-1990238241" label="ChromeOSHWVBREncoding:enabled"/>
   <int value="-1989747818" label="TabStripKeyboardFocus:disabled"/>
   <int value="-1989624484" label="StartSurfaceRefactor:disabled"/>
@@ -61223,6 +61227,7 @@
   <int value="564355877" label="OopRasterizationDDL:disabled"/>
   <int value="564452531" label="SystemEmojiPickerExtension:enabled"/>
   <int value="564522013" label="Av1Decoder:disabled"/>
+  <int value="565254510" label="LensRegionSearchStaticPage:disabled"/>
   <int value="565406673" label="EnableVirtualKeyboardMdUi:enabled"/>
   <int value="567368307" label="enable-experimental-canvas-features"/>
   <int value="570469494" label="LoginDetection:disabled"/>
@@ -95575,6 +95580,7 @@
   <int value="52" label="Printers Authorization Servers"/>
   <int value="53" label="Contact info"/>
   <int value="54" label="Autofill Wallet Usage"/>
+  <int value="55" label="Segmentation"/>
 </enum>
 
 <enum name="SyncModelTypeStoreInitResult">
@@ -103357,6 +103363,27 @@
   <int value="3" label="Transferred WebContents"/>
 </enum>
 
+<enum name="WebFeedChangeReason">
+  <int value="0" label="Unspecified">Unknown change reason</int>
+  <int value="1" label="Web page menu">
+    The user tapped the Follow/Unfollow option from the three dot menu while on
+    a web page.
+  </int>
+  <int value="2" label="Web page accelerator">
+    The user tapped the Follow accelerator while visiting a site.
+  </int>
+  <int value="3" label="Management page">
+    The user tapped to Follow/Unfollow on the Follow Management page.
+  </int>
+  <int value="4" label="In feed recommendation">
+    The user tapped to Follow/Unfollow a recommendation embedded in feed
+    content.
+  </int>
+  <int value="5" label="Back of card unfollow">
+    The user tapped 'Unfollow' on the back of card menu.
+  </int>
+</enum>
+
 <enum name="WebFeedPageInformationRequestReason">
   <int value="0" label="User Requested Follow">
     The user requested to Follow the current web page.
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index beb5ac0..95f1efc3 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1499,6 +1499,9 @@
 
 <histogram name="Apps.AppListPlayStoreAppLaunchedIndex" units="indices"
     expires_after="2021-12-31">
+  <obsolete>
+    Deprecated in M108. Tiled app results are no longer shown.
+  </obsolete>
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <summary>
@@ -1515,10 +1518,14 @@
 
 <histogram name="Apps.AppListPlayStoreSearchAppsDisplayed" units="apss"
     expires_after="2021-12-31">
+  <obsolete>
+    Deprecated in M108. Tiled app results are no longer shown.
+  </obsolete>
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <summary>
-    The number of the play store apps displayed to user for a query.
+    Deprecated in Oct 2022. The number of the play store apps displayed to user
+    as tile items for a query.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 1a0ba11..eb68c155 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1658,6 +1658,9 @@
 
 <histogram name="Arc.PlayStoreSearch.DefaultResultClickLatency" units="ms"
     expires_after="2021-12-31">
+  <obsolete>
+    Deprecated in M108. Tiled app results are no longer shown.
+  </obsolete>
   <owner>jennyz@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 427bda19..596259c 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -1473,6 +1473,19 @@
   </token>
 </histogram>
 
+<histogram name="ContentSuggestions.Feed.WebFeed.NewFollow.ChangeReason"
+    enum="WebFeedChangeReason" expires_after="2023-04-01">
+  <owner>harringtond@chromium.org</owner>
+  <owner>feed@chromium.org</owner>
+  <summary>
+    Change reason for the follow.
+
+    Reported upon successfully following a web feed. Reported as 'true' if the
+    web feed was recommended, even if the user did not see or interact with
+    recommendation UI.
+  </summary>
+</histogram>
+
 <histogram name="ContentSuggestions.Feed.WebFeed.NewFollow.IsRecommended"
     enum="Boolean" expires_after="2023-03-01">
   <owner>harringtond@chromium.org</owner>
@@ -1480,9 +1493,7 @@
   <summary>
     Whether the followed web feed was recommended by the server.
 
-    Reported upon successfully following a web feed. Reported as 'true' if the
-    web feed was recommended, even if the user did not see or interact with
-    recommendation UI.
+    Reported upon successfully following a web feed.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 073c8c66..dea969ba 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -54,6 +54,7 @@
   <variant name=".READING_LIST" summary="READING_LIST"/>
   <variant name=".SEARCH_ENGINE" summary="SEARCH_ENGINE"/>
   <variant name=".SECURITY_EVENT" summary="SECURITY_EVENT"/>
+  <variant name=".SEGMENTATION" summary="SEGMENTATION"/>
   <variant name=".SEND_TAB_TO_SELF" summary="SEND_TAB_TO_SELF"/>
   <variant name=".SESSION" summary="SESSION"/>
   <variant name=".SHARING_MESSAGE" summary="SHARING_MESSAGE"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 7c97b6eb..2950587 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -16542,6 +16542,11 @@
     PageTimelineState UKM events. One PageTimelineState is recorded for each
     browser tab when a slice is collected.
   </summary>
+  <metric name="BatterySaverMode" enum="Boolean">
+    <summary>
+      True if Batter Saver Mode is enabled at the time this event is recorded.
+    </summary>
+  </metric>
   <metric name="ChangedFaviconOrTitleInBackground" enum="Boolean">
     <summary>
       True if this page has been observed to change its favicon or title when in
@@ -16553,6 +16558,43 @@
       The state the tab was in when the slice was recorded.
     </summary>
   </metric>
+  <metric name="HasNotificationPermission" enum="Boolean">
+    <summary>
+      True if this page has been granted the notification permission.
+    </summary>
+  </metric>
+  <metric name="HighEfficiencyMode" enum="Boolean">
+    <summary>
+      True if High Efficiency Mode is enabled at the time this event is
+      recorded.
+    </summary>
+  </metric>
+  <metric name="IsActiveTab" enum="Boolean">
+    <summary>
+      True if this page is the active tab in its tab strip.
+    </summary>
+  </metric>
+  <metric name="IsCapturingMedia" enum="Boolean">
+    <summary>
+      True if this page is capturing media (audio/video/screen).
+    </summary>
+  </metric>
+  <metric name="IsConnectedToDevice" enum="Boolean">
+    <summary>
+      True if this page is connected to a BT or USB device.
+    </summary>
+  </metric>
+  <metric name="IsPlayingAudio" enum="Boolean">
+    <summary>
+      True if this page is playing audio.
+    </summary>
+  </metric>
+  <metric name="ResidentSetSize">
+    <summary>
+      The total resident set size footprint of this page at the moment the
+      sample was recorded, in bytes.
+    </summary>
+  </metric>
   <metric name="SliceId">
     <summary>
       A strictly increasing ID used to order slices in relation to each other.
diff --git a/tools/perf/benchmarks/loading_metrics_category.py b/tools/perf/benchmarks/loading_metrics_category.py
index b507ecf..25d9db7e 100644
--- a/tools/perf/benchmarks/loading_metrics_category.py
+++ b/tools/perf/benchmarks/loading_metrics_category.py
@@ -26,5 +26,6 @@
   # properly compute time-to-interactive.
   cat_filter.AddDisabledByDefault('disabled-by-default-network')
 
-  tbm_options.AddTimelineBasedMetric('loadingMetric')
+  tbm_options.ExtendTimelineBasedMetric(
+      ['loadingMetric', 'coreWebVitalsMetric'])
   return tbm_options
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 3ef368e..dc3fa53 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,15 +6,15 @@
         },
         "win": {
             "hash": "cd36010f4aaa8261c0ead7927e3b5b0c51b23680",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/08c1f851b8a083fbf2e052f42f190db9b8915e0b/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/7bd83a8f9af8604e932cd717fdd56e586c54d3a4/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "3c5d52cc52064a87d37f0e22efbb8d0ea38856ff",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/fabd415c7415ae91f871fc08683cd3bdcc47830e/trace_processor_shell"
+            "hash": "b3d9c24d59f3e90d4cc0351d61bd90f45f8ac025",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/7bd83a8f9af8604e932cd717fdd56e586c54d3a4/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "92318bea34f5c9beec69d2d826a9a92ec9d3cdcd",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "9ec936285839034b556c7e91136aeda7c8a59150",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/08c1f851b8a083fbf2e052f42f190db9b8915e0b/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/7bd83a8f9af8604e932cd717fdd56e586c54d3a4/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/compositor/total_animation_throughput_reporter.cc b/ui/compositor/total_animation_throughput_reporter.cc
index ffd295b..53f0608 100644
--- a/ui/compositor/total_animation_throughput_reporter.cc
+++ b/ui/compositor/total_animation_throughput_reporter.cc
@@ -10,19 +10,6 @@
 
 namespace ui {
 
-TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker::
-    ScopedThroughputReporterBlocker(
-        base::WeakPtr<TotalAnimationThroughputReporter> reporter)
-    : reporter_(std::move(reporter)) {
-  reporter_->scoped_blocker_count_++;
-}
-
-TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker::
-    ~ScopedThroughputReporterBlocker() {
-  if (reporter_)
-    reporter_->scoped_blocker_count_--;
-}
-
 TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
     ui::Compositor* compositor,
     ReportOnceCallback once_callback,
@@ -58,9 +45,6 @@
 
 void TotalAnimationThroughputReporter::OnFirstNonAnimatedFrameStarted(
     ui::Compositor* compositor) {
-  if (IsBlocked())
-    return;
-
   throughput_tracker_->Stop();
   throughput_tracker_.reset();
   // Stop observing if no need to report multiple times.
@@ -80,19 +64,6 @@
     delete this;
 }
 
-base::WeakPtr<ui::TotalAnimationThroughputReporter>
-TotalAnimationThroughputReporter::GetWeakPtr() {
-  return ptr_factory_.GetWeakPtr();
-}
-
-std::unique_ptr<
-    TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>
-TotalAnimationThroughputReporter::NewScopedBlocker() {
-  return std::make_unique<
-      ui::TotalAnimationThroughputReporter::ScopedThroughputReporterBlocker>(
-      ptr_factory_.GetWeakPtr());
-}
-
 TotalAnimationThroughputReporter::TotalAnimationThroughputReporter(
     ui::Compositor* compositor,
     ReportRepeatingCallback repeating_callback,
@@ -123,8 +94,4 @@
     report_repeating_callback_.Run(data);
 }
 
-bool TotalAnimationThroughputReporter::IsBlocked() const {
-  return scoped_blocker_count_;
-}
-
 }  // namespace ui
diff --git a/ui/compositor/total_animation_throughput_reporter.h b/ui/compositor/total_animation_throughput_reporter.h
index 866676e..bddc5e4 100644
--- a/ui/compositor/total_animation_throughput_reporter.h
+++ b/ui/compositor/total_animation_throughput_reporter.h
@@ -14,10 +14,6 @@
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/throughput_tracker.h"
 
-namespace ash {
-class LoginUnlockThroughputRecorderTestBase;
-}
-
 namespace ui {
 
 // Reports cc::FrameSequenceMetrics::ThroughputData between the first animation
@@ -36,31 +32,9 @@
 // report callback is invoked on the next begin frame if there is enough data.
 // Since this observes multiple animations, aborting one of animations will
 // not cancel the tracking, and the data will be reported as normal.
-//
-// The reporter will not fire if ScopedThroughputReporterBlocker is active.
-// This allows to measure throughput from the very first animation (when
-// reporter was created) till the specific expected animation ends even if
-// there were delays between the animations.
 class COMPOSITOR_EXPORT TotalAnimationThroughputReporter
     : public CompositorObserver {
  public:
-  // This allows to temporarily ignore OnFirstNonAnimatedFrameStarted event
-  // until an interesting event happens.
-  class COMPOSITOR_EXPORT ScopedThroughputReporterBlocker {
-   public:
-    explicit ScopedThroughputReporterBlocker(
-        base::WeakPtr<TotalAnimationThroughputReporter> reporter);
-    ScopedThroughputReporterBlocker(const ScopedThroughputReporterBlocker&) =
-        delete;
-    ~ScopedThroughputReporterBlocker();
-
-    ScopedThroughputReporterBlocker& operator=(
-        const ScopedThroughputReporterBlocker&) = delete;
-
-   private:
-    base::WeakPtr<TotalAnimationThroughputReporter> reporter_;
-  };
-
   using ReportOnceCallback = base::OnceCallback<void(
       const cc::FrameSequenceMetrics::CustomReportData& data)>;
   using ReportRepeatingCallback = base::RepeatingCallback<void(
@@ -90,18 +64,9 @@
   void OnFirstNonAnimatedFrameStarted(Compositor* compositor) override;
   void OnCompositingShuttingDown(Compositor* compositor) override;
 
-  base::WeakPtr<ui::TotalAnimationThroughputReporter> GetWeakPtr();
-
   bool IsMeasuringForTesting() const { return bool{throughput_tracker_}; }
 
-  // The returned scope will delay the animation report until the next
-  // |OnFirstNonAnimatedFrameStarted| received after it is destructed. See
-  // |ScopedThroughputReporterBlocker| above.
-  std::unique_ptr<ScopedThroughputReporterBlocker> NewScopedBlocker();
-
  private:
-  friend class ash::LoginUnlockThroughputRecorderTestBase;
-
   TotalAnimationThroughputReporter(Compositor* compositor,
                                    ReportRepeatingCallback repeating_callback,
                                    ReportOnceCallback once_callback,
@@ -109,18 +74,12 @@
 
   void Report(const cc::FrameSequenceMetrics::CustomReportData& data);
 
-  // Returns true if there is an active ScopedThroughputReporterBlocker.
-  bool IsBlocked() const;
-
   raw_ptr<Compositor> compositor_;
   ReportRepeatingCallback report_repeating_callback_;
   ReportOnceCallback report_once_callback_;
   bool should_delete_ = false;
   absl::optional<ThroughputTracker> throughput_tracker_;
 
-  // Number of active ScopedThroughputReporterBlocker objects.
-  int scoped_blocker_count_ = 0;
-
   base::WeakPtrFactory<TotalAnimationThroughputReporter> ptr_factory_{this};
 };
 
diff --git a/ui/compositor/total_animation_throughput_reporter_unittest.cc b/ui/compositor/total_animation_throughput_reporter_unittest.cc
index b4c02dc..7f8d369 100644
--- a/ui/compositor/total_animation_throughput_reporter_unittest.cc
+++ b/ui/compositor/total_animation_throughput_reporter_unittest.cc
@@ -48,58 +48,6 @@
   layer.SetOpacity(opacity);
 }
 
-class TestCompositorMonitor : public ui::CompositorObserver {
- public:
-  explicit TestCompositorMonitor(ui::Compositor* compositor)
-      : compositor_(compositor) {
-    compositor->AddObserver(this);
-  }
-
-  ~TestCompositorMonitor() override { compositor_->RemoveObserver(this); }
-
-  // ui::CompositorObserver
-  void OnFirstAnimationStarted(Compositor* compositor) override {
-    animatins_running_ = true;
-  }
-
-  void OnFirstNonAnimatedFrameStarted(Compositor* compositor) override {
-    DCHECK_EQ(compositor_, compositor);
-    if (animatins_running_) {
-      waiting_for_did_present_compositor_frame_ = true;
-    }
-    animatins_running_ = false;
-  }
-
-  void OnDidPresentCompositorFrame(
-      uint32_t frame_token,
-      const gfx::PresentationFeedback& feedback) override {
-    if (waiting_for_did_present_compositor_frame_) {
-      waiting_for_did_present_compositor_frame_ = false;
-      if (animatins_running_)
-        return;
-
-      if (run_loop_)
-        run_loop_->Quit();
-    }
-  }
-
-  void WaitForAllAnimationsEnd() {
-    if (!animatins_running_ && !waiting_for_did_present_compositor_frame_)
-      return;
-
-    run_loop_ = std::make_unique<base::RunLoop>(
-        base::RunLoop::Type::kNestableTasksAllowed);
-    run_loop_->Run();
-    run_loop_.reset();
-  }
-
- private:
-  const base::raw_ptr<ui::Compositor> compositor_;
-  bool animatins_running_ = false;
-  bool waiting_for_did_present_compositor_frame_ = false;
-  std::unique_ptr<base::RunLoop> run_loop_;
-};
-
 }  // namespace
 
 using TotalAnimationThroughputReporterTest =
@@ -113,21 +61,7 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(compositor(),
                                             checker.repeating_callback());
-  auto scoped_blocker = reporter.NewScopedBlocker();
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
-  Advance(base::Milliseconds(200));
-
-  // No report should happen while scoped_blocker exists.
-  EXPECT_FALSE(checker.reported());
-
-  scoped_blocker.reset();
-  // No animation should be running yet, nothing to report.
-  EXPECT_FALSE(checker.reported());
-  Advance(base::Milliseconds(200));
-  EXPECT_FALSE(checker.reported());
-
-  // Animation of opacity goes to 0.5.
-  SetLayerOpacity(layer, 0.5f, base::Milliseconds(48));
   Advance(base::Milliseconds(32));
   EXPECT_FALSE(checker.reported());
   EXPECT_TRUE(checker.WaitUntilReported());
@@ -192,6 +126,7 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(compositor(),
                                             checker.repeating_callback());
+
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
   {
     LayerAnimator* animator = layer.GetAnimator();
@@ -354,7 +289,6 @@
 
 // Make sure the once reporter is called only once.
 TEST_F(TotalAnimationThroughputReporterTest, OnceReporter) {
-  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -366,7 +300,6 @@
   ThroughputReportChecker checker(this);
   TotalAnimationThroughputReporter reporter(
       compositor(), checker.once_callback(), /*should_delete=*/false);
-  auto scoped_blocker = reporter.NewScopedBlocker();
 
   // Make sure the TotalAnimationThroughputReporter removes itself
   // from compositor as observer.
@@ -374,22 +307,6 @@
 
   // Report data for animation of opacity goes to 1.
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
-  Advance(base::Milliseconds(100));
-
-  // No report should happen while scoped_blocker exists.
-  EXPECT_FALSE(checker.reported());
-
-  // Make sure there are no animations running.
-  compositor_monitor.WaitForAllAnimationsEnd();
-
-  scoped_blocker.reset();
-  // No animation should be running yet, nothing to report.
-  EXPECT_FALSE(checker.reported());
-  Advance(base::Milliseconds(100));
-  EXPECT_FALSE(checker.reported());
-
-  // Animation of opacity goes to 0.5.
-  SetLayerOpacity(layer, 0.7f, base::Milliseconds(48));
   EXPECT_TRUE(checker.WaitUntilReported());
 
   // Report data for animation of opacity goes to 0.5.
@@ -417,7 +334,6 @@
     raw_ptr<bool> deleted_;
   };
 
-  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -430,40 +346,21 @@
   base::RunLoop run_loop;
 
   bool deleted = false;
-  TotalAnimationThroughputReporter* reporter = new DeleteTestReporter(
+  new DeleteTestReporter(
       compositor(),
       base::BindLambdaForTesting(
           [&](const cc::FrameSequenceMetrics::CustomReportData&) {
             run_loop.Quit();
           }),
       &deleted);
-  auto scoped_blocker = reporter->NewScopedBlocker();
 
   // Report data for animation of opacity goes to 1.
   SetLayerOpacity(layer, 1.0f, base::Milliseconds(48));
-  Advance(base::Milliseconds(100));
-
-  // No report should happen while scoped_blocker exists.
-  EXPECT_FALSE(deleted);
-
-  // Make sure there are no animations running.
-  compositor_monitor.WaitForAllAnimationsEnd();
-
-  scoped_blocker.reset();
-  // No animation should be running yet, nothing to report.
-  EXPECT_FALSE(deleted);
-  Advance(base::Milliseconds(100));
-  EXPECT_FALSE(deleted);
-
-  // Animation of opacity goes to 0.5.
-  layer.SetOpacity(0.7f);
-  EXPECT_FALSE(deleted);
-  Advance(base::Milliseconds(100));
+  run_loop.Run();
   EXPECT_TRUE(deleted);
 }
 
 TEST_F(TotalAnimationThroughputReporterTest, ThreadCheck) {
-  TestCompositorMonitor compositor_monitor(compositor());
   Layer layer;
   layer.SetOpacity(0.5f);
   root_layer()->Add(&layer);
@@ -486,26 +383,9 @@
 
   TotalAnimationThroughputReporter reporter(c, std::move(callback),
                                             /*should_delete=*/false);
-  auto scoped_blocker = reporter.NewScopedBlocker();
 
   // Report data for animation of opacity goes to 1.
   layer.SetOpacity(1.0f);
-  Advance(base::Milliseconds(100));
-
-  // No report should happen while scoped_blocker exists.
-  EXPECT_FALSE(checker.reported());
-
-  // Make sure there are no animations running.
-  compositor_monitor.WaitForAllAnimationsEnd();
-
-  scoped_blocker.reset();
-  // No animation should be running yet, nothing to report.
-  EXPECT_FALSE(checker.reported());
-  Advance(base::Milliseconds(100));
-  EXPECT_FALSE(checker.reported());
-
-  // Animation of opacity goes to 0.5.
-  layer.SetOpacity(0.7f);
   EXPECT_TRUE(checker.WaitUntilReported());
 }
 
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 907ad7640..8766c097 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -17,7 +17,6 @@
 #include "ui/base/models/dialog_model_field.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/geometry/insets.h"
-#include "ui/views/accessibility/accessibility_paint_checks.h"
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
@@ -797,12 +796,6 @@
   // TODO(pbos): Support updates to the existing model.
 
   auto textfield = std::make_unique<Textfield>();
-  // TODO(crbug.com/1218186): Remove this, this is in place temporarily to be
-  // able to submit accessibility checks, but this focusable View needs to
-  // add a name so that the screen reader knows what to announce. The
-  // placeholder name may need to be pushed into DialogModel, unless we can tie
-  // this to the label. Maybe SetAssociatedField on Textfield is sufficient?
-  textfield->SetProperty(kSkipAccessibilityPaintChecks, true);
   textfield->SetAccessibleName(
       model_field->accessible_name(GetPassKey()).empty()
           ? model_field->label(GetPassKey())
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 1be7478..8ece700 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -432,9 +432,6 @@
   }
 
   if (new_index.has_value()) {
-    if (menu_selection_at_callback_)
-      menu_selection_at_callback_.Run(new_index.value());
-
     SetSelectedIndex(new_index);
     OnPerformAction();
   }
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index eeb848b..e287da1 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -160,7 +160,6 @@
   "js/cr.m.js",
   "js/cr/ui.js",
   "js/load_time_data.m.js",
-  "js/icon.js",
   "js/util.js",
 ]
 
@@ -185,6 +184,7 @@
                "js/focus_grid.ts",
                "js/focus_row.ts",
                "js/focus_outline_manager.ts",
+               "js/icon.ts",
                "js/keyboard_shortcut_list.ts",
                "js/plural_string_proxy.ts",
                "js/static_types.ts",
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn
index acbc5ae..ccb1561 100644
--- a/ui/webui/resources/js/BUILD.gn
+++ b/ui/webui/resources/js/BUILD.gn
@@ -48,6 +48,7 @@
     "focus_grid.ts",
     "focus_outline_manager.ts",
     "focus_row.ts",
+    "icon.ts",
     "keyboard_shortcut_list.ts",
     "plural_string_proxy.ts",
     "search_highlight_utils.ts",
@@ -78,7 +79,6 @@
     "cr.m.js",
     "cr/event_target.js",
     "cr/ui.js",
-    "icon.js",
     "load_time_data.m.js",
     "load_time_data_deprecated.js",
     "parse_html_subset.js",
@@ -138,7 +138,6 @@
   deps = [
     ":assert",
     ":cr.m",
-    ":icon",
     ":load_time_data.m",
     ":parse_html_subset",
     ":promise_resolver",
@@ -157,10 +156,6 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
-js_library("icon") {
-  deps = [ ":cr.m" ]
-}
-
 js_library("load_time_data.m") {
 }
 
diff --git a/ui/webui/resources/js/icon.js b/ui/webui/resources/js/icon.ts
similarity index 76%
rename from ui/webui/resources/js/icon.js
rename to ui/webui/resources/js/icon.ts
index 5cd55f0..a19ce7b 100644
--- a/ui/webui/resources/js/icon.js
+++ b/ui/webui/resources/js/icon.ts
@@ -5,10 +5,9 @@
 import {isAndroid, isIOS} from './cr.m.js';
 
 /**
- * @return {!Array<number>} The scale factors supported by this platform for
- *     webui resources.
+ * @return The scale factors supported by this platform for webui resources.
  */
-function getSupportedScaleFactors() {
+function getSupportedScaleFactors(): number[] {
   const supportedScaleFactors = [];
   if (!isIOS) {
     // This matches the code in ResourceBundle::InitSharedInstance() that
@@ -33,10 +32,10 @@
 
 /**
  * Generates a CSS url string.
- * @param {string} s The URL to generate the CSS url for.
- * @return {string} The CSS url string.
+ * @param s The URL to generate the CSS url for.
+ * @return The CSS url string.
  */
-export function getUrlForCss(s) {
+export function getUrlForCss(s: string): string {
   // http://www.w3.org/TR/css3-values/#uris
   // Parentheses, commas, whitespace characters, single quotes (') and double
   // quotes (") appearing in a URI must be escaped with a backslash
@@ -46,10 +45,8 @@
 
 /**
  * A URL for the filetype icon for |filePath|. OS and theme dependent.
- * @param {string} filePath
- * @return {string}
  */
-export function getFileIconUrl(filePath) {
+export function getFileIconUrl(filePath: string): string {
   const url = new URL('chrome://fileicon/');
   url.searchParams.set('path', filePath);
   url.searchParams.set('scale', window.devicePixelRatio + 'x');
@@ -62,11 +59,11 @@
  * The scale-factor-specific url is generated by replacing the first instance
  * of 'scalefactor' in |path| with the numeric scale factor.
  *
- * @param {string} path The URL to generate an image set for.
+ * @param path The URL to generate an image set for.
  *     'scalefactor' should be a substring of |path|.
- * @return {string} The CSS -webkit-image-set.
+ * @return The CSS -webkit-image-set.
  */
-function getImageSet(path) {
+function getImageSet(path: string): string {
   const supportedScaleFactors = getSupportedScaleFactors();
 
   const replaceStartIndex = path.indexOf('SCALEFACTOR');
@@ -93,10 +90,10 @@
  * Returns the URL of the image, or an image set of URLs for the provided
  * path.  Resources in chrome://theme have multiple supported scale factors.
  *
- * @param {string} path The path of the image.
- * @return {string} The url, or an image set of URLs.
+ * @param path The path of the image.
+ * @return The url, or an image set of URLs.
  */
-export function getImage(path) {
+export function getImage(path: string): string {
   const chromeThemePath = 'chrome://theme';
   const isChromeThemeUrl =
       (path.slice(0, chromeThemePath.length) === chromeThemePath);
@@ -104,7 +101,7 @@
                             getUrlForCss(path);
 }
 
-function getBaseFaviconUrl() {
+function getBaseFaviconUrl(): URL {
   const faviconUrl = new URL('chrome://favicon2/');
   faviconUrl.searchParams.set('size', '16');
   faviconUrl.searchParams.set('scaleFactor', 'SCALEFACTORx');
@@ -114,10 +111,10 @@
 /**
  * Creates a CSS -webkit-image-set for a favicon.
  *
- * @param {string} url URL of the favicon
- * @return {string} -webkit-image-set for the favicon
+ * @param url URL of the favicon
+ * @return -webkit-image-set for the favicon
  */
-export function getFavicon(url) {
+export function getFavicon(url: string): string {
   const faviconUrl = getBaseFaviconUrl();
   faviconUrl.searchParams.set('iconUrl', url);
   return getImageSet(faviconUrl.toString());
@@ -126,25 +123,26 @@
 /**
  * Creates a CSS -webkit-image-set for a favicon request based on a page URL.
  *
- * @param {string} url URL of the original page
- * @param {boolean} isSyncedUrlForHistoryUi Should be set to true only if the
+ * @param url URL of the original page
+ * @param isSyncedUrlForHistoryUi Should be set to true only if the
  *     caller is an UI aimed at displaying user history, and the requested url
  *     is known to be present in Chrome sync data.
- * @param {string=} remoteIconUrlForUma In case the entry is contained in sync
+ * @param remoteIconUrlForUma In case the entry is contained in sync
  *     data, we can pass the associated icon url.
- * @param {number=} size The favicon size.
- * @param {boolean=} forceLightMode Flag to force the service to show the light
+ * @param size The favicon size.
+ * @param forceLightMode Flag to force the service to show the light
  *     mode version of the default favicon.
  *
- * @return {string} -webkit-image-set for the favicon.
+ * @return -webkit-image-set for the favicon.
  */
 export function getFaviconForPageURL(
-    url, isSyncedUrlForHistoryUi, remoteIconUrlForUma = '', size = 16,
-    forceLightMode = false) {
+    url: string, isSyncedUrlForHistoryUi: boolean,
+    remoteIconUrlForUma: string = '', size: number = 16,
+    forceLightMode: boolean = false): string {
   // Note: URL param keys used below must match those in the description of
   // chrome://favicon2 format in components/favicon_base/favicon_url_parser.h.
   const faviconUrl = getBaseFaviconUrl();
-  faviconUrl.searchParams.set('size', size);
+  faviconUrl.searchParams.set('size', size.toString());
   faviconUrl.searchParams.set('pageUrl', url);
   // TODO(dbeam): use the presence of 'allowGoogleServerFallback' to
   // indicate true, otherwise false.
@@ -154,7 +152,7 @@
     faviconUrl.searchParams.set('iconUrl', remoteIconUrlForUma);
   }
   if (forceLightMode) {
-    faviconUrl.searchParams.set('forceLightMode', true);
+    faviconUrl.searchParams.set('forceLightMode', 'true');
   }
 
   return getImageSet(faviconUrl.toString());