diff --git a/DEPS b/DEPS
index b080e01..bd1380b 100644
--- a/DEPS
+++ b/DEPS
@@ -304,7 +304,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'b0f56d43aa08a7d46707e73f5deb6a615e9b6cf0',
+  'skia_revision': '497dc2e1f01fe5aeaf53b7361dc2b2efff0995c6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -312,7 +312,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '435e557c5f7e425abdc54612e7bcae462b78cf29',
+  'angle_revision': '249b03aca732165c125e8b2c5684035beb03b3e7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -331,7 +331,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:12.20230324.2.1',
+  'fuchsia_version': 'version:12.20230324.3.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.
@@ -431,7 +431,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': 'aff2b43596d4b8429083e40debf71da62afc2861',
+  'dawn_revision': 'deb2ec978575c5ead0ceeeb20b216a2c51c99578',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -790,7 +790,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '36fa9155528e9810390f35ca35ce15464b7f645a',
+    '9840e8a8089325487a28cec9618e1e9fb571eec9',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1230,7 +1230,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8422acf6870290b05896201ba1c4d97e76688a9c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd9717259ee7ecbe8de97b75a264f5edc18224ab2',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1702,7 +1702,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '98e4886b5735e9d96d9d842967fb78bdfdc729fa',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1c8b4fe31582532ffa4967f46d708e971a662c43',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1847,7 +1847,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3fc72f611482f8c7a959d66fbee71a750d27a001',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@ba1817f840562f6ab7ad6f348535e9e384bfd142',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1964,7 +1964,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': Var('chrome_git') + '/chrome/src-internal.git@687418f825955bff7f560556620defab3a2117bd',
+    'url': Var('chrome_git') + '/chrome/src-internal.git@9d7fada06de3ecf0679edc51cfeb2dc9df551576',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java
index 9426c50..dd15bf76 100644
--- a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java
+++ b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java
@@ -62,6 +62,7 @@
 import androidx.webkit.WebViewCompat;
 import androidx.webkit.WebViewFeature;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.BuildInfo;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
@@ -328,6 +329,7 @@
             }
             return false;
         });
+        ApiCompatibilityUtils.clearHandwritingBoundsOffsetBottom(mUrlBar);
         findViewById(R.id.btn_load_url).setOnClickListener((view) -> loadUrlFromUrlBar(view));
 
         enableStrictMode();
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 71f164d..d9028e30 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2889,7 +2889,6 @@
     "assistant/model/assistant_query_history_unittest.cc",
     "assistant/ui/assistant_web_container_view_unittest.cc",
     "assistant/ui/base/assistant_button_unittest.cc",
-    "assistant/ui/colors/assistant_colors_util_unittest.cc",
     "assistant/ui/main_stage/assistant_onboarding_suggestion_view_unittest.cc",
     "assistant/ui/main_stage/assistant_onboarding_view_unittest.cc",
     "assistant/ui/main_stage/assistant_opt_in_view_unittest.cc",
@@ -3476,7 +3475,6 @@
     "//ash/assistant/model",
     "//ash/assistant/ui",
     "//ash/assistant/ui:constants",
-    "//ash/assistant/ui/colors:assistant_colors_util",
     "//ash/assistant/ui/colors:assistant_colors_views",
     "//ash/assistant/ui/test_support",
     "//ash/assistant/util",
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index e36fdcb..0fd29d9 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -163,7 +163,6 @@
     "//ash/assistant/model",
     "//ash/assistant/ui",
     "//ash/assistant/ui:constants",
-    "//ash/assistant/ui/colors:assistant_colors_util",
     "//ash/assistant/ui/colors:assistant_colors_views",
     "//ash/assistant/util",
     "//ash/keyboard/ui",
diff --git a/ash/app_list/views/app_list_view_pixeltest.cc b/ash/app_list/views/app_list_view_pixeltest.cc
index af9b0aa..bc3474b 100644
--- a/ash/app_list/views/app_list_view_pixeltest.cc
+++ b/ash/app_list/views/app_list_view_pixeltest.cc
@@ -17,6 +17,7 @@
 #include "ash/test/pixel/ash_pixel_differ.h"
 #include "ash/test/pixel/ash_pixel_test_init_params.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ui/events/types/event_type.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/textfield/textfield_test_api.h"
 
@@ -259,4 +260,13 @@
       /*revision_number=*/0, GetAppListTestHelper()->GetAppsContainerView()));
 }
 
+TEST_P(AppListViewTabletPixelTest, SearchBoxViewActive) {
+  raw_ptr<SearchBoxView> search_box_view =
+      GetAppListTestHelper()->GetSearchBoxView();
+  search_box_view->SetSearchBoxActive(true, ui::EventType::ET_UNKNOWN);
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "search_box_view_active", /*revision_number=*/0, search_box_view));
+}
+
 }  // namespace ash
diff --git a/ash/assistant/assistant_controller_impl_unittest.cc b/ash/assistant/assistant_controller_impl_unittest.cc
index 7cc9d81..ff0bb1a 100644
--- a/ash/assistant/assistant_controller_impl_unittest.cc
+++ b/ash/assistant/assistant_controller_impl_unittest.cc
@@ -21,7 +21,6 @@
 #include "base/scoped_observation.h"
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace ash {
@@ -257,26 +256,7 @@
   ui_model()->RemoveObserver(&ui_model_observer_mock);
 }
 
-// Dark mode is set to true if the DarkLightMode flag is off. This is determined
-// in DarkLightModeControllerImpl::IsDarkModeEnabled().
-TEST_F(AssistantControllerImplTestForStartUp,
-       ColorModeIsSetWhenAssistantIsReadyFlagOff) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      /*enabled_features=*/{}, /*disabled_features=*/{
-          chromeos::features::kDarkLightMode, features::kNotificationsRefresh});
-  SetUpActiveUser();
-
-  ASSERT_TRUE(assistant_service()->dark_mode_enabled().has_value());
-  EXPECT_TRUE(assistant_service()->dark_mode_enabled().value());
-}
-
 TEST_F(AssistantControllerImplTestForStartUp, ColorModeIsUpdated) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(chromeos::features::kDarkLightMode);
-
-  ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
-
   auto* active_user_pref_service =
       Shell::Get()->session_controller()->GetPrimaryUserPrefService();
   ASSERT_TRUE(active_user_pref_service);
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn
index 1fc5019b..7c43df3d 100644
--- a/ash/assistant/ui/BUILD.gn
+++ b/ash/assistant/ui/BUILD.gn
@@ -88,7 +88,6 @@
   deps = [
     "//ash/assistant/model",
     "//ash/assistant/ui:constants",
-    "//ash/assistant/ui/colors:assistant_colors_util",
     "//ash/assistant/ui/colors:assistant_colors_views",
     "//ash/assistant/util",
     "//ash/keyboard/ui",
diff --git a/ash/assistant/ui/colors/BUILD.gn b/ash/assistant/ui/colors/BUILD.gn
index f8a8ffbf6..26af737c 100644
--- a/ash/assistant/ui/colors/BUILD.gn
+++ b/ash/assistant/ui/colors/BUILD.gn
@@ -15,17 +15,3 @@
 
   cpp_namespace = "assistant_colors"
 }
-
-source_set("assistant_colors_util") {
-  sources = [
-    "assistant_colors_util.cc",
-    "assistant_colors_util.h",
-  ]
-  deps = [
-    ":assistant_colors_views",
-    "//ash/constants",
-    "//ash/public/cpp",
-    "//base",
-    "//skia",
-  ]
-}
diff --git a/ash/assistant/ui/colors/assistant_colors_util.cc b/ash/assistant/ui/colors/assistant_colors_util.cc
deleted file mode 100644
index a622248..0000000
--- a/ash/assistant/ui/colors/assistant_colors_util.cc
+++ /dev/null
@@ -1,19 +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.
-
-#include "ash/assistant/ui/colors/assistant_colors_util.h"
-
-#include "ash/assistant/ui/colors/assistant_colors.h"
-#include "ash/public/cpp/style/dark_light_mode_controller.h"
-
-namespace ash {
-namespace assistant {
-
-SkColor ResolveAssistantColor(assistant_colors::ColorName color_name) {
-  return assistant_colors::ResolveColor(
-      color_name, DarkLightModeController::Get()->IsDarkModeEnabled());
-}
-
-}  // namespace assistant
-}  // namespace ash
diff --git a/ash/assistant/ui/colors/assistant_colors_util.h b/ash/assistant/ui/colors/assistant_colors_util.h
deleted file mode 100644
index 270157a..0000000
--- a/ash/assistant/ui/colors/assistant_colors_util.h
+++ /dev/null
@@ -1,21 +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.
-
-#ifndef ASH_ASSISTANT_UI_COLORS_ASSISTANT_COLORS_UTIL_H_
-#define ASH_ASSISTANT_UI_COLORS_ASSISTANT_COLORS_UTIL_H_
-
-#include "ash/assistant/ui/colors/assistant_colors.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace ash {
-namespace assistant {
-
-// This redirects a request to assistant_colors::ResolveColor. If kDarkLightMode
-// flag is off, this resolve the color from a map defined in the cc file.
-SkColor ResolveAssistantColor(assistant_colors::ColorName color_name);
-
-}  // namespace assistant
-}  // namespace ash
-
-#endif  // ASH_ASSISTANT_UI_COLORS_ASSISTANT_COLORS_UTIL_H_
diff --git a/ash/assistant/ui/colors/assistant_colors_util_unittest.cc b/ash/assistant/ui/colors/assistant_colors_util_unittest.cc
deleted file mode 100644
index 0346756..0000000
--- a/ash/assistant/ui/colors/assistant_colors_util_unittest.cc
+++ /dev/null
@@ -1,84 +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.
-
-#include "ash/assistant/ui/colors/assistant_colors_util.h"
-
-#include "ash/assistant/ui/colors/assistant_colors.h"
-#include "ash/constants/ash_features.h"
-#include "ash/constants/ash_pref_names.h"
-#include "ash/session/session_controller_impl.h"
-#include "ash/shell.h"
-#include "ash/style/dark_light_mode_controller_impl.h"
-#include "ash/test/ash_test_base.h"
-#include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace ash {
-namespace assistant {
-
-using AssistantColorsUtilUnittest = AshTestBase;
-
-TEST_F(AssistantColorsUtilUnittest, AssistantColor) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      chromeos::features::kDarkLightMode);
-  auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
-  dark_light_mode_controller->OnActiveUserPrefServiceChanged(
-      Shell::Get()->session_controller()->GetActivePrefService());
-  const bool initial_dark_mode_status =
-      dark_light_mode_controller->IsDarkModeEnabled();
-
-  EXPECT_EQ(
-      ResolveAssistantColor(assistant_colors::ColorName::kBgAssistantPlate),
-      assistant_colors::ResolveColor(
-          assistant_colors::ColorName::kBgAssistantPlate,
-          /*is_dark_mode=*/initial_dark_mode_status,
-          /*use_debug_colors=*/false));
-
-  // Switch the color mode.
-  dark_light_mode_controller->ToggleColorMode();
-  ASSERT_NE(initial_dark_mode_status,
-            dark_light_mode_controller->IsDarkModeEnabled());
-
-  EXPECT_EQ(
-      ResolveAssistantColor(assistant_colors::ColorName::kBgAssistantPlate),
-      assistant_colors::ResolveColor(
-          assistant_colors::ColorName::kBgAssistantPlate,
-          /*is_dark_mode=*/!initial_dark_mode_status,
-          /*use_debug_colors=*/false));
-}
-
-TEST_F(AssistantColorsUtilUnittest, AssistantColorFlagOff) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      /*enabled_features=*/{}, /*disabled_features=*/{
-          chromeos::features::kDarkLightMode, features::kNotificationsRefresh});
-
-  // If DarkLightMode is off, the dark mode is on by default.
-  EXPECT_EQ(
-      ResolveAssistantColor(assistant_colors::ColorName::kBgAssistantPlate),
-      assistant_colors::ResolveColor(
-          assistant_colors::ColorName::kBgAssistantPlate,
-          /*is_dark_mode=*/true,
-          /*use_debug_colors=*/false));
-}
-
-// ResolveAssistantColor falls back to assistant_colors::ResolveColor with dark
-// mode off if the color is not defined in the cc file map and the flag is off.
-TEST_F(AssistantColorsUtilUnittest, AssistantColorFlagOffFallback) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      /*enabled_features=*/{}, /*disabled_features=*/{
-          chromeos::features::kDarkLightMode, features::kNotificationsRefresh});
-
-  // If DarkLightMode is off, the dark mode is on by default.
-  EXPECT_EQ(ResolveAssistantColor(assistant_colors::ColorName::kGoogleBlue100),
-            assistant_colors::ResolveColor(
-                assistant_colors::ColorName::kGoogleBlue100,
-                /*is_dark_mode=*/true, /*use_debug_colors=*/false));
-}
-
-}  // namespace assistant
-}  // namespace ash
diff --git a/ash/assistant/ui/main_stage/assistant_query_view.cc b/ash/assistant/ui/main_stage/assistant_query_view.cc
index 4fd1eed..7d50249 100644
--- a/ash/assistant/ui/main_stage/assistant_query_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_query_view.cc
@@ -11,7 +11,6 @@
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_ids.h"
 #include "ash/assistant/ui/colors/assistant_colors.h"
-#include "ash/assistant/ui/colors/assistant_colors_util.h"
 #include "ash/constants/ash_features.h"
 #include "ash/style/ash_color_id.h"
 #include "base/strings/escape.h"
diff --git a/ash/assistant/ui/main_stage/assistant_zero_state_view.cc b/ash/assistant/ui/main_stage/assistant_zero_state_view.cc
index 7c5dd82..c405f27 100644
--- a/ash/assistant/ui/main_stage/assistant_zero_state_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_zero_state_view.cc
@@ -11,8 +11,6 @@
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/ui/assistant_view_ids.h"
-#include "ash/assistant/ui/colors/assistant_colors.h"
-#include "ash/assistant/ui/colors/assistant_colors_util.h"
 #include "ash/assistant/ui/main_stage/assistant_onboarding_view.h"
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
@@ -95,16 +93,6 @@
   PreferredSizeChanged();
 }
 
-void AssistantZeroStateView::OnThemeChanged() {
-  views::View::OnThemeChanged();
-
-  greeting_label_->SetBackgroundColor(ash::assistant::ResolveAssistantColor(
-      assistant_colors::ColorName::kBgAssistantPlate));
-
-  greeting_label_->SetEnabledColor(
-      GetColorProvider()->GetColor(kColorAshAssistantTextColorPrimary));
-}
-
 void AssistantZeroStateView::OnAssistantControllerDestroying() {
   AssistantUiController::Get()->GetModel()->RemoveObserver(this);
   DCHECK(assistant_controller_observation_.IsObservingSource(
@@ -148,6 +136,8 @@
   greeting_label_->SetMultiLine(true);
   greeting_label_->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_PROMPT_DEFAULT));
+  greeting_label_->SetBackgroundColorId(kColorAshAssistantBgPlate);
+  greeting_label_->SetEnabledColorId(kColorAshAssistantTextColorPrimary);
 
   // Spacer.
   spacer_ = AddChildView(std::make_unique<views::View>());
diff --git a/ash/assistant/ui/main_stage/assistant_zero_state_view.h b/ash/assistant/ui/main_stage/assistant_zero_state_view.h
index 9e5454bb..352eda77 100644
--- a/ash/assistant/ui/main_stage/assistant_zero_state_view.h
+++ b/ash/assistant/ui/main_stage/assistant_zero_state_view.h
@@ -37,7 +37,6 @@
   const char* GetClassName() const override;
   gfx::Size CalculatePreferredSize() const override;
   void ChildPreferredSizeChanged(views::View* child) override;
-  void OnThemeChanged() override;
 
   // AssistantController:
   void OnAssistantControllerDestroying() override;
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index 03cefc8..fb5d4c2 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -673,14 +673,14 @@
                   : nullptr;
   }
 
-  void ShowMultitaskMenu() {
+  void ShowMultitaskMenu(MultitaskMenuEntryType entry_type =
+                             MultitaskMenuEntryType::kFrameSizeButtonHover) {
     DCHECK(size_button());
 
     views::NamedWidgetShownWaiter waiter(
         views::test::AnyWidgetTestPasskey{},
         std::string(kMultitaskMenuBubbleWidgetName));
-    static_cast<FrameSizeButton*>(size_button())
-        ->ShowMultitaskMenu(MultitaskMenuEntryType::kFrameSizeButtonHover);
+    static_cast<FrameSizeButton*>(size_button())->ShowMultitaskMenu(entry_type);
     waiter.WaitIfNeededAndGet();
   }
 
@@ -752,7 +752,7 @@
       .SetDisplayRotation(display::Display::ROTATE_180,
                           display::Display::RotationSource::ACTIVE);
 
-  ShowMultitaskMenu();
+  ShowMultitaskMenu(MultitaskMenuEntryType::kAccel);
 
   // Click on the left side of the half button. It should be in secondary
   // snapped state, because in this orientation secondary snapped is actually
@@ -941,4 +941,40 @@
   ASSERT_FALSE(GetMultitaskMenu());
 }
 
+// Tests that moving the mouse outside the menu will close the menu, if opened
+// via hovering on the frame size button.
+TEST_F(MultitaskMenuTest, MoveMouseOutsideMenu) {
+  chromeos::MultitaskMenuView::SetSkipMouseOutDelayFoTesting(true);
+
+  // Simulate opening the menu by moving the mouse to the frame size button and
+  // opening the menu.
+  ui::test::EventGenerator* event_generator = GetEventGenerator();
+  event_generator->MoveMouseTo(
+      size_button()->GetBoundsInScreen().CenterPoint());
+  ShowMultitaskMenu();
+
+  MultitaskMenu* multitask_menu = GetMultitaskMenu();
+  ASSERT_TRUE(multitask_menu);
+  event_generator->MoveMouseTo(
+      multitask_menu->GetBoundsInScreen().CenterPoint());
+  // Widget is closed with a post task.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(GetMultitaskMenu());
+
+  event_generator->MoveMouseTo(gfx::Point(1, 1));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(GetMultitaskMenu());
+
+  // Open the menu using the accelerator.
+  event_generator->MoveMouseTo(
+      size_button()->GetBoundsInScreen().CenterPoint());
+  ShowMultitaskMenu(MultitaskMenuEntryType::kAccel);
+
+  // Test that the menu remains open if we move outside when using the
+  // accelerator.
+  event_generator->MoveMouseTo(gfx::Point(1, 1));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(GetMultitaskMenu());
+}
+
 }  // namespace ash
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index 8cbd71f..8aa5bcfe 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -189,14 +189,6 @@
   return security_token_request_controller_.request_canceled();
 }
 
-void LoginScreenController::HardlockPod(const AccountId& account_id) {
-  GetModel()->NotifyFocusPod(account_id);
-  if (!client_) {
-    return;
-  }
-  client_->HardlockPod(account_id);
-}
-
 void LoginScreenController::OnFocusPod(const AccountId& account_id) {
   GetModel()->NotifyFocusPod(account_id);
   if (!client_) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index eb64fa1..5d3a832 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -77,7 +77,6 @@
       base::Time validation_time,
       const std::string& code);
   bool GetSecurityTokenPinRequestCanceled() const;
-  void HardlockPod(const AccountId& account_id);
   void OnFocusPod(const AccountId& account_id);
   void OnNoPodFocused();
   void LoadWallpaper(const AccountId& account_id);
diff --git a/ash/login/login_screen_controller_unittest.cc b/ash/login/login_screen_controller_unittest.cc
index b42efee4..246b2ebb 100644
--- a/ash/login/login_screen_controller_unittest.cc
+++ b/ash/login/login_screen_controller_unittest.cc
@@ -111,11 +111,6 @@
   EXPECT_CALL(*client, AuthenticateUserWithEasyUnlock(id));
   controller->AuthenticateUserWithEasyUnlock(id);
   base::RunLoop().RunUntilIdle();
-
-  // Verify HardlockPod mojo call is run with the same account id.
-  EXPECT_CALL(*client, HardlockPod(id));
-  controller->HardlockPod(id);
-  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(LoginScreenControllerTest, RequestUserPodFocus) {
diff --git a/ash/login/mock_login_screen_client.h b/ash/login/mock_login_screen_client.h
index 59e73a9..f1f402a 100644
--- a/ash/login/mock_login_screen_client.h
+++ b/ash/login/mock_login_screen_client.h
@@ -75,7 +75,6 @@
               AuthenticateUserWithEasyUnlock,
               (const AccountId& account_id),
               (override));
-  MOCK_METHOD(void, HardlockPod, (const AccountId& account_id), (override));
   MOCK_METHOD(void, OnFocusPod, (const AccountId& account_id), (override));
   MOCK_METHOD(void, OnNoPodFocused, (), (override));
   MOCK_METHOD(void, LoadWallpaper, (const AccountId& account_id), (override));
diff --git a/ash/public/cpp/login_screen_client.h b/ash/public/cpp/login_screen_client.h
index 93063af..a90d27e 100644
--- a/ash/public/cpp/login_screen_client.h
+++ b/ash/public/cpp/login_screen_client.h
@@ -71,10 +71,6 @@
       const std::string& access_code,
       base::Time validation_time) = 0;
 
-  // Request to hard lock the user pod.
-  // |account_id|:    The account id of the user in the user pod.
-  virtual void HardlockPod(const AccountId& account_id) = 0;
-
   // Focus user pod of user with |account_id|.
   virtual void OnFocusPod(const AccountId& account_id) = 0;
 
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 33935962..56d4f967 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -116,8 +116,9 @@
 namespace {
 
 bool IsInShelfContainer(aura::Window* container) {
-  if (!container)
+  if (!container) {
     return false;
+  }
   int id = container->GetId();
   if (id == ash::kShellWindowId_ShelfContainer ||
       id == ash::kShellWindowId_ShelfBubbleContainer) {
@@ -144,8 +145,9 @@
   // The root window is put at the end so that we compare windows at
   // the same depth.
   while (!blocking_path.empty()) {
-    if (target_path.empty())
+    if (target_path.empty()) {
       return false;
+    }
 
     aura::Window* target = target_path.back();
     target_path.pop_back();
@@ -153,13 +155,15 @@
     blocking_path.pop_back();
 
     // Still on the same path, continue.
-    if (target == blocking)
+    if (target == blocking) {
       continue;
+    }
 
     // This can happen only if unparented window is passed because
     // first element must be the same root.
-    if (!target->parent() || !blocking->parent())
+    if (!target->parent() || !blocking->parent()) {
       return false;
+    }
 
     aura::Window* common_parent = target->parent();
     DCHECK_EQ(common_parent, blocking->parent());
@@ -220,11 +224,13 @@
   new_parent->AddChild(window);
 
   // Docked windows have bounds handled by the layout manager in AddChild().
-  if (update_bounds)
+  if (update_bounds) {
     window->SetBounds(local_bounds);
+  }
 
-  if (has_restore_bounds)
+  if (has_restore_bounds) {
     state->SetRestoreBoundsInParent(restore_bounds);
+  }
 }
 
 // Reparents the appropriate set of windows from |src| to |dst|.
@@ -248,15 +254,17 @@
   // Desk container ids are different depends on whether Bento feature is
   // enabled or not.
   std::vector<int> container_ids = desks_util::GetDesksContainersIds();
-  for (const int id : kContainerIdsToMove)
+  for (const int id : kContainerIdsToMove) {
     container_ids.emplace_back(id);
+  }
 
   // Check the display mode as this is also necessary when trasitioning between
   // mirror and unified mode.
   if (Shell::Get()->display_manager()->current_default_multi_display_mode() ==
       display::DisplayManager::UNIFIED) {
-    for (const int id : kExtraContainerIdsToMoveInUnifiedMode)
+    for (const int id : kExtraContainerIdsToMoveInUnifiedMode) {
       container_ids.emplace_back(id);
+    }
   }
 
   const std::vector<aura::Window*> mru_list =
@@ -276,8 +284,9 @@
         ++iter;
       }
       // If the entire window list is modal background windows then stop.
-      if (iter == src_container_children.rend())
+      if (iter == src_container_children.rend()) {
         break;
+      }
 
       // |iter| is invalidated after ReparentWindow. Cache it to use afterwards.
       aura::Window* const window = *iter;
@@ -295,8 +304,9 @@
             continue;
           }
 
-          if (!found_window || window_iter->parent() != dst_container)
+          if (!found_window || window_iter->parent() != dst_container) {
             continue;
+          }
 
           // Once |window| is found, the next item in |mru_list| with the same
           // parent (container) is the stacking target.
@@ -309,10 +319,11 @@
       // means the children of that container wouldn't be in the MRU list or if
       // |window| was the last item in the MRU list with parent id |id|. In
       // this case stack |window| at the bottom.
-      if (stacking_target)
+      if (stacking_target) {
         dst_container->StackChildAbove(window, stacking_target);
-      else
+      } else {
         dst_container->StackChildAtBottom(window);
+      }
     }
   }
 }
@@ -324,8 +335,9 @@
 // Clears the workspace controllers from the properties of all virtual desks
 // containers in |root|.
 void ClearWorkspaceControllers(aura::Window* root) {
-  for (auto* desk_container : desks_util::GetDesksContainers(root))
+  for (auto* desk_container : desks_util::GetDesksContainers(root)) {
     SetWorkspaceController(desk_container, nullptr);
+  }
 }
 
 class RootWindowTargeter : public aura::WindowTargeter {
@@ -390,8 +402,9 @@
       return true;
     }
     // For other cases, reset the state
-    if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
+    if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
       last_mouse_event_type_ = ui::ET_UNKNOWN;
+    }
     return false;
   }
 
@@ -475,8 +488,9 @@
     for (auto* child : container_->children()) {
       const int resize_behavior =
           child->GetProperty(aura::client::kResizeBehaviorKey);
-      if (resize_behavior & aura::client::kResizeBehaviorCanMaximize)
+      if (resize_behavior & aura::client::kResizeBehaviorCanMaximize) {
         SetChildBoundsDirect(child, fullscreen);
+      }
     }
   }
 
@@ -583,8 +597,9 @@
 }
 
 bool RootWindowController::CanWindowReceiveEvents(aura::Window* window) {
-  if (GetRootWindow() != window->GetRootWindow())
+  if (GetRootWindow() != window->GetRootWindow()) {
     return false;
+  }
 
   aura::Window* blocking_container = nullptr;
   aura::Window* modal_container = nullptr;
@@ -594,26 +609,31 @@
   modal_layout_manager = static_cast<SystemModalContainerLayoutManager*>(
       modal_container->layout_manager());
 
-  if (modal_layout_manager->has_window_dimmer())
+  if (modal_layout_manager->has_window_dimmer()) {
     blocking_container = modal_container;
-  else
+  } else {
     modal_container = nullptr;  // Don't check modal dialogs.
+  }
 
   // In normal session.
-  if (!blocking_container)
+  if (!blocking_container) {
     return true;
+  }
 
-  if (!IsWindowAboveContainer(window, blocking_container))
+  if (!IsWindowAboveContainer(window, blocking_container)) {
     return false;
+  }
 
   if (modal_container) {
     // If the window is in the target modal container, only allow the top most
     // one.
-    if (modal_container->Contains(window))
+    if (modal_container->Contains(window)) {
       return modal_layout_manager->IsPartOfActiveModalWindow(window);
+    }
     // Don't allow shelf to process events if there is a visible modal dialog.
-    if (IsInShelfContainer(window->parent()))
+    if (IsInShelfContainer(window->parent())) {
       return false;
+    }
   }
   return true;
 }
@@ -660,8 +680,9 @@
   // Forget with the display ID so that display lookup
   // ends up with invalid display.
   GetRootWindowSettings(root_window)->display_id = display::kInvalidDisplayId;
-  if (ash_host_)
+  if (ash_host_) {
     ash_host_->PrepareForShutdown();
+  }
 
   system_wallpaper_.reset();
   security_curtain_widget_controller_.reset();
@@ -678,8 +699,9 @@
 void RootWindowController::CloseChildWindows() {
   // Child windows can be closed by secondary monitor disconnection, Shell
   // shutdown, or both. Avoid running the related cleanup code twice.
-  if (did_close_child_windows_)
+  if (did_close_child_windows_) {
     return;
+  }
   did_close_child_windows_ = true;
 
   aura::Window* root = GetRootWindow();
@@ -691,8 +713,9 @@
   Shell::Get()->keyboard_controller()->OnRootWindowClosing(root);
 
   OverviewController* overview_controller = Shell::Get()->overview_controller();
-  if (overview_controller && overview_controller->InOverviewSession())
+  if (overview_controller && overview_controller->InOverviewSession()) {
     overview_controller->overview_session()->OnRootWindowClosing(root);
+  }
 
   shelf_->ShutdownShelfWidget();
 
@@ -707,12 +730,14 @@
     aura::Window* non_toplevel_window = non_toplevel_windows.Pop();
     aura::WindowTracker toplevel_windows;
     for (aura::Window* child : non_toplevel_window->children()) {
-      if (!ShouldDestroyWindowInCloseChildWindows(child))
+      if (!ShouldDestroyWindowInCloseChildWindows(child)) {
         continue;
-      if (child->delegate())
+      }
+      if (child->delegate()) {
         toplevel_windows.Add(child);
-      else
+      } else {
         non_toplevel_windows.Add(child);
+      }
     }
     while (!toplevel_windows.windows().empty()) {
       aura::Window* toplevel_window = toplevel_windows.windows().back();
@@ -736,10 +761,11 @@
   // And then remove the containers.
   while (!root->children().empty()) {
     aura::Window* child = root->children()[0];
-    if (ShouldDestroyWindowInCloseChildWindows(child))
+    if (ShouldDestroyWindowInCloseChildWindows(child)) {
       delete child;
-    else
+    } else {
       root->RemoveChild(child);
+    }
   }
 
   // Removing the containers destroys ShelfLayoutManager. ShelfWidget outlives
@@ -752,8 +778,9 @@
 void RootWindowController::MoveWindowsTo(aura::Window* dst) {
   // Suspend unnecessary updates of the shelf visibility indefinitely since it
   // is going away.
-  if (GetShelfLayoutManager())
+  if (GetShelfLayoutManager()) {
     GetShelfLayoutManager()->SuspendVisibilityUpdateForShutdown();
+  }
 
   // Clear the workspace controller to avoid a lot of unnecessary operations
   // when window are removed.
@@ -768,12 +795,14 @@
 void RootWindowController::InitTouchHuds() {
   // Enable touch debugging features when each display is initialized.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kAshTouchHud))
+  if (command_line->HasSwitch(switches::kAshTouchHud)) {
     set_touch_hud_debug(new TouchHudDebug(GetRootWindow()));
+  }
 
   // TouchHudProjection manages its own lifetime.
-  if (command_line->HasSwitch(switches::kShowTaps))
+  if (command_line->HasSwitch(switches::kShowTaps)) {
     touch_hud_projection_ = new TouchHudProjection(GetRootWindow());
+  }
 }
 
 aura::Window* RootWindowController::GetWindowForFullscreenMode() {
@@ -787,8 +816,9 @@
 
 void RootWindowController::SetTouchAccessibilityAnchorPoint(
     const gfx::Point& anchor_point) {
-  if (touch_exploration_manager_)
+  if (touch_exploration_manager_) {
     touch_exploration_manager_->SetTouchAccessibilityAnchorPoint(anchor_point);
+  }
 }
 
 void RootWindowController::ShowContextMenu(const gfx::Point& location_in_screen,
@@ -864,13 +894,15 @@
 }
 
 void RootWindowController::HideContextMenu() {
-  if (root_window_menu_model_adapter_)
+  if (root_window_menu_model_adapter_) {
     root_window_menu_model_adapter_->Cancel();
+  }
 }
 
 void RootWindowController::HideContextMenuNoAnimation() {
-  if (!IsContextMenuShown())
+  if (!IsContextMenuShown()) {
     return;
+  }
 
   views::Widget* submenu_widget =
       root_window_menu_model_adapter_->GetSubmenuWidget();
@@ -887,8 +919,9 @@
 void RootWindowController::UpdateAfterLoginStatusChange(LoginStatus status) {
   StatusAreaWidget* status_area_widget =
       shelf_->shelf_widget()->status_area_widget();
-  if (status_area_widget)
+  if (status_area_widget) {
     status_area_widget->UpdateAfterLoginStatusChange(status);
+  }
 }
 
 void RootWindowController::CreateAmbientWidget() {
@@ -903,10 +936,11 @@
 
 void RootWindowController::CloseAmbientWidget(bool immediately) {
   if (ambient_widget_) {
-    if (immediately)
+    if (immediately) {
       ambient_widget_->CloseNow();
-    else
+    } else {
       ambient_widget_->CloseWithReason(views::Widget::ClosedReason::kLostFocus);
+    }
   }
 
   ambient_widget_.reset();
@@ -949,8 +983,9 @@
   DCHECK(ash_host_);
   DCHECK(window_tree_host_);
 
-  if (!root_window_controllers_)
+  if (!root_window_controllers_) {
     root_window_controllers_ = new std::vector<RootWindowController*>;
+  }
   root_window_controllers_->push_back(this);
 
   aura::Window* root_window = GetRootWindow();
@@ -1172,8 +1207,9 @@
     window_util::SetChildrenUseExtendedHitRegionForWindow(container);
 
     // Hide the non-active containers.
-    if (id != desks_util::GetActiveDeskContainerId())
+    if (id != desks_util::GetActiveDeskContainerId()) {
       container->Hide();
+    }
   }
 
   aura::Window* always_on_top_container =
@@ -1345,8 +1381,9 @@
   window->SetId(window_id);
   window->SetName(name);
   parent->AddChild(window);
-  if (window_id != kShellWindowId_UnparentedContainer)
+  if (window_id != kShellWindowId_UnparentedContainer) {
     window->Show();
+  }
   root_window_layout_manager_->AddContainer(window);
   return window;
 }
@@ -1361,8 +1398,9 @@
       root_window_type == RootWindowType::PRIMARY &&
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kFirstExecAfterBoot);
-  if (is_boot_splash_screen)
+  if (is_boot_splash_screen) {
     color = kChromeOsBootColor;
+  }
   system_wallpaper_ =
       std::make_unique<SystemWallpaperController>(GetRootWindow(), color);
 }
diff --git a/ash/rounded_display/rounded_display_frame_factory.cc b/ash/rounded_display/rounded_display_frame_factory.cc
index 56498019..bd32442 100644
--- a/ash/rounded_display/rounded_display_frame_factory.cc
+++ b/ash/rounded_display/rounded_display_frame_factory.cc
@@ -4,12 +4,15 @@
 
 #include "ash/rounded_display/rounded_display_frame_factory.h"
 
+#include <algorithm>
+#include <array>
 #include <memory>
 #include <vector>
 
 #include "ash/frame_sink/ui_resource.h"
 #include "ash/frame_sink/ui_resource_manager.h"
 #include "ash/rounded_display/rounded_display_gutter.h"
+#include "base/check.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "components/viz/common/quads/compositor_frame.h"
@@ -30,6 +33,7 @@
 #include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/transform.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -37,6 +41,8 @@
 namespace ash {
 namespace {
 
+using RoundedCorner = RoundedDisplayGutter::RoundedCorner;
+
 constexpr viz::ResourceFormat kResourceFormat =
     SK_B32_SHIFT ? viz::RGBA_8888 : viz::BGRA_8888;
 
@@ -53,6 +59,46 @@
   return root_rotation_transform;
 }
 
+viz::TextureDrawQuad::RoundedDisplayMasksInfo MapToRoundedDisplayMasksInfo(
+    const std::vector<RoundedCorner>& corners) {
+  DCHECK(corners.size() <= 2) << "Currently, viz can only handle textures that "
+                                 "have up to 2 corner masks drawn into them";
+
+  if (corners.size() == 1) {
+    return viz::TextureDrawQuad::RoundedDisplayMasksInfo::
+        CreateRoundedDisplayMasksInfo(corners.back().radius(), 0,
+                                      /*is_horizontally_positioned=*/true);
+  }
+
+  std::array<const RoundedCorner*, 2> sorted_corners = {&corners.at(0),
+                                                        &corners.at(1)};
+
+  std::sort(sorted_corners.begin(), sorted_corners.end(),
+            [](const RoundedCorner* c1, const RoundedCorner* c2) {
+              return c1->bounds().origin() < c2->bounds().origin();
+            });
+
+  const RoundedDisplayGutter::RoundedCorner& first_corner =
+      *sorted_corners.at(0);
+  const RoundedDisplayGutter::RoundedCorner& second_corner =
+      *sorted_corners.at(1);
+
+  // Corners of a gutter need to be either vertically or horizontally
+  // aligned.
+  DCHECK(first_corner.bounds().x() == second_corner.bounds().x() ||
+         first_corner.bounds().y() == second_corner.bounds().y());
+
+  DCHECK(!first_corner.bounds().Intersects(second_corner.bounds()));
+
+  bool is_horizontally_positioned =
+      first_corner.bounds().y() == second_corner.bounds().y();
+
+  return viz::TextureDrawQuad::RoundedDisplayMasksInfo::
+      CreateRoundedDisplayMasksInfo(first_corner.radius(),
+                                    second_corner.radius(),
+                                    is_horizontally_positioned);
+}
+
 }  // namespace
 
 // -----------------------------------------------------------------------------
@@ -200,8 +246,7 @@
     viz::TransferableResource transferable_resource =
         resource_manager.PrepareResourceForExport(resource_id);
 
-    AppendQuad(transferable_resource, gutter->bounds().size(),
-               gutter->bounds().size(), buffer_to_target_transform,
+    AppendQuad(transferable_resource, buffer_to_target_transform, *gutter,
                *render_pass);
 
     frame->resource_list.push_back(std::move(transferable_resource));
@@ -262,41 +307,49 @@
 
 void RoundedDisplayFrameFactory::AppendQuad(
     const viz::TransferableResource& resource,
-    const gfx::Size& gutter_size,
-    const gfx::Size& buffer_size,
     const gfx::Transform& buffer_to_target_transform,
+    const RoundedDisplayGutter& gutter,
     viz::CompositorRenderPass& render_pass_out) const {
-  gfx::Rect output_rect(gutter_size);
+  const gfx::Size& gutter_size_in_pixels = gutter.bounds().size();
 
+  // Each gutter can be thought of as a single ui::Layer that produces only one
+  // quad. Therefore the layer_rect and visible_layer_rect is the size of the
+  // `gutter_size_in_pixels`. (layer is the same size as the texture produced
+  // and it is all visible)
   viz::SharedQuadState* quad_state =
       render_pass_out.CreateAndAppendSharedQuadState();
   quad_state->SetAll(buffer_to_target_transform,
-                     /*layer_rect=*/output_rect,
-                     /*visible_layer_rect=*/output_rect,
+                     /*layer_rect=*/gfx::Rect(gutter_size_in_pixels),
+                     /*visible_layer_rect=*/gfx::Rect(gutter_size_in_pixels),
                      /*filter_info=*/gfx::MaskFilterInfo(),
                      /*clip=*/absl::nullopt, /*contents_opaque=*/false,
                      /*opacity_f=*/1.f,
                      /*blend=*/SkBlendMode::kSrcOver,
                      /*sorting_context=*/0);
 
-  gfx::Rect quad_rect(buffer_size);
-
   viz::TextureDrawQuad* texture_quad =
       render_pass_out.CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
-  float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-  gfx::RectF uv_crop(quad_rect);
-  uv_crop.Scale(1.f / buffer_size.width(), 1.f / buffer_size.height());
 
-  texture_quad->SetNew(
-      quad_state, quad_rect, quad_rect,
-      /*needs_blending=*/true, resource.id,
-      /*premultiplied=*/true, uv_crop.origin(), uv_crop.bottom_right(),
-      /*background=*/SkColors::kTransparent, vertex_opacity,
-      /*flipped=*/false,
-      /*nearest=*/false,
-      /*secure_output=*/false, gfx::ProtectedVideoType::kClear);
+  constexpr float kVertexOpacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+  // Each frame, we re-render the full texture therefore quad_rect is the size
+  // of the texture i.e `gutter_size_in_pixels`.
+  gfx::Rect quad_rect(gutter_size_in_pixels);
+
+  texture_quad->SetNew(quad_state, quad_rect, quad_rect,
+                       /*needs_blending=*/true, resource.id,
+                       /*premultiplied=*/true, gfx::RectF(quad_rect).origin(),
+                       gfx::RectF(quad_rect).bottom_right(),
+                       /*background=*/SkColors::kTransparent, kVertexOpacity,
+                       /*flipped=*/false,
+                       /*nearest=*/false,
+                       /*secure_output=*/false,
+                       gfx::ProtectedVideoType::kClear);
 
   texture_quad->set_resource_size_in_pixels(resource.size);
+
+  texture_quad->rounded_display_masks_info =
+      MapToRoundedDisplayMasksInfo(gutter.GetGutterCorners());
 }
 
 }  // namespace ash
diff --git a/ash/rounded_display/rounded_display_frame_factory.h b/ash/rounded_display/rounded_display_frame_factory.h
index f4a0ce4..c96b626 100644
--- a/ash/rounded_display/rounded_display_frame_factory.h
+++ b/ash/rounded_display/rounded_display_frame_factory.h
@@ -74,9 +74,8 @@
  private:
   // Configures and appends a `TextureDrawQuad` to the `render_pass`.
   void AppendQuad(const viz::TransferableResource& resource,
-                  const gfx::Size& gutter_size,
-                  const gfx::Size& buffer_size,
                   const gfx::Transform& buffer_to_target_transform,
+                  const RoundedDisplayGutter& gutter,
                   viz::CompositorRenderPass& render_pass_out) const;
 
   // Get a UiResource for the `gutter`. We try to reuse any existing resources
diff --git a/ash/rounded_display/rounded_display_frame_factory_unittest.cc b/ash/rounded_display/rounded_display_frame_factory_unittest.cc
index c9950a9..78296da 100644
--- a/ash/rounded_display/rounded_display_frame_factory_unittest.cc
+++ b/ash/rounded_display/rounded_display_frame_factory_unittest.cc
@@ -13,7 +13,10 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
+#include "components/viz/common/quads/quad_list.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
 #include "rounded_display_gutter_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/compositor/layer_type.h"
@@ -25,6 +28,9 @@
 constexpr viz::ResourceFormat kTestResourceFormat =
     SK_B32_SHIFT ? viz::RGBA_8888 : viz::BGRA_8888;
 constexpr gfx::Size kTestDisplaySize(1920, 1080);
+constexpr gfx::RoundedCornersF kTestPanelRadii(10);
+
+using RoundedDisplayMasksInfo = viz::TextureDrawQuad::RoundedDisplayMasksInfo;
 
 class RoundedDisplayFrameFactoryTest : public AshTestBase {
  public:
@@ -48,9 +54,6 @@
 
     auto* root_window = ash_test_helper()->GetHost()->window();
     root_window->AddChild(host_window_.get());
-
-    gutters_ = CreateGutters(kTestDisplaySize, gfx::RoundedCornersF(10),
-                             /*create_vertical_gutters=*/true);
   }
 
   // AshTestBase:
@@ -73,27 +76,39 @@
     return gutters;
   }
 
-  std::vector<std::unique_ptr<RoundedDisplayGutter>> CreateGutters(
-      const gfx::Size& display_size_in_pixels,
-      const gfx::RoundedCornersF& display_radii,
-      bool create_vertical_gutters) {
-    std::vector<std::unique_ptr<RoundedDisplayGutter>> gutters;
-
+  // Creates vertical gutters and appends them to `gutters_`.
+  void AppendVerticalOverlayGutters(const gfx::Size& display_size_in_pixels,
+                                    const gfx::RoundedCornersF& panel_radii) {
     auto overlay_gutters = gutter_factory_->CreateOverlayGutters(
-        display_size_in_pixels, display_radii, create_vertical_gutters);
+        display_size_in_pixels, panel_radii,
+        /*create_vertical_gutters=*/true);
 
     for (auto& gutter : overlay_gutters) {
-      gutters.push_back(std::move(gutter));
+      gutters_.push_back(std::move(gutter));
     }
+  }
 
+  // Creates horizontal gutters and appends them to `gutters_`.
+  void AppendHorizontalOverlayGutters(const gfx::Size& display_size_in_pixels,
+                                      const gfx::RoundedCornersF& panel_radii) {
+    auto overlay_gutters = gutter_factory_->CreateOverlayGutters(
+        display_size_in_pixels, panel_radii,
+        /*create_vertical_gutters=*/false);
+
+    for (auto& gutter : overlay_gutters) {
+      gutters_.push_back(std::move(gutter));
+    }
+  }
+
+  // Creates non overlay gutters and appends them to `gutters_`.
+  void AppendNonOverlayGutters(const gfx::Size& display_size_in_pixels,
+                               const gfx::RoundedCornersF& panel_radii) {
     auto non_overlay_gutters = gutter_factory_->CreateNonOverlayGutters(
-        display_size_in_pixels, display_radii);
+        display_size_in_pixels, panel_radii);
 
     for (auto& gutter : non_overlay_gutters) {
-      gutters.push_back(std::move(gutter));
+      gutters_.push_back(std::move(gutter));
     }
-
-    return gutters;
   }
 
  protected:
@@ -106,6 +121,8 @@
 
 // TODO(zoraiznaeem): Add more unittest coverage.
 TEST_F(RoundedDisplayFrameFactoryTest, CompositorFrameHasCorrectStructure) {
+  AppendVerticalOverlayGutters(kTestDisplaySize, kTestPanelRadii);
+
   const auto& gutters = GetGutters();
 
   auto frame = frame_factory_->CreateCompositorFrame(
@@ -133,7 +150,92 @@
   EXPECT_EQ(shared_quad_state_list.size(), gutters.size());
 }
 
+MATCHER_P(IsRoundedDisplayMasksInfoEqual, value, "") {
+  return arg.is_horizontally_positioned == value.is_horizontally_positioned &&
+         arg.radii[RoundedDisplayMasksInfo::kOriginRoundedDisplayMaskIndex] ==
+             value.radii
+                 [RoundedDisplayMasksInfo::kOriginRoundedDisplayMaskIndex] &&
+         arg.radii[RoundedDisplayMasksInfo::kOtherRoundedDisplayMaskIndex] ==
+             value
+                 .radii[RoundedDisplayMasksInfo::kOtherRoundedDisplayMaskIndex];
+}
+
+TEST_F(RoundedDisplayFrameFactoryTest,
+       CorrectRoundedDisplayInfo_VerticalGuttersWithTwoCorners) {
+  const auto panel_radii = gfx::RoundedCornersF(10, 0, 0, 15);
+  AppendVerticalOverlayGutters(kTestDisplaySize, panel_radii);
+
+  // `gutter_factory_` will only create left overlay gutter.
+  EXPECT_EQ(gutters_.size(), 1u);
+
+  auto frame = frame_factory_->CreateCompositorFrame(
+      viz::BeginFrameAck::CreateManualAckWithDamage(), *host_window_,
+      resource_manager_, GetGutters());
+
+  const viz::QuadList& quad_list = frame->render_pass_list.front()->quad_list;
+  ASSERT_EQ(quad_list.size(), 1u);
+
+  EXPECT_THAT(viz::TextureDrawQuad::MaterialCast(quad_list.ElementAt(0))
+                  ->rounded_display_masks_info,
+              IsRoundedDisplayMasksInfoEqual(
+                  RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(
+                      /*origin_rounded_display_mask_radius=*/10,
+                      /*other_rounded_display_mask_radius=*/15,
+                      /*is_horizontally_positioned=*/false)));
+}
+
+TEST_F(RoundedDisplayFrameFactoryTest,
+       CorrectRoundedDisplayInfo_HorizontalGuttersWithTwoCorners) {
+  const auto panel_radii = gfx::RoundedCornersF(15, 10, 0, 0);
+  AppendHorizontalOverlayGutters(kTestDisplaySize, panel_radii);
+
+  // `gutter_factory_` will only create upper overlay gutter.
+  EXPECT_EQ(gutters_.size(), 1u);
+
+  auto frame = frame_factory_->CreateCompositorFrame(
+      viz::BeginFrameAck::CreateManualAckWithDamage(), *host_window_,
+      resource_manager_, GetGutters());
+
+  const viz::QuadList& quad_list = frame->render_pass_list.front()->quad_list;
+  ASSERT_EQ(quad_list.size(), 1u);
+
+  EXPECT_THAT(viz::TextureDrawQuad::MaterialCast(quad_list.ElementAt(0))
+                  ->rounded_display_masks_info,
+              IsRoundedDisplayMasksInfoEqual(
+                  RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(
+                      /*origin_rounded_display_mask_radius=*/15,
+                      /*other_rounded_display_mask_radius=*/10,
+                      /*is_horizontally_positioned=*/true)));
+}
+
+TEST_F(RoundedDisplayFrameFactoryTest,
+       CorrectRoundedDisplayInfo_GuttersWithOneCorner) {
+  const auto panel_radii = gfx::RoundedCornersF(10, 0, 0, 0);
+  AppendNonOverlayGutters(kTestDisplaySize, panel_radii);
+
+  // `gutter_factory_` will only create upper-left non-overlay gutter.
+  EXPECT_EQ(gutters_.size(), 1u);
+
+  auto frame = frame_factory_->CreateCompositorFrame(
+      viz::BeginFrameAck::CreateManualAckWithDamage(), *host_window_,
+      resource_manager_, GetGutters());
+
+  const viz::QuadList& quad_list = frame->render_pass_list.front()->quad_list;
+  ASSERT_EQ(quad_list.size(), 1u);
+
+  EXPECT_THAT(viz::TextureDrawQuad::MaterialCast(quad_list.ElementAt(0))
+                  ->rounded_display_masks_info,
+              IsRoundedDisplayMasksInfoEqual(
+                  RoundedDisplayMasksInfo::CreateRoundedDisplayMasksInfo(
+                      /*origin_rounded_display_mask_radius=*/10,
+                      /*other_rounded_display_mask_radius=*/0,
+                      /*is_horizontally_positioned=*/true)));
+}
+
 TEST_F(RoundedDisplayFrameFactoryTest, OnlyCreateNewResourcesWhenNecessary) {
+  AppendVerticalOverlayGutters(kTestDisplaySize, kTestPanelRadii);
+  AppendNonOverlayGutters(kTestDisplaySize, kTestPanelRadii);
+
   const auto& gutters = GetGutters();
 
   // Populate resources in the resource manager.
diff --git a/ash/search_box/search_box_view_base.cc b/ash/search_box/search_box_view_base.cc
index 15a1db27..1a19bc7a 100644
--- a/ash/search_box/search_box_view_base.cc
+++ b/ash/search_box/search_box_view_base.cc
@@ -349,6 +349,8 @@
                           views::DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING);
   iph_container_ = AddChildView(std::make_unique<views::BoxLayoutView>());
   iph_container_->SetOrientation(views::BoxLayout::Orientation::kVertical);
+  iph_container_->SetMainAxisAlignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
 
   content_container_ =
       iph_container_->AddChildView(std::make_unique<views::BoxLayoutView>());
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 70f2fd3..d8790bb0 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -85,6 +85,8 @@
 #include "ui/events/event_utils.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/transform_util.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/animation/bounds_animator.h"
 #include "ui/views/animation/ink_drop.h"
@@ -1267,6 +1269,7 @@
   // animation is still in progress), as drag icon proxy is not expected to be
   // reused after it starts animating out.
   drag_icon_proxy_.reset();
+  drag_image_layer_.reset();
 
   // Only when the repost event occurs on the same shelf item, we should ignore
   // the call in ShelfView::ButtonPressed(...).
@@ -1333,30 +1336,18 @@
 
   delegate_->CancelScrollForItemDrag();
 
-  if (!drag_view_ || dragged_off_shelf_)
+  if (!drag_view_ || dragged_off_shelf_) {
     drag_icon_proxy_.reset();
+    drag_image_layer_.reset();
+  }
+
+  const gfx::Rect target_bounds_in_screen =
+      CalculateDropTargetBoundsForDragViewInScreen();
 
   if (drag_icon_proxy_) {
-    const gfx::Rect drag_view_ideal_bounds = view_model_->ideal_bounds(
-        view_model_->GetIndexOfView(drag_view_).value());
-    gfx::Rect target_bounds_in_screen =
-        drag_view_->GetIdealIconBounds(drag_view_ideal_bounds.size(),
-                                       /*icon_scale=*/1.0f);
-    target_bounds_in_screen.Offset(drag_view_ideal_bounds.x(),
-                                   drag_view_ideal_bounds.y());
-    target_bounds_in_screen = GetMirroredRect(target_bounds_in_screen);
-    views::View::ConvertRectToScreen(this, &target_bounds_in_screen);
-
-    if (!delegate_->AreBoundsWithinVisibleSpace(target_bounds_in_screen)) {
-      drag_icon_proxy_.reset();
-      drag_view_->layer()->SetOpacity(1.0f);
-    } else {
-      drag_icon_proxy_->AnimateToBoundsAndCloseWidget(
-          target_bounds_in_screen,
-          base::BindOnce(&ShelfView::OnDragIconProxyAnimatedOut,
-                         base::Unretained(this),
-                         std::make_unique<ViewOpacityResetter>(drag_view_)));
-    }
+    AnimateDragIconProxy(target_bounds_in_screen);
+  } else if (drag_image_layer_) {
+    AnimateDragImageLayer(target_bounds_in_screen);
   } else if (drag_view_) {
     drag_view_->layer()->SetOpacity(1.0f);
   }
@@ -1368,10 +1359,89 @@
   RemoveGhostView();
 }
 
+void ShelfView::AnimateDragImageLayer(
+    const gfx::Rect& target_bounds_in_screen) {
+  DCHECK(drag_image_layer_);
+
+  if (!delegate_->AreBoundsWithinVisibleSpace(target_bounds_in_screen)) {
+    drag_image_layer_.reset();
+    drag_view_->layer()->SetOpacity(1.0f);
+    return;
+  }
+
+  ui::Layer* target_layer = drag_image_layer_->root();
+  if (target_layer) {
+    target_layer->GetAnimator()->AbortAllAnimations();
+
+    gfx::Rect current_bounds = target_layer->bounds();
+    if (current_bounds.IsEmpty()) {
+      OnDragIconProxyAnimatedOut(
+          std::make_unique<ViewOpacityResetter>(drag_view_));
+      return;
+    }
+
+    // |target_layer| bounds are in display coordinates.
+    display::Display display =
+        display::Screen::GetScreen()->GetDisplayNearestWindow(
+            GetWidget()->GetNativeWindow());
+    current_bounds.Offset(display.bounds().OffsetFromOrigin());
+
+    const gfx::Transform transform = gfx::TransformBetweenRects(
+        gfx::RectF(current_bounds), gfx::RectF(target_bounds_in_screen));
+
+    views::AnimationBuilder builder;
+    builder.SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET)
+        .OnEnded(base::BindOnce(
+            &ShelfView::OnDragIconProxyAnimatedOut, weak_factory_.GetWeakPtr(),
+            std::make_unique<ViewOpacityResetter>(drag_view_)))
+        .OnAborted(base::BindOnce(
+            &ShelfView::OnDragIconProxyAnimatedOut, weak_factory_.GetWeakPtr(),
+            std::make_unique<ViewOpacityResetter>(drag_view_)))
+        .Once()
+        .SetDuration(base::Milliseconds(200))
+        .SetTransform(target_layer, transform, gfx::Tween::FAST_OUT_LINEAR_IN);
+  }
+}
+
+void ShelfView::AnimateDragIconProxy(const gfx::Rect& target_bounds_in_screen) {
+  DCHECK(drag_icon_proxy_);
+
+  if (!delegate_->AreBoundsWithinVisibleSpace(target_bounds_in_screen)) {
+    drag_icon_proxy_.reset();
+    drag_view_->layer()->SetOpacity(1.0f);
+    return;
+  }
+
+  drag_icon_proxy_->AnimateToBoundsAndCloseWidget(
+      target_bounds_in_screen,
+      base::BindOnce(&ShelfView::OnDragIconProxyAnimatedOut,
+                     base::Unretained(this),
+                     std::make_unique<ViewOpacityResetter>(drag_view_)));
+}
+
+gfx::Rect ShelfView::CalculateDropTargetBoundsForDragViewInScreen() {
+  if (!drag_view_) {
+    return gfx::Rect();
+  }
+
+  const gfx::Rect drag_view_ideal_bounds = view_model_->ideal_bounds(
+      view_model_->GetIndexOfView(drag_view_).value());
+  gfx::Rect target_bounds_in_screen =
+      drag_view_->GetIdealIconBounds(drag_view_ideal_bounds.size(),
+                                     /*icon_scale=*/1.0f);
+  target_bounds_in_screen.Offset(drag_view_ideal_bounds.x(),
+                                 drag_view_ideal_bounds.y());
+  target_bounds_in_screen = GetMirroredRect(target_bounds_in_screen);
+  views::View::ConvertRectToScreen(this, &target_bounds_in_screen);
+
+  return target_bounds_in_screen;
+}
+
 void ShelfView::OnDragIconProxyAnimatedOut(
     std::unique_ptr<ViewOpacityResetter> opacity_resetter) {
   opacity_resetter->Run();
   drag_icon_proxy_.reset();
+  drag_image_layer_.reset();
 }
 
 void ShelfView::LayoutToIdealBounds() {
@@ -1507,6 +1577,7 @@
   // Drag icon proxy from previous drag may be around if the icon is still
   // animating to the final position. Reset it here to cancel the animation.
   drag_icon_proxy_.reset();
+  drag_image_layer_.reset();
   delegate_->CancelScrollForItemDrag();
 
   drag_view_->layer()->SetOpacity(0.0f);
@@ -1757,6 +1828,7 @@
   // proxy image.
   if (!current_index.has_value()) {
     drag_icon_proxy_.reset();
+    drag_image_layer_.reset();
     return;
   }
 
@@ -1799,6 +1871,7 @@
     model_->OnItemReturnedFromRipOff(model_->item_count() - 1);
   }
   drag_icon_proxy_.reset();
+  drag_image_layer_.reset();
 }
 
 ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) const {
@@ -2065,6 +2138,7 @@
 
   delegate_->CancelScrollForItemDrag();
   drag_icon_proxy_.reset();
+  drag_image_layer_.reset();
 
   if (!drag_view_)
     return modified_index;
@@ -2804,6 +2878,7 @@
     std::unique_ptr<ui::LayerTreeOwner> drag_image_layer_owner) {
   // TODO(b/271601288): Hook up drop animation with the drag image icon.
   output_drag_op = ui::mojom::DragOperation::kMove;
+  drag_image_layer_ = std::move(drag_image_layer_owner);
   EndDrag(false, /*icon_proxy = */ nullptr);
 }
 
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 417782a2..97b61fe 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -594,6 +594,18 @@
   // ShelfParty feature is enabled.
   bool AreAllPinnedAppsHidden() const;
 
+  // Calculate the drop target bounds in the screen for the current `drag_view_`
+  // according to the target position in the shelf.
+  gfx::Rect CalculateDropTargetBoundsForDragViewInScreen();
+
+  // Runs animation for a `drag_icon_proxy_` to the provided
+  // `target_bounds_in_screen`.
+  void AnimateDragIconProxy(const gfx::Rect& target_bounds_in_screen);
+
+  // Runs animation for a `drag_image_layer_` to the provided
+  // `target_bounds_in_screen`.
+  void AnimateDragImageLayer(const gfx::Rect& target_bounds_in_screen);
+
   // The model; owned by Launcher.
   ShelfModel* const model_;
 
@@ -778,6 +790,10 @@
   // Called when showing shelf context menu.
   base::RepeatingClosure context_menu_shown_callback_;
 
+  // The layer that contains the icon image for the item under the drag cursor.
+  // Assigned before the dropping animation is scheduled.
+  std::unique_ptr<ui::LayerTreeOwner> drag_image_layer_;
+
   // The shelf party animations.
   base::flat_map<ShelfID, std::unique_ptr<PartyingShelfItem>> party_;
 
diff --git a/ash/style/ash_color_id.h b/ash/style/ash_color_id.h
index 8e6de686..eb34425 100644
--- a/ash/style/ash_color_id.h
+++ b/ash/style/ash_color_id.h
@@ -101,6 +101,7 @@
   E_CPONLY(kColorAshInkDrop) \
   E_CPONLY(kColorAshInkDropOpaqueColor) \
   /* Colors for Google Assistant */ \
+  E_CPONLY(kColorAshAssistantBgPlate) \
   E_CPONLY(kColorAshAssistantGreetingEnabled) \
   E_CPONLY(kColorAshSuggestionChipViewTextView) \
   E_CPONLY(kColorAshAssistantQueryHighConfidenceLabel) \
diff --git a/ash/style/ash_color_mixer.cc b/ash/style/ash_color_mixer.cc
index 72b0bb8..c0822c13 100644
--- a/ash/style/ash_color_mixer.cc
+++ b/ash/style/ash_color_mixer.cc
@@ -526,6 +526,9 @@
   AddControlsColors(mixer, key);
   AddContentColors(mixer, key);
 
+  mixer[kColorAshAssistantBgPlate] = {use_dark_color
+                                          ? SkColorSetRGB(0x1c, 0x2b, 0x3b)
+                                          : SkColorSetRGB(0xec, 0xef, 0xee)};
   mixer[kColorAshAssistantGreetingEnabled] = {cros_tokens::kColorPrimary};
   mixer[kColorAshSuggestionChipViewTextView] = {cros_tokens::kColorSecondary};
   mixer[kColorAshAssistantQueryHighConfidenceLabel] = {
diff --git a/ash/style/color_palette_controller.cc b/ash/style/color_palette_controller.cc
index 252fcba5..88326966 100644
--- a/ash/style/color_palette_controller.cc
+++ b/ash/style/color_palette_controller.cc
@@ -263,13 +263,6 @@
 }  // namespace
 
 // static
-std::unique_ptr<ColorPaletteController> ColorPaletteController::Create() {
-  Shell* shell = Shell::Get();
-  return Create(shell->dark_light_mode_controller(),
-                shell->wallpaper_controller());
-}
-
-// static
 std::unique_ptr<ColorPaletteController> ColorPaletteController::Create(
     DarkLightModeController* dark_light_mode_controller,
     WallpaperControllerImpl* wallpaper_controller) {
diff --git a/ash/style/color_palette_controller.h b/ash/style/color_palette_controller.h
index 2370b57..b7a82502 100644
--- a/ash/style/color_palette_controller.h
+++ b/ash/style/color_palette_controller.h
@@ -72,9 +72,6 @@
     virtual void OnColorPaletteChanging(const ColorPaletteSeed& seed) = 0;
   };
 
-  // Temporary factory for migration.  DO NOT USE.
-  static std::unique_ptr<ColorPaletteController> Create();
-
   static std::unique_ptr<ColorPaletteController> Create(
       DarkLightModeController* dark_light_mode_controller,
       WallpaperControllerImpl* wallpaper_controller);
diff --git a/ash/style/dark_light_mode_controller_impl.cc b/ash/style/dark_light_mode_controller_impl.cc
index cb75246..c254a0f7 100644
--- a/ash/style/dark_light_mode_controller_impl.cc
+++ b/ash/style/dark_light_mode_controller_impl.cc
@@ -52,10 +52,14 @@
   native_theme->NotifyOnNativeThemeUpdated();
 
   auto* native_theme_web = ui::NativeTheme::GetInstanceForWeb();
-  native_theme_web->set_use_dark_colors(is_dark_mode_enabled);
-  native_theme_web->set_preferred_color_scheme(
-      is_dark_mode_enabled ? ui::NativeTheme::PreferredColorScheme::kDark
-                           : ui::NativeTheme::PreferredColorScheme::kLight);
+  if (!native_theme_web->IsForcedDarkMode()) {
+    // If we're in forced dark mode, leave the value alone to allow the tests to
+    // work.
+    native_theme_web->set_use_dark_colors(is_dark_mode_enabled);
+    native_theme_web->set_preferred_color_scheme(
+        is_dark_mode_enabled ? ui::NativeTheme::PreferredColorScheme::kDark
+                             : ui::NativeTheme::PreferredColorScheme::kLight);
+  }
   native_theme_web->set_user_color(themed_color);
   native_theme_web->NotifyOnNativeThemeUpdated();
 }
diff --git a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.cc b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.cc
index a9045432..22b1085 100644
--- a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.cc
+++ b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.cc
@@ -17,6 +17,15 @@
 namespace ash {
 namespace {
 
+// Whether or not settings taken during the transition period should be
+// persisted to the prefs. Values should only ever be true if the original
+// setting was a user-configured value.
+struct ForcePointingStickSettingPersistence {
+  bool swap_right = false;
+  bool sensitivity = false;
+  bool acceleration_enabled = false;
+};
+
 mojom::PointingStickSettingsPtr GetDefaultPointingStickSettings() {
   mojom::PointingStickSettingsPtr settings =
       mojom::PointingStickSettings::New();
@@ -29,17 +38,125 @@
 // GetPointingStickSettingsFromPrefs returns pointing stick settings based on
 // user prefs to be used as settings for new pointing sticks.
 mojom::PointingStickSettingsPtr GetPointingStickSettingsFromPrefs(
-    PrefService* prefs) {
+    PrefService* prefs,
+    ForcePointingStickSettingPersistence& force_persistence) {
   mojom::PointingStickSettingsPtr settings =
       mojom::PointingStickSettings::New();
-  settings->sensitivity = prefs->GetInteger(prefs::kPointingStickSensitivity);
-  settings->swap_right =
-      prefs->GetBoolean(prefs::kPrimaryPointingStickButtonRight);
+
+  const auto* swap_right_preference =
+      prefs->GetUserPrefValue(prefs::kPrimaryPointingStickButtonRight);
+  settings->swap_right = swap_right_preference
+                             ? swap_right_preference->GetBool()
+                             : kDefaultSwapRight;
+  force_persistence.swap_right = swap_right_preference != nullptr;
+
+  const auto* sensitivity_preference =
+      prefs->GetUserPrefValue(prefs::kPointingStickSensitivity);
+  settings->sensitivity = sensitivity_preference
+                              ? sensitivity_preference->GetInt()
+                              : kDefaultSensitivity;
+  force_persistence.sensitivity = sensitivity_preference != nullptr;
+
+  const auto* acceleration_enabled_preference =
+      prefs->GetUserPrefValue(prefs::kPointingStickAcceleration);
   settings->acceleration_enabled =
-      prefs->GetBoolean(prefs::kPointingStickAcceleration);
+      acceleration_enabled_preference
+          ? acceleration_enabled_preference->GetBool()
+          : kDefaultAccelerationEnabled;
+  force_persistence.acceleration_enabled =
+      acceleration_enabled_preference != nullptr;
+
   return settings;
 }
 
+mojom::PointingStickSettingsPtr RetrievePointingStickSettings(
+    PrefService* pref_service,
+    const mojom::PointingStick& pointing_stick,
+    const base::Value::Dict& settings_dict) {
+  mojom::PointingStickSettingsPtr settings =
+      mojom::PointingStickSettings::New();
+  settings->sensitivity =
+      settings_dict.FindInt(prefs::kPointingStickSettingSensitivity)
+          .value_or(kDefaultSensitivity);
+  settings->swap_right =
+      settings_dict.FindBool(prefs::kPointingStickSettingSwapRight)
+          .value_or(kDefaultSwapRight);
+  settings->acceleration_enabled =
+      settings_dict.FindBool(prefs::kPointingStickSettingAcceleration)
+          .value_or(kDefaultAccelerationEnabled);
+  return settings;
+}
+
+bool ExistingSettingsHasValue(base::StringPiece setting_key,
+                              const base::Value::Dict* existing_settings_dict) {
+  if (!existing_settings_dict) {
+    return false;
+  }
+
+  return existing_settings_dict->Find(setting_key) != nullptr;
+}
+
+void UpdatePointingStickSettingsImpl(
+    PrefService* pref_service,
+    const mojom::PointingStick& pointing_stick,
+    const ForcePointingStickSettingPersistence& force_persistence) {
+  DCHECK(pointing_stick.settings);
+  base::Value::Dict devices_dict =
+      pref_service->GetDict(prefs::kPointingStickDeviceSettingsDictPref)
+          .Clone();
+  base::Value::Dict* existing_settings_dict =
+      devices_dict.FindDict(pointing_stick.device_key);
+  const mojom::PointingStickSettings& settings = *pointing_stick.settings;
+
+  // Settings should only be persisted if one or more of the following is true:
+  // - Setting was previously persisted to storage
+  // - `force_persistence` requires the setting to be persisted, this means this
+  //   device is being transitioned from the old global settings to per-device
+  //   settings and the user specified the specific value for this setting.
+  // - Setting is different than the default, which means the user manually
+  //   changed the value.
+
+  // Populate `settings_dict` with all settings in `settings`.
+  base::Value::Dict settings_dict;
+
+  if (ExistingSettingsHasValue(prefs::kPointingStickSettingSwapRight,
+                               existing_settings_dict) ||
+      force_persistence.swap_right ||
+      settings.swap_right != kDefaultSwapRight) {
+    settings_dict.Set(prefs::kPointingStickSettingSwapRight,
+                      settings.swap_right);
+  }
+
+  if (ExistingSettingsHasValue(prefs::kPointingStickSettingSensitivity,
+                               existing_settings_dict) ||
+      force_persistence.sensitivity ||
+      settings.sensitivity != kDefaultSensitivity) {
+    settings_dict.Set(prefs::kPointingStickSettingSensitivity,
+                      settings.sensitivity);
+  }
+
+  if (ExistingSettingsHasValue(prefs::kPointingStickSettingAcceleration,
+                               existing_settings_dict) ||
+      force_persistence.acceleration_enabled ||
+      settings.acceleration_enabled != kDefaultAccelerationEnabled) {
+    settings_dict.Set(prefs::kPointingStickSettingAcceleration,
+                      settings.acceleration_enabled);
+  }
+
+  // If an old settings dict already exists for the device, merge the updated
+  // settings into the old settings. Otherwise, insert the dict at
+  // `pointing_stick.device_key`.
+  if (existing_settings_dict) {
+    existing_settings_dict->Merge(std::move(settings_dict));
+  } else {
+    devices_dict.Set(pointing_stick.device_key, std::move(settings_dict));
+  }
+
+  pref_service->SetDict(
+      std::string(prefs::kPointingStickDeviceSettingsDictPref),
+      std::move(devices_dict));
+}
+
 }  // namespace
 
 PointingStickPrefHandlerImpl::PointingStickPrefHandlerImpl() = default;
@@ -56,84 +173,30 @@
   const auto& devices_dict =
       pref_service->GetDict(prefs::kPointingStickDeviceSettingsDictPref);
   const auto* settings_dict = devices_dict.FindDict(pointing_stick->device_key);
-  if (!settings_dict) {
-    pointing_stick->settings =
-        GetNewPointingStickSettings(pref_service, *pointing_stick);
-  } else {
+  ForcePointingStickSettingPersistence force_persistence;
+
+  if (settings_dict) {
     pointing_stick->settings = RetrievePointingStickSettings(
         pref_service, *pointing_stick, *settings_dict);
+  } else if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected(
+                 InputDeviceTracker::InputDeviceCategory::kPointingStick,
+                 pointing_stick->device_key)) {
+    pointing_stick->settings =
+        GetPointingStickSettingsFromPrefs(pref_service, force_persistence);
+  } else {
+    pointing_stick->settings = GetDefaultPointingStickSettings();
   }
   DCHECK(pointing_stick->settings);
 
-  UpdatePointingStickSettings(pref_service, *pointing_stick);
+  UpdatePointingStickSettingsImpl(pref_service, *pointing_stick,
+                                  force_persistence);
 }
 
 void PointingStickPrefHandlerImpl::UpdatePointingStickSettings(
     PrefService* pref_service,
     const mojom::PointingStick& pointing_stick) {
-  // Populate `settings_dict` with all settings in `settings`.
-  const mojom::PointingStickSettings& settings = *pointing_stick.settings;
-
-  DCHECK(pointing_stick.settings);
-  base::Value::Dict settings_dict;
-  settings_dict.Set(prefs::kPointingStickSettingSwapRight, settings.swap_right);
-  settings_dict.Set(prefs::kPointingStickSettingSensitivity,
-                    settings.sensitivity);
-  settings_dict.Set(prefs::kPointingStickSettingAcceleration,
-                    settings.acceleration_enabled);
-
-  // Retrieve old settings and merge with the new ones.
-  base::Value::Dict devices_dict =
-      pref_service->GetDict(prefs::kPointingStickDeviceSettingsDictPref)
-          .Clone();
-
-  // If an old settings dict already exists for the device, merge the updated
-  // settings into the old settings. Otherwise, insert the dict at
-  // `pointing_stick.device_key`.
-  base::Value::Dict* old_settings_dict =
-      devices_dict.FindDict(pointing_stick.device_key);
-  if (old_settings_dict) {
-    old_settings_dict->Merge(std::move(settings_dict));
-  } else {
-    devices_dict.Set(pointing_stick.device_key, std::move(settings_dict));
-  }
-
-  pref_service->SetDict(
-      std::string(prefs::kPointingStickDeviceSettingsDictPref),
-      std::move(devices_dict));
-}
-
-mojom::PointingStickSettingsPtr
-PointingStickPrefHandlerImpl::GetNewPointingStickSettings(
-    PrefService* pref_service,
-    const mojom::PointingStick& pointing_stick) {
-  // TODO(michaelcheco): Remove once transitioned to per-device settings.
-  if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected(
-          InputDeviceTracker::InputDeviceCategory::kPointingStick,
-          pointing_stick.device_key)) {
-    return GetPointingStickSettingsFromPrefs(pref_service);
-  }
-
-  return GetDefaultPointingStickSettings();
-}
-
-mojom::PointingStickSettingsPtr
-PointingStickPrefHandlerImpl::RetrievePointingStickSettings(
-    PrefService* pref_service,
-    const mojom::PointingStick& pointing_stick,
-    const base::Value::Dict& settings_dict) {
-  mojom::PointingStickSettingsPtr settings =
-      mojom::PointingStickSettings::New();
-  settings->sensitivity =
-      settings_dict.FindInt(prefs::kPointingStickSettingSensitivity)
-          .value_or(kDefaultSensitivity);
-  settings->swap_right =
-      settings_dict.FindBool(prefs::kPointingStickSettingSwapRight)
-          .value_or(kDefaultSwapRight);
-  settings->acceleration_enabled =
-      settings_dict.FindBool(prefs::kPointingStickSettingAcceleration)
-          .value_or(kDefaultAccelerationEnabled);
-  return settings;
+  UpdatePointingStickSettingsImpl(pref_service, pointing_stick,
+                                  /*force_persistence=*/{});
 }
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h
index fa1dae9..650588bc 100644
--- a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h
+++ b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h
@@ -29,15 +29,6 @@
   void UpdatePointingStickSettings(
       PrefService* pref_service,
       const mojom::PointingStick& pointing_stick) override;
-
- private:
-  mojom::PointingStickSettingsPtr GetNewPointingStickSettings(
-      PrefService* prefs,
-      const mojom::PointingStick& pointing_stick);
-  mojom::PointingStickSettingsPtr RetrievePointingStickSettings(
-      PrefService* prefs,
-      const mojom::PointingStick& pointing_stick,
-      const base::Value::Dict& settings_dict);
 };
 
 }  // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_unittest.cc b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_unittest.cc
index 4b0e591..c73f9fe 100644
--- a/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_unittest.cc
+++ b/ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/public/mojom/input_device_settings.mojom-forward.h"
 #include "ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h"
 
 #include "ash/constants/ash_pref_names.h"
@@ -32,6 +33,11 @@
     /*sensitivity=*/kDefaultSensitivity,
     /*acceleration_enabled=*/kDefaultAccelerationEnabled);
 
+const mojom::PointingStickSettings kPointingStickSettingsNotDefault(
+    /*swap_right=*/!kDefaultSwapRight,
+    /*sensitivity=*/1,
+    /*acceleration_enabled=*/!kDefaultAccelerationEnabled);
+
 const mojom::PointingStickSettings kPointingStickSettings1(
     /*swap_right=*/true,
     /*sensitivity=*/1,
@@ -70,11 +76,18 @@
     pref_service_->registry()->RegisterDictionaryPref(
         prefs::kPointingStickDeviceSettingsDictPref);
     pref_service_->registry()->RegisterIntegerPref(
-        prefs::kPointingStickSensitivity, kTestSensitivity);
+        prefs::kPointingStickSensitivity, kDefaultSensitivity);
     pref_service_->registry()->RegisterBooleanPref(
-        prefs::kPrimaryPointingStickButtonRight, kTestSwapRight);
+        prefs::kPrimaryPointingStickButtonRight, kDefaultSwapRight);
     pref_service_->registry()->RegisterBooleanPref(
-        prefs::kPointingStickAcceleration, kTestAccelerationEnabled);
+        prefs::kPointingStickAcceleration, kDefaultAccelerationEnabled);
+
+    pref_service_->SetUserPref(prefs::kPointingStickSensitivity,
+                               base::Value(kTestSensitivity));
+    pref_service_->SetUserPref(prefs::kPrimaryPointingStickButtonRight,
+                               base::Value(kTestSwapRight));
+    pref_service_->SetUserPref(prefs::kPointingStickAcceleration,
+                               base::Value(kTestAccelerationEnabled));
   }
 
   void CheckPointingStickSettingsAndDictAreEqual(
@@ -82,18 +95,27 @@
       const base::Value::Dict& settings_dict) {
     const auto sensitivity =
         settings_dict.FindInt(prefs::kPointingStickSettingSensitivity);
-    ASSERT_TRUE(sensitivity.has_value());
-    EXPECT_EQ(settings.sensitivity, sensitivity);
+    if (sensitivity.has_value()) {
+      EXPECT_EQ(settings.sensitivity, sensitivity);
+    } else {
+      EXPECT_EQ(settings.sensitivity, kDefaultSensitivity);
+    }
 
     const auto swap_right =
         settings_dict.FindBool(prefs::kPointingStickSettingSwapRight);
-    ASSERT_TRUE(swap_right.has_value());
-    EXPECT_EQ(settings.swap_right, swap_right);
+    if (swap_right.has_value()) {
+      EXPECT_EQ(settings.swap_right, swap_right);
+    } else {
+      EXPECT_EQ(settings.swap_right, kDefaultSwapRight);
+    }
 
     const auto acceleration_enabled =
         settings_dict.FindBool(prefs::kPointingStickSettingAcceleration);
-    ASSERT_TRUE(acceleration_enabled.has_value());
-    EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled);
+    if (acceleration_enabled.has_value()) {
+      EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled);
+    } else {
+      EXPECT_EQ(settings.acceleration_enabled, kDefaultAccelerationEnabled);
+    }
   }
 
   void CallUpdatePointingStickSettings(
@@ -117,6 +139,16 @@
     return std::move(pointing_stick->settings);
   }
 
+  const base::Value::Dict* GetSettingsDict(const std::string& device_key) {
+    const auto& devices_dict =
+        pref_service_->GetDict(prefs::kPointingStickDeviceSettingsDictPref);
+    EXPECT_EQ(1u, devices_dict.size());
+    const auto* settings_dict = devices_dict.FindDict(device_key);
+    EXPECT_NE(nullptr, settings_dict);
+
+    return settings_dict;
+  }
+
  protected:
   std::unique_ptr<PointingStickPrefHandlerImpl> pref_handler_;
   std::unique_ptr<TestingPrefServiceSimple> pref_service_;
@@ -279,6 +311,66 @@
   ASSERT_EQ(settings->acceleration_enabled, kTestAccelerationEnabled);
 }
 
+TEST_F(PointingStickPrefHandlerTest,
+       TransitionPeriodSettingsPersistedWhenUserChosen) {
+  mojom::PointingStick pointing_stick;
+  pointing_stick.device_key = kPointingStickKey1;
+  Shell::Get()->input_device_tracker()->OnPointingStickConnected(
+      pointing_stick);
+
+  pref_service_->SetUserPref(prefs::kPointingStickSensitivity,
+                             base::Value(kDefaultSensitivity));
+  pref_service_->SetUserPref(prefs::kPrimaryPointingStickButtonRight,
+                             base::Value(kDefaultSwapRight));
+  pref_service_->SetUserPref(prefs::kPointingStickAcceleration,
+                             base::Value(kDefaultAccelerationEnabled));
+  mojom::PointingStickSettingsPtr settings =
+      CallInitializePointingStickSettings(pointing_stick.device_key);
+  EXPECT_EQ(kPointingStickSettingsDefault, *settings);
+
+  const auto* settings_dict = GetSettingsDict(pointing_stick.device_key);
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSensitivity));
+  EXPECT_TRUE(
+      settings_dict->contains(prefs::kPointingStickSettingAcceleration));
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSwapRight));
+  CheckPointingStickSettingsAndDictAreEqual(kPointingStickSettingsDefault,
+                                            *settings_dict);
+}
+
+TEST_F(PointingStickPrefHandlerTest, DefaultNotPersistedUntilUpdated) {
+  CallUpdatePointingStickSettings(kPointingStickKey1,
+                                  kPointingStickSettingsDefault);
+
+  const auto* settings_dict = GetSettingsDict(kPointingStickKey1);
+  EXPECT_FALSE(
+      settings_dict->contains(prefs::kPointingStickSettingSensitivity));
+  EXPECT_FALSE(
+      settings_dict->contains(prefs::kPointingStickSettingAcceleration));
+  EXPECT_FALSE(settings_dict->contains(prefs::kPointingStickSettingSwapRight));
+  CheckPointingStickSettingsAndDictAreEqual(kPointingStickSettingsDefault,
+                                            *settings_dict);
+
+  CallUpdatePointingStickSettings(kPointingStickKey1,
+                                  kPointingStickSettingsNotDefault);
+  settings_dict = GetSettingsDict(kPointingStickKey1);
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSensitivity));
+  EXPECT_TRUE(
+      settings_dict->contains(prefs::kPointingStickSettingAcceleration));
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSwapRight));
+  CheckPointingStickSettingsAndDictAreEqual(kPointingStickSettingsNotDefault,
+                                            *settings_dict);
+
+  CallUpdatePointingStickSettings(kPointingStickKey1,
+                                  kPointingStickSettingsDefault);
+  settings_dict = GetSettingsDict(kPointingStickKey1);
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSensitivity));
+  EXPECT_TRUE(
+      settings_dict->contains(prefs::kPointingStickSettingAcceleration));
+  EXPECT_TRUE(settings_dict->contains(prefs::kPointingStickSettingSwapRight));
+  CheckPointingStickSettingsAndDictAreEqual(kPointingStickSettingsDefault,
+                                            *settings_dict);
+}
+
 class PointingStickSettingsPrefConversionTest
     : public PointingStickPrefHandlerTest,
       public testing::WithParamInterface<
diff --git a/ash/webui/camera_app_ui/resources/css/css.gni b/ash/webui/camera_app_ui/resources/css/css.gni
index 9c78494..76cbcfe1 100644
--- a/ash/webui/camera_app_ui/resources/css/css.gni
+++ b/ash/webui/camera_app_ui/resources/css/css.gni
@@ -8,6 +8,7 @@
   "flash.css",
   "inkdrop.css",
   "main.css",
+  "menu.css",
   "mode/mode.css",
   "mode/scan.css",
   "mode/video.css",
diff --git a/ash/webui/camera_app_ui/resources/css/menu.css b/ash/webui/camera_app_ui/resources/css/menu.css
new file mode 100644
index 0000000..1910217
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/css/menu.css
@@ -0,0 +1,39 @@
+/* Copyright 2023 The Chromium Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.menu-root {
+  /* Use linear-gradient to apply multiple background colors. */
+  background: linear-gradient(
+    0deg,
+    rgba(255, 255, 255, 0.06),
+    rgba(255, 255, 255, 0.06)
+  ), var(--grey-900);
+  border-radius: 4px;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px rgba(0, 0, 0, 0.15);
+  box-sizing: border-box;
+  color: var(--grey-200);
+  display: none;
+  font-size: 14px;
+  margin: 0;
+  max-width: calc(100vw - 16px);
+  padding-block: 8px;
+  padding-inline: 0;
+  position: fixed;
+  width: max-content;
+}
+
+.menu-root[aria-expanded=true] {
+  display: block;
+}
+
+.menu-root > .item {
+  cursor: pointer;
+  list-style-type: none;
+  padding-block: 8px;
+  padding-inline: 16px;
+}
+
+.menu-root > .item:is(:hover, :focus-visible) {
+  background-color: rgba(255, 255, 255, 0.08);
+}
diff --git a/ash/webui/camera_app_ui/resources/js/js.gni b/ash/webui/camera_app_ui/resources/js/js.gni
index 41c6aac..96661f7 100644
--- a/ash/webui/camera_app_ui/resources/js/js.gni
+++ b/ash/webui/camera_app_ui/resources/js/js.gni
@@ -43,6 +43,7 @@
   "lib/comlink_protocol.ts",
   "lib/ffmpeg.js",
   "main.ts",
+  "menu.ts",
   "metrics.ts",
   "models/async_interval.ts",
   "models/async_writer.ts",
diff --git a/ash/webui/camera_app_ui/resources/js/menu.ts b/ash/webui/camera_app_ui/resources/js/menu.ts
new file mode 100644
index 0000000..286c21e
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/js/menu.ts
@@ -0,0 +1,326 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert, assertInstanceof} from './assert.js';
+import * as dom from './dom.js';
+import {getKeyboardShortcut, instantiateTemplate} from './util.js';
+
+// The minimum pixels space between menu and viewport.
+const MARGIN = 8;
+
+interface MenuOrigin {
+  horizontal: 'center'|'left'|'right';
+  vertical: 'bottom'|'center'|'top';
+}
+
+interface MenuPosition {
+  left: number;
+  top: number;
+}
+
+interface Classes {
+  root: string;
+  item: string;
+}
+
+interface MenuParams {
+  /**
+   * The target element to append the menu element.
+   */
+  target: HTMLElement;
+  /**
+   * The id to set on the menu element for aria- reference by the entry element.
+   */
+  id: string;
+  /**
+   * The root element will be passed to `render` for content customization.
+   * `action` is called when the menu item is clicked.
+   */
+  items: Array<{
+    render: (root: HTMLLIElement) => void,
+    action: (e: Event) => void,
+  }>;
+  /**
+   * The point on the anchor where the menu will attach to.
+   */
+  anchorOrigin?: MenuOrigin;
+  /**
+   * The point on the menu which will attach to the anchor's origin.
+   */
+  transformOrigin?: MenuOrigin;
+  /**
+   * The button element to trigger the menu.
+   */
+  entryElement: HTMLElement;
+  /**
+   * The alternative anchor for menu to calculate its position. Default is
+   * `entryElement`.
+   */
+  anchorElement?: HTMLElement;
+  /**
+   * Relatively adjust the position of menu.
+   */
+  position?: MenuPosition;
+  /**
+   * The custom classes to set on elements created by Menu.
+   */
+  classes?: Partial<Classes>;
+}
+
+const DEFAULT_ANCHOR_ORIGIN: MenuOrigin = {
+  vertical: 'bottom',
+  horizontal: 'left',
+} as const;
+const DEFAULT_TRANSFORM_ORIGIN: MenuOrigin = {
+  vertical: 'top',
+  horizontal: 'left',
+} as const;
+const DEFAULT_POSITION: MenuPosition = {
+  left: 0,
+  top: 0,
+} as const;
+const DEFAULT_CLASSES: Classes = {
+  root: 'menu-root',
+  item: 'item',
+} as const;
+
+export class Menu {
+  private readonly root: HTMLUListElement;
+
+  private readonly entry: HTMLElement;
+
+  private readonly items: HTMLLIElement[] = [];
+
+  private readonly anchorOrigin: MenuOrigin;
+
+  private readonly transformOrigin: MenuOrigin;
+
+  private readonly position: MenuPosition;
+
+  private readonly anchor: HTMLElement;
+
+  private readonly clickAwayListener: (e: MouseEvent) => void;
+
+  private readonly classes: Classes;
+
+  constructor({
+    entryElement,
+    id,
+    items,
+    target,
+    anchorElement = entryElement,
+    anchorOrigin = DEFAULT_ANCHOR_ORIGIN,
+    transformOrigin = DEFAULT_TRANSFORM_ORIGIN,
+    position = DEFAULT_POSITION,
+    classes = {},
+  }: MenuParams) {
+    const fragment = instantiateTemplate('#menu');
+    this.root = dom.getFrom(fragment, '.menu-root', HTMLUListElement);
+    this.entry = entryElement;
+    this.anchor = anchorElement;
+    entryElement.setAttribute('aria-haspopup', 'true');
+    entryElement.setAttribute('aria-controls', id);
+    this.root.setAttribute('aria-labelledby', entryElement.id);
+    this.classes = {...DEFAULT_CLASSES, ...classes};
+    this.root.classList.add(this.classes.root);
+    this.root.id = id;
+    for (const item of items) {
+      const fragment = instantiateTemplate('#menu-item');
+      const itemElement = dom.getFrom(fragment, '.item', HTMLLIElement);
+      itemElement.setAttribute('tabindex', '-1');
+      itemElement.classList.add(this.classes.item);
+      item.render(itemElement);
+      this.root.append(itemElement);
+      itemElement.addEventListener('click', (e) => {
+        this.handleItemClick(e, item.action);
+      });
+      itemElement.addEventListener('keydown', (e) => {
+        this.handleItemKeydown(e, item.action);
+      });
+      this.items.push(itemElement);
+    }
+    this.setupEntry();
+    target.append(this.root);
+    this.clickAwayListener = (e: MouseEvent) => {
+      if (e.target instanceof Node && this.root.contains(e.target)) {
+        return;
+      }
+      this.close();
+    };
+    this.anchorOrigin = anchorOrigin;
+    this.transformOrigin = transformOrigin;
+    this.position = position;
+  }
+
+  private isOpen() {
+    return this.root.getAttribute('aria-expanded') === 'true';
+  }
+
+  /**
+   * Open the menu.
+   */
+  open(): void {
+    if (this.isOpen()) {
+      return;
+    }
+    this.root.setAttribute('aria-expanded', 'true');
+    this.layout();
+    window.addEventListener('click', this.clickAwayListener);
+  }
+
+  /**
+   * Close the menu.
+   */
+  close(): void {
+    if (!this.isOpen()) {
+      return;
+    }
+    this.root.setAttribute('aria-expanded', 'false');
+    this.entry.focus();
+    window.removeEventListener('click', this.clickAwayListener);
+  }
+
+  private focusItem(newItem: HTMLLIElement) {
+    for (const item of this.items) {
+      assertInstanceof(item, HTMLLIElement).tabIndex = -1;
+    }
+    newItem.tabIndex = 0;
+    newItem.focus();
+  }
+
+  private focusFirstItem() {
+    this.focusItem(this.items[0]);
+  }
+
+  private focusLastItem() {
+    this.focusItem(this.items[this.items.length - 1]);
+  }
+
+  private setupEntry() {
+    this.entry.addEventListener('click', (e) => {
+      if (this.isOpen()) {
+        this.close();
+      } else {
+        this.open();
+        this.focusFirstItem();
+      }
+      e.stopPropagation();
+      e.preventDefault();
+    });
+    this.entry.addEventListener('keydown', (e) => {
+      const key = getKeyboardShortcut(e);
+      switch (key) {
+        case 'ArrowDown':
+          this.open();
+          this.focusFirstItem();
+          break;
+        case 'ArrowUp':
+          this.open();
+          this.focusLastItem();
+          break;
+        default:
+          return;
+      }
+      e.preventDefault();
+      e.stopPropagation();
+    });
+  }
+
+  private handleItemKeydown(e: KeyboardEvent, action: (e: Event) => void) {
+    const key = getKeyboardShortcut(e);
+    const item = assertInstanceof(e.currentTarget, HTMLLIElement);
+    switch (key) {
+      case ' ':
+      case 'Enter':
+        this.close();
+        action(e);
+        break;
+      case 'Escape':
+        this.close();
+        break;
+      case 'ArrowUp':
+        this.focusPreviousItem(item);
+        break;
+      case 'ArrowDown':
+        this.focusNextItem(item);
+        break;
+      case 'Home':
+        this.focusFirstItem();
+        break;
+      case 'End':
+        this.focusLastItem();
+        break;
+      case 'Tab':
+      case 'Shift-Tab':
+        this.close();
+        break;
+      default:
+        return;
+    }
+    e.stopPropagation();
+    e.preventDefault();
+  }
+
+  private handleItemClick(e: MouseEvent, action: (e: Event) => void) {
+    this.close();
+    action(e);
+    e.stopPropagation();
+    e.preventDefault();
+  }
+
+
+  private focusPreviousItem(item: HTMLLIElement) {
+    const index = this.items.indexOf(item);
+    assert(index !== -1);
+    const nextIndex = (this.items.length + index - 1) % this.items.length;
+    this.focusItem(this.items[nextIndex]);
+  }
+
+  private focusNextItem(item: HTMLLIElement) {
+    const index = this.items.indexOf(item);
+    assert(index !== -1);
+    const nextIndex = (index + 1) % this.items.length;
+    this.focusItem(this.items[nextIndex]);
+  }
+
+  private layout() {
+    const {top, right, bottom, left, width, height} =
+        this.anchor.getBoundingClientRect();
+    let menuLeft = left;
+    let menuTop = top;
+    if (this.anchorOrigin.horizontal === 'center') {
+      menuLeft = left + width / 2;
+    } else if (this.anchorOrigin.horizontal === 'right') {
+      menuLeft = right;
+    }
+    if (this.anchorOrigin.vertical === 'center') {
+      menuTop = top + height / 2;
+    } else if (this.anchorOrigin.vertical === 'bottom') {
+      menuTop = bottom;
+    }
+    menuLeft += this.position.left;
+    menuTop += this.position.top;
+    const {width: offsetWidth, height: offsetHeight} =
+        this.root.getBoundingClientRect();
+    if (this.transformOrigin.horizontal === 'center') {
+      menuLeft -= offsetWidth / 2;
+    } else if (this.transformOrigin.horizontal === 'right') {
+      menuLeft -= offsetWidth;
+    }
+    if (this.transformOrigin.vertical === 'center') {
+      menuTop -= offsetHeight / 2;
+    } else if (this.transformOrigin.vertical === 'bottom') {
+      menuTop -= offsetHeight;
+    }
+    menuLeft = Math.max(
+        Math.min(menuLeft, document.body.offsetWidth - offsetWidth - MARGIN),
+        MARGIN);
+    menuTop = Math.max(
+        Math.min(menuTop, document.body.offsetHeight - offsetHeight - MARGIN),
+        MARGIN);
+    const style = this.root.attributeStyleMap;
+    style.set('left', CSS.px(menuLeft));
+    style.set('top', CSS.px(menuTop));
+  }
+}
diff --git a/ash/webui/camera_app_ui/resources/js/util.ts b/ash/webui/camera_app_ui/resources/js/util.ts
index a1ee443..eb05baeb8 100644
--- a/ash/webui/camera_app_ui/resources/js/util.ts
+++ b/ash/webui/camera_app_ui/resources/js/util.ts
@@ -95,9 +95,12 @@
   'AudioVolumeUp',
   'AudioVolumeDown',
   'BrowserBack',
-  'Delete',
+  'Delete',  // Alt + Backspace
+  'End',     // Ctrl + Alt + ArrowDown
   'Enter',
   'Escape',
+  'Home',  // Ctrl + Alt + ArrowUp
+  'Tab',
 ] as const;
 const KEYBOARD_KEY_SET = new Set(KEYBOARD_KEYS);
 type KeyboardKey = typeof KEYBOARD_KEYS[number];
diff --git a/ash/webui/camera_app_ui/resources/views/main.html b/ash/webui/camera_app_ui/resources/views/main.html
index a1ea0ba..482e13e 100644
--- a/ash/webui/camera_app_ui/resources/views/main.html
+++ b/ash/webui/camera_app_ui/resources/views/main.html
@@ -8,6 +8,7 @@
     <meta charset="utf-8">
     <!-- main.css contains all :root styles require to be loaded first. -->
     <link rel="stylesheet" href="/css/main.css">
+    <link rel="stylesheet" href="/css/menu.css">
     <link rel="stylesheet" href="/css/button.css">
     <link rel="stylesheet" href="/css/custom_toast.css">
     <link rel="stylesheet" href="/css/flash.css">
@@ -667,5 +668,13 @@
         </div>
       </div>
     </template>
+    <!-- Use `menu-root` and `item` as class name instead of existing `menu` and
+         `menu-item. -->
+    <template id="menu">
+      <ul class="menu-root" role="menu"></ul>
+    </template>
+    <template id="menu-item">
+      <li class="item" role="menuitem"></li>
+    </template>
   </body>
 </html>
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/constants.ts b/ash/webui/personalization_app/resources/js/wallpaper/constants.ts
index e22031d3..ff7396c1 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/constants.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/constants.ts
@@ -31,4 +31,5 @@
   unitId?: bigint;
   preview: Url[];
   isTimeOfDayWallpaper?: boolean;
+  hasPreviewImage?: boolean;
 }
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
index 8347cb46..f575f6f 100644
--- a/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
+++ b/ash/webui/personalization_app/resources/js/wallpaper/wallpaper_images_element.ts
@@ -62,7 +62,9 @@
   const tileMap = images.reduce((result, next) => {
     if (result.has(next.unitId)) {
       const tile = result.get(next.unitId)! as ImageTile;
-      tile.preview.push(next.url);
+      if (!tile.hasPreviewImage) {
+        tile.preview.push(next.url);
+      }
     } else {
       result.set(next.unitId, {
         preview: [next.url],
@@ -91,6 +93,12 @@
         tile.assetId = next.assetId;
         tile.attribution = next.attribution;
         break;
+      case OnlineImageType.kPreview:
+        tile.hasPreviewImage = true;
+        tile.preview = [next.url];
+        tile.assetId = next.assetId;
+        tile.attribution = next.attribution;
+        break;
       case OnlineImageType.kUnknown:
         tile.assetId = next.assetId;
         tile.attribution = next.attribution;
diff --git a/ash/wm/container_finder.cc b/ash/wm/container_finder.cc
index b5e2db1..dfe2c28f 100644
--- a/ash/wm/container_finder.cc
+++ b/ash/wm/container_finder.cc
@@ -23,8 +23,9 @@
 namespace {
 
 aura::Window* FindContainerRoot(const gfx::Rect& bounds_in_screen) {
-  if (bounds_in_screen == gfx::Rect())
+  if (bounds_in_screen == gfx::Rect()) {
     return Shell::GetRootWindowForNewWindows();
+  }
   return window_util::GetRootWindowMatching(bounds_in_screen);
 }
 
@@ -42,8 +43,9 @@
   // If |window| is already in a system modal container in |root|, re-use it.
   for (auto modal_container_id : kSystemModalContainerIds) {
     aura::Window* modal_container = root->GetChildById(modal_container_id);
-    if (window->parent() == modal_container)
+    if (window->parent() == modal_container) {
       return modal_container;
+    }
   }
 
   aura::Window* transient_parent = ::wm::GetTransientParent(window);
@@ -60,8 +62,9 @@
   // Otherwise those that originate from LockScreen container and above are
   // placed in the screen lock modal container.
   int window_container_id = transient_parent->parent()->GetId();
-  if (window_container_id < kShellWindowId_LockScreenContainer)
+  if (window_container_id < kShellWindowId_LockScreenContainer) {
     return root->GetChildById(kShellWindowId_SystemModalContainer);
+  }
   return root->GetChildById(kShellWindowId_LockSystemModalContainer);
 }
 
@@ -77,8 +80,9 @@
 aura::Window* GetContainerForWindow(aura::Window* window) {
   aura::Window* parent = window->parent();
   // The first parent with an explicit shell window ID is the container.
-  while (parent && parent->GetId() == kShellWindowId_Invalid)
+  while (parent && parent->GetId() == kShellWindowId_Invalid) {
     parent = parent->parent();
+  }
   return parent;
 }
 
@@ -99,8 +103,9 @@
   // can be retrieved. An example would be ARC windows, which can be created
   // before their associated tasks are, which are required to retrieve window
   // restore data.
-  if (window->GetProperty(app_restore::kParentToHiddenContainerKey))
+  if (window->GetProperty(app_restore::kParentToHiddenContainerKey)) {
     return target_root->GetChildById(kShellWindowId_UnparentedContainer);
+  }
 
   // Use kShellWindowId_DragImageAndTooltipContainer to host security surfaces
   // so that they are on top of other normal widgets (top-level windows, menus,
@@ -114,10 +119,13 @@
   switch (window->GetType()) {
     case aura::client::WINDOW_TYPE_NORMAL:
     case aura::client::WINDOW_TYPE_POPUP:
-      if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM)
+      if (window->GetProperty(aura::client::kModalKey) ==
+          ui::MODAL_TYPE_SYSTEM) {
         return GetSystemModalContainer(target_root, window);
-      if (HasTransientParentWindow(window))
+      }
+      if (HasTransientParentWindow(window)) {
         return GetContainerForWindow(transient_parent);
+      }
       return GetContainerFromAlwaysOnTopController(target_root, window);
     case aura::client::WINDOW_TYPE_CONTROL:
       return target_root->GetChildById(kShellWindowId_UnparentedContainer);
@@ -140,13 +148,15 @@
   aura::Window::Windows containers;
   for (aura::Window* root : Shell::GetAllRootWindows()) {
     aura::Window* container = root->GetChildById(container_id);
-    if (!container)
+    if (!container) {
       continue;
+    }
 
-    if (priority_root && priority_root->Contains(container))
+    if (priority_root && priority_root->Contains(container)) {
       containers.insert(containers.begin(), container);
-    else
+    } else {
       containers.push_back(container);
+    }
   }
   return containers;
 }
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index 192be8a..e17f94d 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -521,7 +521,10 @@
 
   if (features::IsDarkLightModeEnabled()) {
     SetBorder(std::make_unique<views::HighlightBorder>(
-        /*corner_radius=*/0, views::HighlightBorder::Type::kHighlightBorder2,
+        /*corner_radius=*/0,
+        chromeos::features::IsJellyrollEnabled()
+            ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+            : views::HighlightBorder::Type::kHighlightBorder2,
         /*use_light_colors=*/false));
   }
 
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc
index 534aa209..888056af 100644
--- a/ash/wm/desks/templates/saved_desk_item_view.cc
+++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -33,6 +33,7 @@
 #include "base/i18n/time_formatting.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -138,7 +139,10 @@
       .SetBackground(views::CreateThemedRoundedRectBackground(
           cros_tokens::kCrosSysSystemBaseElevated, kCornerRadius))
       .SetBorder(std::make_unique<views::HighlightBorder>(
-          kCornerRadius, views::HighlightBorder::Type::kHighlightBorder1,
+          kCornerRadius,
+          chromeos::features::IsJellyrollEnabled()
+              ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+              : views::HighlightBorder::Type::kHighlightBorder1,
           /*use_light_colors=*/false))
       // TODO(b/274025495): Update Shadow for SavedDeskItemView.
       .AddChildren(
diff --git a/ash/wm/desks/templates/saved_desk_save_desk_button.cc b/ash/wm/desks/templates/saved_desk_save_desk_button.cc
index 68740855..a1d3b91 100644
--- a/ash/wm/desks/templates/saved_desk_save_desk_button.cc
+++ b/ash/wm/desks/templates/saved_desk_save_desk_button.cc
@@ -9,6 +9,7 @@
 #include "ash/style/style_util.h"
 #include "ash/wm/overview/overview_constants.h"
 #include "ash/wm/overview/overview_utils.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/gfx/vector_icon_types.h"
 #include "ui/views/controls/focus_ring.h"
@@ -39,7 +40,9 @@
   if (features::IsDarkLightModeEnabled()) {
     SetBorder(std::make_unique<views::HighlightBorder>(
         /*corner_radius=*/kCornerRadius,
-        views::HighlightBorder::Type::kHighlightBorder1,
+        chromeos::features::IsJellyrollEnabled()
+            ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+            : views::HighlightBorder::Type::kHighlightBorder2,
         /*use_light_colors=*/false));
   }
 }
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index 6f6e3f49..23ce672 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -235,7 +235,10 @@
 
     if (chromeos::features::IsDarkLightModeEnabled()) {
       divider_view_->SetBorder(std::make_unique<views::HighlightBorder>(
-          /*corner_radius=*/0, views::HighlightBorder::Type::kHighlightBorder1,
+          /*corner_radius=*/0,
+          chromeos::features::IsJellyrollEnabled()
+              ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+              : views::HighlightBorder::Type::kHighlightBorder1,
           /*use_light_colors=*/false));
     }
   }
diff --git a/ash/wm/splitview/split_view_highlight_view.cc b/ash/wm/splitview/split_view_highlight_view.cc
index 8f101618..e92faeb 100644
--- a/ash/wm/splitview/split_view_highlight_view.cc
+++ b/ash/wm/splitview/split_view_highlight_view.cc
@@ -64,6 +64,14 @@
   SetBackground(views::CreateRoundedRectBackground(
       AshColorProvider::Get()->GetBackgroundColor(),
       kHighlightScreenRoundRectRadius));
+  if (chromeos::features::IsDarkLightModeEnabled()) {
+    SetBorder(std::make_unique<views::HighlightBorder>(
+        kHighlightScreenRoundRectRadius,
+        chromeos::features::IsJellyrollEnabled()
+            ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+            : views::HighlightBorder::Type::kHighlightBorder1,
+        /*use_light_colors=*/false));
+  }
   layer()->SetFillsBoundsOpaquely(false);
   layer()->SetRoundedCornerRadius(
       gfx::RoundedCornersF{kHighlightScreenRoundRectRadius});
@@ -76,12 +84,6 @@
   views::View::OnThemeChanged();
   background()->SetNativeControlColor(
       AshColorProvider::Get()->GetBackgroundColor());
-  if (chromeos::features::IsDarkLightModeEnabled()) {
-    SetBorder(std::make_unique<views::HighlightBorder>(
-        kHighlightScreenRoundRectRadius,
-        views::HighlightBorder::Type::kHighlightBorder1,
-        /*use_light_colors=*/false));
-  }
 }
 
 void SplitViewHighlightView::SetBounds(
@@ -188,12 +190,6 @@
 
   background()->SetNativeControlColor(
       AshColorProvider::Get()->GetBackgroundColor());
-  if (chromeos::features::IsDarkLightModeEnabled()) {
-    SetBorder(std::make_unique<views::HighlightBorder>(
-        kHighlightScreenRoundRectRadius,
-        views::HighlightBorder::Type::kHighlightBorder1,
-        /*use_light_colors=*/false));
-  }
 
   if (preview_position != SplitViewController::SnapPosition::kNone) {
     DoSplitviewOpacityAnimation(
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
index 9ae967d..5cde3d1 100644
--- a/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
+++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu.cc
@@ -18,6 +18,7 @@
 #include "ash/wm/window_state.h"
 #include "base/cxx17_backports.h"
 #include "base/functional/bind.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_metrics.h"
 #include "chromeos/ui/frame/multitask_menu/multitask_menu_view.h"
 #include "chromeos/ui/frame/multitask_menu/split_button_view.h"
@@ -70,7 +71,10 @@
     SetBackground(views::CreateThemedRoundedRectBackground(
         kColorAshShieldAndBaseOpaque, kCornerRadius));
     SetBorder(std::make_unique<views::HighlightBorder>(
-        kCornerRadius, views::HighlightBorder::Type::kHighlightBorder1,
+        kCornerRadius,
+        chromeos::features::IsJellyrollEnabled()
+            ? views::HighlightBorder::Type::kHighlightBorderOnShadow
+            : views::HighlightBorder::Type::kHighlightBorder1,
         /*use_light_colors=*/false));
 
     SetUseDefaultFillLayout(true);
@@ -104,7 +108,7 @@
 
     menu_view_base_ =
         AddChildView(std::make_unique<chromeos::MultitaskMenuView>(
-            window, std::move(callback), buttons));
+            window, std::move(callback), buttons, /*anchor_view=*/nullptr));
 
     // base::Unretained() is safe since `this` also destroys `menu_view_base_`
     // and its child `feedback_button_`.
diff --git a/ash/wm/window_cycle/window_cycle_view.cc b/ash/wm/window_cycle/window_cycle_view.cc
index 6e0d8ca..4737daae 100644
--- a/ash/wm/window_cycle/window_cycle_view.cc
+++ b/ash/wm/window_cycle/window_cycle_view.cc
@@ -125,7 +125,10 @@
   SetBackground(views::CreateThemedRoundedRectBackground(
       cros_tokens::kCrosSysScrim2, kBackgroundCornerRadius));
   SetBorder(std::make_unique<views::HighlightBorder>(
-      kBackgroundCornerRadius, views::HighlightBorder::Type::kHighlightBorder1,
+      kBackgroundCornerRadius,
+      chromeos::features::IsJellyrollEnabled()
+          ? views::HighlightBorder::Type::kHighlightBorderOnShadow
+          : views::HighlightBorder::Type::kHighlightBorder1,
       /*use_light_colors=*/false));
 
   // |mirror_container_| may be larger than |this|. In this case, it will be
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index 88705c40..6bb22e4 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/style/ash_color_id.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/wm/window_util.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer.h"
@@ -210,7 +211,9 @@
               kColorAshShieldAndBase20, kPhantomWindowCornerRadius))
           .SetBorder(std::make_unique<views::HighlightBorder>(
               kPhantomWindowCornerRadius,
-              views::HighlightBorder::Type::kHighlightBorder1,
+              chromeos::features::IsJellyrollEnabled()
+                  ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+                  : views::HighlightBorder::Type::kHighlightBorder1,
               /*use_light_colors=*/false))
           .Build());
   return phantom_widget;
@@ -251,7 +254,9 @@
               kColorAshShieldAndBase20, kPhantomWindowCornerRadius))
           .SetBorder(std::make_unique<views::HighlightBorder>(
               kPhantomWindowCornerRadius,
-              views::HighlightBorder::Type::kHighlightBorder1,
+              chromeos::features::IsJellyrollEnabled()
+                  ? views::HighlightBorder::Type::kHighlightBorderNoShadow
+                  : views::HighlightBorder::Type::kHighlightBorder1,
               /*use_light_colors=*/false))
           .AddChildren(
               views::Builder<views::Label>()
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 6272b36..7a814bf 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -336,6 +336,38 @@
         }
     }
 
+    /**
+     * Sets the bottom handwriting bounds offset of the given view to 0.
+     * See https://crbug.com/1427112
+     * @param view The view on which to set the handwriting bounds.
+     */
+    @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class)
+    public static void clearHandwritingBoundsOffsetBottom(View view) {
+        // TODO(crbug.com/1427112): Replace uses of this method with direct calls once the API is
+        // available.
+        if (!BuildCompat.isAtLeastU()) return;
+        // Set the bottom handwriting bounds offset to 0 so that the view doesn't intercept
+        // stylus events meant for the web contents.
+        try {
+            // float offsetTop = this.getHandwritingBoundsOffsetTop();
+            float offsetTop =
+                    (float) View.class.getMethod("getHandwritingBoundsOffsetTop").invoke(view);
+            // float offsetLeft = this.getHandwritingBoundsOffsetLeft();
+            float offsetLeft =
+                    (float) View.class.getMethod("getHandwritingBoundsOffsetLeft").invoke(view);
+            // float offsetRight = this.getHandwritingBoundsOffsetRight();
+            float offsetRight =
+                    (float) View.class.getMethod("getHandwritingBoundsOffsetRight").invoke(view);
+            // this.setHandwritingBoundsOffsets(offsetLeft, offsetTop, offsetRight, 0);
+            Method setHandwritingBoundsOffsets = View.class.getMethod("setHandwritingBoundsOffsets",
+                    float.class, float.class, float.class, float.class);
+            setHandwritingBoundsOffsets.invoke(view, offsetLeft, offsetTop, offsetRight, 0);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException
+                | NullPointerException e) {
+            // Do nothing.
+        }
+    }
+
     // Access this via ContextUtils.getProcessName().
     @SuppressWarnings("PrivateApi")
     static String getProcessName() {
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
index 96abf52..bd1b5fd8 100644
--- a/base/message_loop/message_pump_default.cc
+++ b/base/message_loop/message_pump_default.cc
@@ -20,14 +20,6 @@
 
 namespace base {
 
-namespace {
-
-#if BUILDFLAG(IS_APPLE)
-bool g_use_thread_qos = true;
-#endif
-
-}  // namespace
-
 MessagePumpDefault::MessagePumpDefault()
     : keep_running_(true),
       event_(WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -89,38 +81,4 @@
   // this way (bit.ly/merge-message-pump-do-work).
 }
 
-#if BUILDFLAG(IS_APPLE)
-void MessagePumpDefault::SetTimerSlack(TimerSlack timer_slack) {
-  if (!g_use_thread_qos) {
-    thread_latency_qos_policy_data_t policy{};
-    policy.thread_latency_qos_tier = timer_slack == TIMER_SLACK_MAXIMUM
-                                         ? LATENCY_QOS_TIER_3
-                                         : LATENCY_QOS_TIER_UNSPECIFIED;
-    mac::ScopedMachSendRight thread_port(mach_thread_self());
-    kern_return_t kr =
-        thread_policy_set(thread_port.get(), THREAD_LATENCY_QOS_POLICY,
-                          reinterpret_cast<thread_policy_t>(&policy),
-                          THREAD_LATENCY_QOS_POLICY_COUNT);
-    MACH_DVLOG_IF(1, kr != KERN_SUCCESS, kr) << "thread_policy_set";
-  }
-}
-
-// static
-void MessagePumpDefault::InitFeaturesPostFieldTrial() {
-  // Since kUseThreadQoSMac is not constexpr (forbidden for Features), it cannot
-  // be used to initialize |g_use_thread_qos| at compile time. At least DCHECK
-  // that its initial value matches the default value of the feature here.
-  DCHECK_EQ(g_use_thread_qos,
-            kUseThreadQoSMac.default_state == FEATURE_ENABLED_BY_DEFAULT);
-
-  // A DCHECK is triggered on FeatureList initialization if the state of a
-  // feature has been checked before. To avoid triggering this DCHECK in unit
-  // tests that call this before initializing the FeatureList, only check the
-  // state of the feature if the FeatureList is initialized.
-  if (FeatureList::GetInstance()) {
-    g_use_thread_qos = FeatureList::IsEnabled(kUseThreadQoSMac);
-  }
-}
-#endif
-
 }  // namespace base
diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h
index ac46ffb..c8f7274 100644
--- a/base/message_loop/message_pump_default.h
+++ b/base/message_loop/message_pump_default.h
@@ -28,11 +28,6 @@
   void ScheduleWork() override;
   void ScheduleDelayedWork(
       const Delegate::NextWorkInfo& next_work_info) override;
-#if BUILDFLAG(IS_APPLE)
-  void SetTimerSlack(TimerSlack timer_slack) override;
-
-  static void InitFeaturesPostFieldTrial();
-#endif
 
  private:
   // This flag is set to false when Run should return.
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
index cc8f9ee..caee345 100644
--- a/base/metrics/histogram_samples.cc
+++ b/base/metrics/histogram_samples.cc
@@ -83,7 +83,7 @@
 
 HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Load()
     const {
-  AtomicSingleSample single_sample = subtle::Acquire_Load(&as_atomic);
+  AtomicSingleSample single_sample(subtle::Acquire_Load(&as_atomic));
 
   // If the sample was extracted/disabled, it's still zero to the outside.
   if (single_sample.as_atomic == kDisabledSingleSample)
@@ -93,12 +93,48 @@
 }
 
 HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Extract(
-    bool disable) {
-  AtomicSingleSample single_sample = subtle::NoBarrier_AtomicExchange(
-      &as_atomic, disable ? kDisabledSingleSample : 0);
-  if (single_sample.as_atomic == kDisabledSingleSample)
-    single_sample.as_atomic = 0;
-  return single_sample.as_parts;
+    AtomicSingleSample new_value) {
+  DCHECK(new_value.as_atomic != kDisabledSingleSample)
+      << "Disabling an AtomicSingleSample should be done through "
+         "ExtractAndDisable().";
+
+  AtomicSingleSample old_value;
+
+  // Because a concurrent call may modify and/or disable this object as we are
+  // trying to extract its value, a compare-and-swap loop must be done to ensure
+  // that the value was not changed between the reading and writing (and to
+  // prevent accidentally re-enabling this object).
+  while (true) {
+    old_value.as_atomic = subtle::Acquire_Load(&as_atomic);
+
+    // If this object was already disabled, return an empty sample and keep it
+    // disabled.
+    if (old_value.as_atomic == kDisabledSingleSample) {
+      old_value.as_atomic = 0;
+      return old_value.as_parts;
+    }
+
+    // Extract the single-sample from memory. |existing| is what was in that
+    // memory location at the time of the call; if it doesn't match |original|
+    // (i.e., the single-sample was concurrently modified during this
+    // iteration), then the swap did not happen, so try again.
+    subtle::Atomic32 existing = subtle::Release_CompareAndSwap(
+        &as_atomic, old_value.as_atomic, new_value.as_atomic);
+    if (existing == old_value.as_atomic) {
+      return old_value.as_parts;
+    }
+  }
+}
+
+HistogramSamples::SingleSample
+HistogramSamples::AtomicSingleSample::ExtractAndDisable() {
+  AtomicSingleSample old_value(
+      subtle::NoBarrier_AtomicExchange(&as_atomic, kDisabledSingleSample));
+  // If this object was already disabled, return an empty sample.
+  if (old_value.as_atomic == kDisabledSingleSample) {
+    old_value.as_atomic = 0;
+  }
+  return old_value.as_parts;
 }
 
 bool HistogramSamples::AtomicSingleSample::Accumulate(
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index 28e669e..a54196e 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -50,17 +50,23 @@
   // acquire/release operations to guarantee ordering with outside values.
   union BASE_EXPORT AtomicSingleSample {
     AtomicSingleSample() : as_atomic(0) {}
-    AtomicSingleSample(subtle::Atomic32 rhs) : as_atomic(rhs) {}
+    explicit AtomicSingleSample(subtle::Atomic32 rhs) : as_atomic(rhs) {}
 
     // Returns the single sample in an atomic manner. This in an "acquire"
     // load. The returned sample isn't shared and thus its fields can be safely
-    // accessed.
+    // accessed. If this object is disabled, this will return an empty sample
+    // (bucket count set to 0).
     SingleSample Load() const;
 
-    // Extracts the single sample in an atomic manner. If |disable| is true
-    // then this object will be set so it will never accumulate another value.
-    // This is "no barrier" so doesn't enforce ordering with other atomic ops.
-    SingleSample Extract(bool disable);
+    // Extracts and returns the single sample and changes it to |new_value| in
+    // an atomic manner. If this object is disabled, this will return an empty
+    // sample (bucket count set to 0).
+    SingleSample Extract(AtomicSingleSample new_value = AtomicSingleSample(0));
+
+    // Like Extract() above, but also disables this object so that it will
+    // never accumulate another value. If this object is already disabled, this
+    // will return an empty sample (bucket count set to 0).
+    SingleSample ExtractAndDisable();
 
     // Adds a given count to the held bucket. If not possible, it returns false
     // and leaves the parts unchanged. Once extracted/disabled, this always
diff --git a/base/metrics/histogram_samples_unittest.cc b/base/metrics/histogram_samples_unittest.cc
index 2603e21..9b70c9f 100644
--- a/base/metrics/histogram_samples_unittest.cc
+++ b/base/metrics/histogram_samples_unittest.cc
@@ -25,33 +25,44 @@
   s = sample.Load();
   EXPECT_EQ(9U, s.bucket);
   EXPECT_EQ(1U, s.count);
+
+  ASSERT_TRUE(sample.Accumulate(9, 1));
+  s = sample.Load();
+  EXPECT_EQ(9U, s.bucket);
+  EXPECT_EQ(2U, s.count);
 }
 
 TEST(SingleSampleTest, Extract) {
   AtomicSingleSample sample;
   ASSERT_TRUE(sample.Accumulate(9, 1));
 
-  SingleSample s = sample.Extract(/*disable=*/false);
+  SingleSample s = sample.Extract();
   EXPECT_EQ(9U, s.bucket);
   EXPECT_EQ(1U, s.count);
 
-  s = sample.Extract(/*disable=*/false);
+  s = sample.Extract();
   EXPECT_EQ(0U, s.bucket);
   EXPECT_EQ(0U, s.count);
+
+  ASSERT_TRUE(sample.Accumulate(1, 2));
+  s = sample.Extract();
+  EXPECT_EQ(1U, s.bucket);
+  EXPECT_EQ(2U, s.count);
 }
 
 TEST(SingleSampleTest, Disable) {
   AtomicSingleSample sample;
-  EXPECT_EQ(0U, sample.Extract(/*disable=*/false).count);
+  EXPECT_EQ(0U, sample.Extract().count);
   EXPECT_FALSE(sample.IsDisabled());
 
   ASSERT_TRUE(sample.Accumulate(9, 1));
-  EXPECT_EQ(1U, sample.Extract(/*disable=*/true).count);
+  EXPECT_EQ(1U, sample.ExtractAndDisable().count);
   EXPECT_TRUE(sample.IsDisabled());
 
   ASSERT_FALSE(sample.Accumulate(9, 1));
-  EXPECT_EQ(0U, sample.Extract(/*disable=*/false).count);
-  EXPECT_FALSE(sample.IsDisabled());
+  EXPECT_EQ(0U, sample.Extract().count);
+  // The sample should still be disabled.
+  EXPECT_TRUE(sample.IsDisabled());
 }
 
 TEST(SingleSampleTest, Accumulate) {
@@ -60,12 +71,14 @@
   ASSERT_TRUE(sample.Accumulate(9, 1));
   ASSERT_TRUE(sample.Accumulate(9, 2));
   ASSERT_TRUE(sample.Accumulate(9, 4));
-  EXPECT_EQ(7U, sample.Extract(/*disable=*/false).count);
+  ASSERT_FALSE(sample.Accumulate(10, 1));
+  EXPECT_EQ(7U, sample.Extract().count);
 
   ASSERT_TRUE(sample.Accumulate(9, 4));
   ASSERT_TRUE(sample.Accumulate(9, -2));
   ASSERT_TRUE(sample.Accumulate(9, 1));
-  EXPECT_EQ(3U, sample.Extract(/*disable=*/false).count);
+  ASSERT_FALSE(sample.Accumulate(10, 1));
+  EXPECT_EQ(3U, sample.Extract().count);
 }
 
 TEST(SingleSampleTest, Overflow) {
@@ -73,12 +86,11 @@
 
   ASSERT_TRUE(sample.Accumulate(9, 1));
   ASSERT_FALSE(sample.Accumulate(9, -2));
-  EXPECT_EQ(1U, sample.Extract(/*disable=*/false).count);
+  EXPECT_EQ(1U, sample.Extract().count);
 
   ASSERT_TRUE(sample.Accumulate(9, std::numeric_limits<uint16_t>::max()));
   ASSERT_FALSE(sample.Accumulate(9, 1));
-  EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
-            sample.Extract(/*disable=*/false).count);
+  EXPECT_EQ(std::numeric_limits<uint16_t>::max(), sample.Extract().count);
 }
 
 }  // namespace base
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
index 47177e0..ea0f08f 100644
--- a/base/metrics/sample_vector.cc
+++ b/base/metrics/sample_vector.cc
@@ -269,7 +269,7 @@
   DCHECK(counts());
 
   // Disable the single-sample since there is now counts storage for the data.
-  SingleSample sample = single_sample().Extract(/*disable=*/true);
+  SingleSample sample = single_sample().ExtractAndDisable();
 
   // Stop here if there is no "count" as trying to find the bucket index of
   // an invalid (including zero) "value" will crash.
diff --git a/base/threading/hang_watcher.cc b/base/threading/hang_watcher.cc
index e50e540c..f55bcc8 100644
--- a/base/threading/hang_watcher.cc
+++ b/base/threading/hang_watcher.cc
@@ -647,11 +647,17 @@
 ScopedClosureRunner HangWatcher::RegisterThreadInternal(
     ThreadType thread_type) {
   AutoLock auto_lock(watch_state_lock_);
+  CHECK(base::FeatureList::GetInstance());
+
+  // Do not install a WatchState if the results would never be observable.
+  if (!ThreadTypeLoggingLevelGreaterOrEqual(thread_type,
+                                            LoggingLevel::kUmaOnly)) {
+    return ScopedClosureRunner(base::DoNothing());
+  }
 
   watch_states_.push_back(
       internal::HangWatchState::CreateHangWatchStateForCurrentThread(
           thread_type));
-
   return ScopedClosureRunner(BindOnce(&HangWatcher::UnregisterThread,
                                       Unretained(HangWatcher::GetInstance())));
 }
diff --git a/base/threading/hang_watcher_unittest.cc b/base/threading/hang_watcher_unittest.cc
index dd71c7f..badffab 100644
--- a/base/threading/hang_watcher_unittest.cc
+++ b/base/threading/hang_watcher_unittest.cc
@@ -778,6 +778,9 @@
 class HangWatcherPeriodicMonitoringTest : public testing::Test {
  public:
   HangWatcherPeriodicMonitoringTest() {
+    hang_watcher_.InitializeOnMainThread(
+        HangWatcher::ProcessType::kBrowserProcess);
+
     hang_watcher_.SetMonitoringPeriodForTesting(kMonitoringPeriod);
     hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
         &WaitableEvent::Signal, base::Unretained(&hang_event_)));
@@ -793,6 +796,8 @@
   HangWatcherPeriodicMonitoringTest& operator=(
       const HangWatcherPeriodicMonitoringTest& other) = delete;
 
+  void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
+
  protected:
   // Setup the callback invoked after waiting in HangWatcher to advance the
   // tick clock by the desired time delta.
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index 54515dc9..fa192b70 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -93,8 +93,6 @@
 #endif
 );
 
-const Feature kUseThreadQoSMac{"UseThreadQoSMac", FEATURE_ENABLED_BY_DEFAULT};
-
 namespace {
 
 bool IsOptimizedRealtimeThreadingMacEnabled() {
@@ -143,8 +141,6 @@
 std::atomic<bool> g_use_optimized_realtime_threading(
     kOptimizedRealtimeThreadingMac.default_state == FEATURE_ENABLED_BY_DEFAULT);
 std::atomic<TimeConstraints> g_time_constraints;
-std::atomic<bool> g_use_thread_qos(kUseThreadQoSMac.default_state ==
-                                   FEATURE_ENABLED_BY_DEFAULT);
 
 }  // namespace
 
@@ -158,7 +154,6 @@
     g_time_constraints.store(TimeConstraints::ReadFromFeatureParams());
     g_use_optimized_realtime_threading.store(
         IsOptimizedRealtimeThreadingMacEnabled());
-    g_use_thread_qos.store(FeatureList::IsEnabled(kUseThreadQoSMac));
   }
 }
 
@@ -299,7 +294,6 @@
 
 void SetCurrentThreadTypeImpl(ThreadType thread_type,
                               MessagePumpType pump_type_hint) {
-  const bool use_thread_qos = g_use_thread_qos.load(std::memory_order_relaxed);
   // Changing the priority of the main thread causes performance
   // regressions. https://crbug.com/601270
   // TODO(1280764): Remove this check. kCompositing is the default on Mac, so
@@ -315,54 +309,27 @@
   switch (thread_type) {
     case ThreadType::kBackground:
       priority = ThreadPriorityForTest::kBackground;
-      if (use_thread_qos)
-        pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
-      else
-        [[NSThread currentThread] setThreadPriority:0];
+      pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
       break;
     case ThreadType::kUtility:
       priority = ThreadPriorityForTest::kUtility;
-      if (use_thread_qos)
-        pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
-      else
-        [[NSThread currentThread] setThreadPriority:0.5];
+      pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
       break;
     case ThreadType::kResourceEfficient:
-      if (use_thread_qos) {
-        priority = ThreadPriorityForTest::kUtility;
-        pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
-        break;
-      }
-      [[fallthrough]];
+      priority = ThreadPriorityForTest::kUtility;
+      pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
+      break;
     case ThreadType::kDefault:
       // TODO(1329208): Experiment with prioritizing kCompositing on Mac like on
       // other platforms.
       [[fallthrough]];
     case ThreadType::kCompositing:
       priority = ThreadPriorityForTest::kNormal;
-      if (use_thread_qos)
-        pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
-      else
-        [[NSThread currentThread] setThreadPriority:0.5];
+      pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
       break;
     case ThreadType::kDisplayCritical: {
       priority = ThreadPriorityForTest::kDisplay;
-      if (use_thread_qos) {
-        pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
-      } else {
-        // Apple has suggested that insufficient priority may be the reason for
-        // Metal shader compilation hangs. A priority of 50 is higher than user
-        // input.
-        // https://crbug.com/974219.
-        [[NSThread currentThread] setThreadPriority:1.0];
-        sched_param param;
-        int policy;
-        pthread_t thread = pthread_self();
-        if (!pthread_getschedparam(thread, &policy, &param)) {
-          param.sched_priority = 50;
-          pthread_setschedparam(thread, policy, &param);
-        }
-      }
+      pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
       break;
     }
     case ThreadType::kRealtimeAudio:
diff --git a/base/values.cc b/base/values.cc
index d8353335..909d93a9 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1285,10 +1285,6 @@
   return GetDict().SetByDottedPath(path, std::move(value));
 }
 
-Value* Value::SetDoublePath(StringPiece path, double value) {
-  return GetDict().SetByDottedPath(path, value);
-}
-
 Value* Value::SetStringPath(StringPiece path, StringPiece value) {
   return GetDict().SetByDottedPath(path, value);
 }
diff --git a/base/values.h b/base/values.h
index e1c4cf8..0ff64447 100644
--- a/base/values.h
+++ b/base/values.h
@@ -874,8 +874,6 @@
   // SetPath(...) call.
   //
   // DEPRECATED: Use `Value::Dict::SetByDottedPath()`.
-  Value* SetDoublePath(StringPiece path, double value);
-  // DEPRECATED: Use `Value::Dict::SetByDottedPath()`.
   Value* SetStringPath(StringPiece path, StringPiece value);
   // DEPRECATED: Use `Value::Dict::SetByDottedPath()`.
   Value* SetStringPath(StringPiece path, const char* value);
diff --git a/build/config/rust.gni b/build/config/rust.gni
index f6e50771..2f4fe215 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -47,6 +47,13 @@
   # on supported platforms and GN targets.
   enable_local_libstd = true
 
+  # When true, uses the locally-built std in all Rust targets.
+  #
+  # As an internal implementation detail this can be overridden on specific
+  # targets (e.g. to run build.rs scripts while building std), but this
+  # generally should not be done.
+  use_local_std_by_default = false
+
   # Chromium currently has a Rust toolchain for Android and Linux, but
   # if you wish to experiment on more platforms you can use this
   # argument to specify an alternative toolchain.
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index cb916829..ea5abd8 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-12.20230324.2.1
+12.20230324.3.1
diff --git a/build/rust/BUILD.gn b/build/rust/BUILD.gn
index d7dd1e9..01831d15 100644
--- a/build/rust/BUILD.gn
+++ b/build/rust/BUILD.gn
@@ -41,10 +41,13 @@
     # on any first-party Rust target. But in this case, it's conceivable
     # that pure-C++ targets will not depend on any 1p Rust code so we'll add
     # the Rust stdlib explicitly.
-    deps = [
-      ":cxx_rustdeps",
-      "//build/rust/std",
-    ]
+    deps = [ ":cxx_rustdeps" ]
+
+    if (use_local_std_by_default) {
+      deps += [ "//build/rust/std:link_local_std" ]
+    } else {
+      deps += [ "//build/rust/std:link_prebuilt_std" ]
+    }
   }
 
   # The required dependencies for cxx-generated bindings, that must be included
diff --git a/build/rust/rust_target.gni b/build/rust/rust_target.gni
index 7ded1fcc..a0ddfc27 100644
--- a/build/rust/rust_target.gni
+++ b/build/rust/rust_target.gni
@@ -100,6 +100,11 @@
     _visibility = invoker.visibility
   }
 
+  _use_local_std = use_local_std_by_default
+  if (defined(invoker.use_local_std)) {
+    _use_local_std = invoker.use_local_std
+  }
+
   _rustflags = []
   if (defined(invoker.rustflags)) {
     _rustflags += invoker.rustflags
@@ -220,6 +225,7 @@
                  "_support_use_from_cpp",
                  "_test_deps",
                  "_testonly",
+                 "_use_local_std",
                  "_visibility",
                ])
   } else {
@@ -241,11 +247,21 @@
         # target that depends on a rust target directly may need access to Cxx
         # as well, which means it must appear in public_deps.
         public_deps += [ "//build/rust:cxx_cppdeps" ]
+
+        # cxx_cppdeps pulls in the default libstd, so make sure the default was
+        # not overridden.
+        assert(
+            _use_local_std == use_local_std_by_default,
+            "Rust targets with cxx bindings cannot override the default libstd")
       } else if (!defined(invoker.no_std) || !invoker.no_std) {
         # If C++ depends on and links in the library, we need to make sure C++
         # links in the Rust stdlib. This is orthogonal to if the library exports
         # bindings for C++ to use.
-        deps = [ "//build/rust/std" ]
+        if (_use_local_std) {
+          deps = [ "//build/rust/std:link_local_std" ]
+        } else {
+          deps = [ "//build/rust/std:link_prebuilt_std" ]
+        }
       }
     }
 
@@ -265,7 +281,13 @@
     }
 
     if (!defined(invoker.no_std) || !invoker.no_std) {
-      _rust_deps += [ "//build/rust/std:prebuilt_std_for_rustc" ]
+      if (_use_local_std) {
+        _rust_deps += [ "//build/rust/std:local_std_for_rustc" ]
+      } else {
+        _rust_deps += [ "//build/rust/std:prebuilt_std_for_rustc" ]
+      }
+    } else {
+      not_needed([ "_use_local_std" ])
     }
 
     # You must go through the groups above to get to these targets.
diff --git a/build/rust/std/BUILD.gn b/build/rust/std/BUILD.gn
index 2d47dfd6..c355f0b 100644
--- a/build/rust/std/BUILD.gn
+++ b/build/rust/std/BUILD.gn
@@ -229,11 +229,30 @@
     deps = [ ":prebuilt_rustc_sysroot" ]
   }
 
-  config("rust_stdlib_config") {
+  config("prebuilt_rust_stdlib_config") {
     ldflags = []
-    out_libdir = rebase_path(target_out_dir, root_build_dir)
+    lib_dir = rebase_path("$prebuilt_rustc_sysroot/$sysroot_lib_subdir",
+                          root_build_dir)
     foreach(lib, stdlib_files) {
-      this_file = "$out_libdir/lib$lib.rlib"
+      this_file = "$lib_dir/lib$lib.rlib"
+      ldflags += [ this_file ]
+    }
+    if (is_win) {
+      # Our C++ builds already link against a wide variety of Windows API import libraries,
+      # but the Rust stdlib requires a few extra.
+      ldflags += [
+        "bcrypt.lib",
+        "userenv.lib",
+      ]
+    }
+  }
+
+  config("local_rust_stdlib_config") {
+    ldflags = []
+    lib_dir =
+        rebase_path("$local_rustc_sysroot/$sysroot_lib_subdir", root_build_dir)
+    foreach(lib, stdlib_files) {
+      this_file = "$lib_dir/lib$lib.rlib"
       ldflags += [ this_file ]
     }
     if (is_win) {
@@ -255,14 +274,29 @@
 
   # TODO(crbug.com/1368806): rework this so when using locally-built std, we
   # don't link the prebuilt std as well.
-  group("std") {
+
+  # Provides std libs to non-rustc linkers.
+  group("link_prebuilt_std") {
     assert(
         enable_rust,
         "Some C++ target is including Rust code even though enable_rust=false")
-    all_dependent_configs = [ ":rust_stdlib_config" ]
+    all_dependent_configs = [ ":prebuilt_rust_stdlib_config" ]
     deps = [
-      ":find_stdlib",
+      ":prebuilt_rustc_sysroot",
       ":remap_alloc",
     ]
   }
+
+  if (local_libstd_supported) {
+    group("link_local_std") {
+      assert(
+          enable_rust,
+          "Some C++ target is including Rust code even though enable_rust=false")
+      all_dependent_configs = [ ":local_rust_stdlib_config" ]
+      deps = [
+        ":local_std_for_rustc",
+        ":remap_alloc",
+      ]
+    }
+  }
 }
diff --git a/build/rust/tests/test_local_std/BUILD.gn b/build/rust/tests/test_local_std/BUILD.gn
index 6d364c6..499aebd 100644
--- a/build/rust/tests/test_local_std/BUILD.gn
+++ b/build/rust/tests/test_local_std/BUILD.gn
@@ -12,23 +12,12 @@
   sources = [ "lib.rs" ]
   crate_root = "lib.rs"
   build_native_rust_unit_tests = true
-
-  # Override the normal stdlib.
-  #
-  # TODO(crbug.com/1368806): add a better switch for using the prebuilt std vs
-  # locally built std.
-  no_std = true
-  deps = [ "//build/rust/std:local_std_for_rustc" ]
+  use_local_std = true
 }
 
 rust_executable("test_local_std_exe") {
   sources = [ "main.rs" ]
   crate_root = "main.rs"
   deps = [ ":test_local_std" ]
-
-  # Override the normal stdlib.
-  #
-  # TODO(crbug.com/1368806): add a better switch for using the prebuilt std vs
-  # locally built std.
-  no_std = true
+  use_local_std = true
 }
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
index 5851d26..3d6bb56 100644
--- a/build/toolchain/linux/BUILD.gn
+++ b/build/toolchain/linux/BUILD.gn
@@ -181,6 +181,7 @@
 
 # In a LaCrOS build, this toolchain is intended to be used as an alternate
 # toolchain to build Ash-Chrome in a subdirectory.
+# This is a test-only toolchain.
 clang_toolchain("ash_clang_x64") {
   toolchain_args = {
     # This turns the toolchain into the "Linux ChromeOS" build
@@ -202,6 +203,7 @@
 
 # In an ash build, this toolchain is intended to be used as an alternate
 # toolchain to build lacros-Chrome in a subdirectory.
+# This is a test-only toolchain.
 clang_toolchain("lacros_clang_x64") {
   toolchain_args = {
     # This turns the toolchain into the "Lacros" build
@@ -214,7 +216,6 @@
     chromeos_is_browser_only = true
     use_clang_coverage = false
     dcheck_always_on = false
-    symbol_level = 1
   }
 }
 
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc
index e01cc7bf..31f117ea 100644
--- a/cc/input/input_handler.cc
+++ b/cc/input/input_handler.cc
@@ -1274,6 +1274,7 @@
     const ScrollTree& scroll_tree,
     ScrollNode* scroll_node) const {
   DCHECK(!base::FeatureList::IsEnabled(features::kScrollUnification));
+  DCHECK(scroll_node->transform_id != kInvalidPropertyNodeId);
 
   InputHandler::ScrollStatus scroll_status;
   scroll_status.main_thread_scrolling_reasons =
@@ -1616,6 +1617,10 @@
     const gfx::Vector2dF& viewport_delta,
     gfx::Vector2dF* out_local_scroll_delta,
     gfx::PointF* out_local_start_point /*= nullptr*/) {
+  if (scroll_node.transform_id == kInvalidPropertyNodeId) {
+    return false;
+  }
+
   // Layers with non-invertible screen space transforms should not have passed
   // the scroll hit test in the first place.
   const gfx::Transform screen_space_transform =
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index b33a8a3e..7ba0c8b 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1058,11 +1058,10 @@
       // animations, but that is not needed for an impl-side scroll.
 
       // Update the offset in the transform node.
-      DCHECK(scroll_node->transform_id != kInvalidPropertyNodeId);
       TransformTree& transform_tree =
           property_trees()->transform_tree_mutable();
       auto* transform_node = transform_tree.Node(scroll_node->transform_id);
-      if (transform_node->scroll_offset != new_offset) {
+      if (transform_node && transform_node->scroll_offset != new_offset) {
         transform_node->scroll_offset = new_offset;
         transform_node->needs_local_transform_update = true;
         transform_node->transform_changed = true;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index d5cb991..bafe3c6b 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -238,10 +238,13 @@
       !base::FeatureList::IsEnabled(features::kScrollUnification) ||
       scroll_tree.CanRealizeScrollsOnCompositor(*scroll_node);
 
-  DCHECK(scroll_node->transform_id != kInvalidPropertyNodeId);
-  TransformTree& transform_tree = property_trees()->transform_tree_mutable();
-  auto* transform_node = transform_tree.Node(scroll_node->transform_id);
-  if (should_realize_scroll_on_compositor) {
+  // A ScrollNode may have an invalid transform_id if its scroller is
+  // unpainted. Since an unpainted scroller would not be visible to the
+  // user, realizing this scroll is a nop.
+  if (should_realize_scroll_on_compositor &&
+      scroll_node->transform_id != kInvalidPropertyNodeId) {
+    TransformTree& transform_tree = property_trees()->transform_tree_mutable();
+    auto* transform_node = transform_tree.Node(scroll_node->transform_id);
     if (transform_node->scroll_offset !=
         scroll_tree.current_scroll_offset(id)) {
       transform_node->scroll_offset = scroll_tree.current_scroll_offset(id);
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 262b30c1e..e0483e1 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -346,19 +346,10 @@
   const ScrollNode* scroll_node =
       property_trees()->scroll_tree().Node(sticky_data->scroll_ancestor);
   const TransformNode* transform_node = Node(scroll_node->transform_id);
-  const auto& scroll_offset = transform_node->scroll_offset;
-  // TODO(crbug.com/1206694): Understand why these values are not exactly equal
-  // and which one we should be using here.
-#if DCHECK_IS_ON()
-  {
-    const auto& scroll_offset_delta =
-        property_trees()->scroll_tree().current_scroll_offset(
-            scroll_node->element_id) -
-        scroll_offset;
-    DCHECK_LE(std::abs(scroll_offset_delta.x()), 0.5);
-    DCHECK_LE(std::abs(scroll_offset_delta.y()), 0.5);
-  }
-#endif
+  DCHECK(transform_node);
+  gfx::PointF scroll_offset =
+      property_trees()->scroll_tree().current_scroll_offset(
+          scroll_node->element_id);
   gfx::PointF scroll_position(scroll_offset.x(), scroll_offset.y());
   if (transform_node->scrolls) {
     // The scroll position does not include snapping which shifts the scroll
@@ -514,6 +505,9 @@
       continue;
     }
     const TransformNode* transform_node = Node(scroll_node->transform_id);
+    // We don't ever expect that an anchor node or any of its scrolling
+    // containers should have an invalid transform_id.
+    DCHECK(scroll_node->transform_id != kInvalidPropertyNodeId);
     accumulated_scroll_offset +=
         transform_node->scroll_offset.OffsetFromOrigin();
   }
@@ -1614,7 +1608,7 @@
   // simply rounding of the scroll position and not using fractional scroll
   // deltas (see needs_scroll_update in PushScrollUpdatesFromMainThread).
 
-  if (transform_node->scrolls) {
+  if (transform_node && transform_node->scrolls) {
     // If necessary perform a update for this node to ensure snap amount is
     // accurate. This method is used by scroll timeline, so it is possible for
     // it to get called before transform tree has gone through a full update
diff --git a/chrome/VERSION b/chrome/VERSION
index 2887bf0..2c6dc18e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=114
 MINOR=0
-BUILD=5673
+BUILD=5674
 PATCH=0
diff --git a/chrome/android/java/res/layout/autofill_server_card_editor.xml b/chrome/android/java/res/layout/autofill_server_card_editor.xml
index 6cae0e8d..e5732d23 100644
--- a/chrome/android/java/res/layout/autofill_server_card_editor.xml
+++ b/chrome/android/java/res/layout/autofill_server_card_editor.xml
@@ -16,8 +16,8 @@
 
         <ImageView
             android:id="@+id/card_icon"
-            android:layout_width="@dimen/settings_page_card_icon_width"
-            android:layout_height="@dimen/settings_page_card_icon_height"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_alignParentStart="true"
             android:layout_centerVertical="true"
             android:layout_marginEnd="@dimen/settings_page_card_icon_end_margin"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index ed18ce7..928b987 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -400,12 +400,6 @@
     <!-- Price Drop dimensions -->
     <dimen name="price_drop_spotted_iph_ntp_tabswitcher_y_inset">4dp</dimen>
 
-    <!-- Settings page -->
-    <dimen name="settings_page_card_icon_width">32dp</dimen>
-    <dimen name="settings_page_card_icon_height">20dp</dimen>
-    <dimen name="settings_page_card_icon_end_margin">20dp</dimen>
-    <dimen name="settings_page_margin_between_card_name_and_last_four_digits">4dp</dimen>
-
     <!-- Card Unmask dialog -->
     <dimen name="card_unmask_dialog_credit_card_icon_width">32dp</dimen>
     <dimen name="card_unmask_dialog_credit_card_icon_height">20dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
index f590a96c..2f42590 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
@@ -18,6 +18,7 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.fullscreen.BrowserControlsManagerSupplier;
 import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponent;
 import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponentSupplier;
@@ -186,22 +187,21 @@
             String secondaryLabel, String sublabel, String secondarySublabel, String itemTag,
             int iconId, boolean isIconAtStart, int suggestionId, boolean isDeletable,
             boolean isLabelMultiline, boolean isLabelBold, GURL customIconUrl) {
-        array[index] =
-                new AutofillSuggestion.Builder()
-                        .setLabel(label)
-                        .setSecondaryLabel(secondaryLabel)
-                        .setSubLabel(sublabel)
-                        .setSecondarySubLabel(secondarySublabel)
-                        .setItemTag(itemTag)
-                        .setIsIconAtStart(isIconAtStart)
-                        .setSuggestionId(suggestionId)
-                        .setIsDeletable(isDeletable)
-                        .setIsMultiLineLabel(isLabelMultiline)
-                        .setIsBoldLabel(isLabelBold)
-                        .setIconDrawable(AutofillUiUtils.getCardIcon(mContext, customIconUrl,
-                                iconId, R.dimen.autofill_dropdown_icon_width,
-                                R.dimen.autofill_dropdown_icon_height, /* showCustomIcon= */ true))
-                        .build();
+        array[index] = new AutofillSuggestion.Builder()
+                               .setLabel(label)
+                               .setSecondaryLabel(secondaryLabel)
+                               .setSubLabel(sublabel)
+                               .setSecondarySubLabel(secondarySublabel)
+                               .setItemTag(itemTag)
+                               .setIsIconAtStart(isIconAtStart)
+                               .setSuggestionId(suggestionId)
+                               .setIsDeletable(isDeletable)
+                               .setIsMultiLineLabel(isLabelMultiline)
+                               .setIsBoldLabel(isLabelBold)
+                               .setIconDrawable(AutofillUiUtils.getCardIcon(mContext, customIconUrl,
+                                       iconId, getPopupIconWidthId(), getPopupIconHeightId(),
+                                       /* showCustomIcon= */ true))
+                               .build();
     }
 
     private @Nullable WebContentsViewRectProvider tryCreateRectProvider(
@@ -214,6 +214,22 @@
                 BrowserControlsManagerSupplier.from(windowAndroid), manualFillingComponentSupplier);
     }
 
+    public static int getPopupIconWidthId() {
+        if (ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES)) {
+            return R.dimen.autofill_dropdown_icon_width_new;
+        }
+        return R.dimen.autofill_dropdown_icon_width;
+    }
+
+    public static int getPopupIconHeightId() {
+        if (ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES)) {
+            return R.dimen.autofill_dropdown_icon_height_new;
+        }
+        return R.dimen.autofill_dropdown_icon_height;
+    }
+
     @NativeMethods
     interface Natives {
         void suggestionSelected(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java
index c017370..022e946 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillPaymentMethodsFragment.java
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.autofill.settings;
 
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getCardIcon;
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getSettingsPageIconHeightId;
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getSettingsPageIconWidthId;
+
 import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
@@ -22,7 +26,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.AutofillEditorBase;
-import org.chromium.chrome.browser.autofill.AutofillUiUtils;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.feedback.FragmentHelpAndFeedbackLauncher;
@@ -150,8 +153,8 @@
             }
 
             // Set card icon. It can be either a custom card art or a network icon.
-            card_pref.setIcon(AutofillUiUtils.getCardIcon(getStyledContext(), card,
-                    R.dimen.settings_page_card_icon_width, R.dimen.settings_page_card_icon_height));
+            card_pref.setIcon(getCardIcon(getStyledContext(), card, getSettingsPageIconWidthId(),
+                    getSettingsPageIconHeightId()));
 
             if (card.getIsLocal()) {
                 card_pref.setFragment(AutofillLocalCardEditor.class.getName());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillServerCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillServerCardEditor.java
index 0abff7e..9bda8b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillServerCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillServerCardEditor.java
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.autofill.settings;
 
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getCardIcon;
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getSettingsPageIconHeightId;
+import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getSettingsPageIconWidthId;
+
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -22,7 +26,6 @@
 import org.chromium.build.annotations.UsedByReflection;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeStringConstants;
-import org.chromium.chrome.browser.autofill.AutofillUiUtils;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
@@ -148,8 +151,8 @@
 
         // Set card icon. It can be either a custom card art or the network icon.
         ImageView cardIconContainer = v.findViewById(R.id.card_icon);
-        cardIconContainer.setImageDrawable(AutofillUiUtils.getCardIcon(getContext(), mCard,
-                R.dimen.settings_page_card_icon_width, R.dimen.settings_page_card_icon_height));
+        cardIconContainer.setImageDrawable(getCardIcon(
+                getContext(), mCard, getSettingsPageIconWidthId(), getSettingsPageIconHeightId()));
 
         ((TextView) v.findViewById(R.id.card_name)).setText(mCard.getCardNameForAutofillDisplay());
         ((TextView) v.findViewById(R.id.card_last_four))
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
index 3289202..f582fac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/FullscreenVideoPictureInPictureControllerTest.java
@@ -39,6 +39,7 @@
 import org.chromium.content_public.browser.test.util.WebContentsUtils;
 import org.chromium.media.MediaSwitches;
 import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.ui.test.util.DeviceRestriction;
 
 /**
  * Tests for FullscreenVideoPictureInPictureController and related methods.
@@ -47,7 +48,10 @@
 @Batch(Batch.PER_CLASS)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         MediaSwitches.AUTOPLAY_NO_GESTURE_REQUIRED_POLICY})
-@Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
+@Restriction({
+        RESTRICTION_TYPE_NON_LOW_END_DEVICE,
+        DeviceRestriction.RESTRICTION_TYPE_NON_AUTO // PiP not supported on AAOS.
+})
 @RequiresApi(Build.VERSION_CODES.O)
 public class FullscreenVideoPictureInPictureControllerTest {
     // TODO(peconn): Add a test for exit on Tab Reparenting.
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 868a21c1..ac54b987 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -946,7 +946,6 @@
   base::MessagePumpLibevent::InitializeFeatures();
 #elif BUILDFLAG(IS_MAC)
   base::PlatformThread::InitFeaturesPostFieldTrial();
-  base::MessagePumpDefault::InitFeaturesPostFieldTrial();
   base::MessagePumpCFRunLoopBase::InitializeFeatures();
   base::MessagePumpKqueue::InitializeFeatures();
 #endif
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 0c4dd4b7..ef67dd3 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -998,6 +998,7 @@
         <!-- WebHID system tray icon -->
         <message name="IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP" desc="Tooltip for the WebHID system tray icon when one or more HID devices are being accessed.">
             {NUM_DEVICES, plural,
+            =0 {Chromium was connected to a HID device}
             =1 {Chromium is connected to a HID device}
             other {Chromium is connected to HID devices}}
         </message>
diff --git a/chrome/app/chromium_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1 b/chrome/app/chromium_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
index b251fbcd..3f5e25c 100644
--- a/chrome/app/chromium_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
+++ b/chrome/app/chromium_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
@@ -1 +1 @@
-678ae1f6227de889133ce3956c028cbd02189cdc
\ No newline at end of file
+92039a80d2386719a85a3be0dc6594b43ef84e61
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1923bea..749e2a9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1487,6 +1487,9 @@
         <message name="IDS_SHOW_DOWNLOADS" desc="The show downloads menu in the app menu">
           &amp;Downloads
         </message>
+        <message name="IDS_VIEW_PASSWORDS" desc="The show Password Manager menu in the app menu">
+          &amp;Password Manager
+        </message>
         <message name="IDS_SHOW_EXTENSIONS" desc="The show extensions menu in the app menu">
           &amp;Extensions
         </message>
@@ -1537,6 +1540,9 @@
         <message name="IDS_SHOW_DOWNLOADS" desc="In Title Case: The show downloads menu in the app menu">
           &amp;Downloads
         </message>
+        <message name="IDS_VIEW_PASSWORDS" desc="In Title Case: The show Password Manager menu in the app menu">
+          Password Manager
+        </message>
         <message name="IDS_SHOW_EXTENSIONS" desc="In Title Case: The show extensions menu in the app menu">
           &amp;Extensions
         </message>
diff --git a/chrome/app/generated_resources_grd/IDS_VIEW_PASSWORDS.png.sha1 b/chrome/app/generated_resources_grd/IDS_VIEW_PASSWORDS.png.sha1
new file mode 100644
index 0000000..45eb682
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_VIEW_PASSWORDS.png.sha1
@@ -0,0 +1 @@
+59af7c027036dbc173f47b8040265340c49c742d
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index ba998bf..0b81272 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1052,6 +1052,7 @@
         <!-- WebHID system tray icon -->
         <message name="IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP" desc="Tooltip for the WebHID system tray icon when one or more HID devices are being accessed.">
             {NUM_DEVICES, plural,
+            =0 {Google Chrome was connected to a HID device}
             =1 {Google Chrome is connected to a HID device}
             other {Google Chrome is connected to HID devices}}
         </message>
diff --git a/chrome/app/google_chrome_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
index 99030560..3f5e25c 100644
--- a/chrome/app/google_chrome_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
+++ b/chrome/app/google_chrome_strings_grd/IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP.png.sha1
@@ -1 +1 @@
-d953c69958f551e7a8cd1b2686edecc34a828030
\ No newline at end of file
+92039a80d2386719a85a3be0dc6594b43ef84e61
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 95957d4..8a6d100 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -7102,11 +7102,6 @@
      flag_descriptions::kEvDetailsInPageInfoDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kEvDetailsInPageInfo)},
 
-    {"mouse-subframe-no-implicit-capture",
-     flag_descriptions::kMouseSubframeNoImplicitCaptureName,
-     flag_descriptions::kMouseSubframeNoImplicitCaptureDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kMouseSubframeNoImplicitCapture)},
-
 #if BUILDFLAG(IS_CHROMEOS)
     {"global-media-controls-cros-updated-ui",
      flag_descriptions::kGlobalMediaControlsCrOSUpdatedUIName,
diff --git a/chrome/browser/ash/dbus/encrypted_reporting_service_provider.cc b/chrome/browser/ash/dbus/encrypted_reporting_service_provider.cc
index dd8b9a0..9d7df6d17 100644
--- a/chrome/browser/ash/dbus/encrypted_reporting_service_provider.cc
+++ b/chrome/browser/ash/dbus/encrypted_reporting_service_provider.cc
@@ -17,6 +17,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h"
+#include "chrome/browser/policy/messaging_layer/upload/file_upload_impl.h"
 #include "chrome/browser/policy/messaging_layer/upload/upload_client.h"
 #include "chrome/browser/policy/messaging_layer/upload/upload_provider.h"
 #include "chromeos/dbus/missive/missive_client.h"
@@ -40,9 +41,9 @@
 
 void SendStatusAsResponse(std::unique_ptr<dbus::Response> response,
                           dbus::ExportedObject::ResponseSender response_sender,
-                          reporting::Status status) {
+                          ::reporting::Status status) {
   // Build StatusProto
-  reporting::StatusProto status_proto;
+  ::reporting::StatusProto status_proto;
   status.SaveTo(&status_proto);
 
   dbus::MessageWriter writer(response.get());
@@ -147,8 +148,9 @@
     // We should never get to here, since the provider is only exported
     // when is_uploader_required() is true. Have this code only as
     // in order to let `missive` daemon to log configuration inconsistency.
-    reporting::Status status{reporting::error::FAILED_PRECONDITION,
-                             "Uploads are not expected in this configuration"};
+    ::reporting::Status status{
+        ::reporting::error::FAILED_PRECONDITION,
+        "Uploads are not expected in this configuration"};
     LOG(ERROR) << "Uploads are not expected in this configuration";
     SendStatusAsResponse(std::move(response), std::move(response_sender),
                          status);
@@ -161,8 +163,8 @@
   if (!reader.PopArrayOfBytes(
           reinterpret_cast<const uint8_t**>(&serialized_request_buf),
           &serialized_request_buf_size)) {
-    reporting::Status status{
-        reporting::error::INVALID_ARGUMENT,
+    ::reporting::Status status{
+        ::reporting::error::INVALID_ARGUMENT,
         "Error reading UploadEncryptedRecordRequest as array of bytes"};
     LOG(ERROR) << "Unable to process UploadEncryptedRecordRequest. status: "
                << status;
@@ -174,9 +176,9 @@
   ::reporting::ScopedReservation scoped_reservation(serialized_request_buf_size,
                                                     memory_resource_);
   if (!scoped_reservation.reserved()) {
-    reporting::Status status{reporting::error::RESOURCE_EXHAUSTED,
-                             "UploadEncryptedRecordRequest has exhausted "
-                             "assigned memory pool in Chrome"};
+    ::reporting::Status status{::reporting::error::RESOURCE_EXHAUSTED,
+                               "UploadEncryptedRecordRequest has exhausted "
+                               "assigned memory pool in Chrome"};
     LOG(ERROR) << "Unable to process UploadEncryptedRecordRequest. status: "
                << status;
     SendStatusAsResponse(std::move(response), std::move(response_sender),
@@ -184,11 +186,11 @@
     return;
   }
 
-  reporting::UploadEncryptedRecordRequest request;
+  ::reporting::UploadEncryptedRecordRequest request;
   if (!request.ParseFromArray(serialized_request_buf,
                               serialized_request_buf_size)) {
-    reporting::Status status{
-        reporting::error::INVALID_ARGUMENT,
+    ::reporting::Status status{
+        ::reporting::error::INVALID_ARGUMENT,
         "Failed to parse UploadEncryptedRecordRequest from array of bytes."};
     LOG(ERROR) << "Unable to process UploadEncryptedRecordRequest. status: "
                << status;
@@ -209,11 +211,12 @@
       request.has_new_events_rate() ? request.new_events_rate() : 1U;
   // Move events from |request| into a separate vector |records|, using more or
   // less the same amount of memory that has been reserved above.
-  auto records{reporting::EventUploadSizeController::BuildEncryptedRecords(
+  auto records{::reporting::EventUploadSizeController::BuildEncryptedRecords(
       request.encrypted_record(),
-      reporting::EventUploadSizeController(network_condition_service_,
-                                           new_events_rate,
-                                           remaining_storage_capacity))};
+      ::reporting::EventUploadSizeController(
+          network_condition_service_, new_events_rate,
+          remaining_storage_capacity,
+          ::reporting::FileUploadDelegate::kMaxUploadBufferSize))};
 
   DCHECK(upload_provider_);
   chromeos::MissiveClient* const missive_client =
@@ -222,8 +225,8 @@
     LOG(ERROR) << "No Missive client available";
     SendStatusAsResponse(
         std::move(response), std::move(response_sender),
-        reporting::Status(reporting::error::FAILED_PRECONDITION,
-                          "No Missive client available"));
+        ::reporting::Status(::reporting::error::FAILED_PRECONDITION,
+                            "No Missive client available"));
     return;
   }
 
diff --git a/chrome/browser/ash/eol_notification_browsertest.cc b/chrome/browser/ash/eol_notification_browsertest.cc
index 0f66608..2e5939b 100644
--- a/chrome/browser/ash/eol_notification_browsertest.cc
+++ b/chrome/browser/ash/eol_notification_browsertest.cc
@@ -31,9 +31,11 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
+#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
 #include "chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h"
 #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
 #include "components/session_manager/core/session_manager.h"
+#include "components/user_manager/user_manager.h"
 #include "content/public/test/browser_test.h"
 
 namespace ash {
@@ -85,30 +87,67 @@
   kInvalidProfileCreation
 };
 
-// Helper class to create NotificationDisplayServiceTester before notification
-// in the session shown.
-class NotificationDisplayServiceWaiter : public ProfileManagerObserver {
+// A mixin that injects a stub notification display service that tracks set of
+// notifications for the primary profile. Expected to be used with test that go
+// through login flow, and the primary user profile is different than the
+// browser test profile (`browser()->profile()`).
+class NotificationDisplayServiceMixin : public InProcessBrowserTestMixin,
+                                        public ProfileManagerObserver {
  public:
-  NotificationDisplayServiceWaiter() {
-    g_browser_process->profile_manager()->AddObserver(this);
+  explicit NotificationDisplayServiceMixin(
+      InProcessBrowserTestMixinHost* mixin_host)
+      : InProcessBrowserTestMixin(mixin_host) {}
+
+  NotificationDisplayServiceMixin(const NotificationDisplayServiceMixin&) =
+      delete;
+  NotificationDisplayServiceMixin& operator=(
+      const NotificationDisplayServiceMixin&) = delete;
+
+  ~NotificationDisplayServiceMixin() override = default;
+
+  // InProcessBrowserTestMixin:
+  void SetUpOnMainThread() override {
+    // The mixin observes profile manager, and initializes the test notification
+    // service when the primary user profile gets added. If primary user (and
+    // profile) have already been created at this point, the mixin will not be
+    // able to detect profile addition.
+    ASSERT_FALSE(user_manager::UserManager::Get()->GetPrimaryUser());
+    profile_waiter_ = std::make_unique<base::RunLoop>();
+    profile_manager_observer_.Observe(g_browser_process->profile_manager());
+  }
+
+  void TearDownOnMainThread() override {
+    profile_manager_observer_.Reset();
+    profile_waiter_.reset();
+    display_service_.reset();
   }
 
   // ProfileManagerObserver:
   void OnProfileAdded(Profile* profile) override {
-    g_browser_process->profile_manager()->RemoveObserver(this);
+    if (!user_manager::UserManager::Get()->IsPrimaryUser(
+            BrowserContextHelper::Get()->GetUserByBrowserContext(profile))) {
+      return;
+    }
+    profile_manager_observer_.Reset();
     display_service_ =
         std::make_unique<NotificationDisplayServiceTester>(profile);
-    run_loop_.Quit();
+    profile_waiter_->Quit();
   }
 
-  std::unique_ptr<NotificationDisplayServiceTester> Wait() {
-    run_loop_.Run();
-    return std::move(display_service_);
+  NotificationDisplayServiceTester* WaitForDisplayService() {
+    if (!display_service_ && !profile_manager_observer_.IsObserving()) {
+      return nullptr;
+    }
+
+    profile_waiter_->Run();
+    return display_service_.get();
   }
 
  private:
+  base::ScopedObservation<ProfileManager, ProfileManagerObserver>
+      profile_manager_observer_{this};
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
-  base::RunLoop run_loop_;
+  std::unique_ptr<base::RunLoop> profile_waiter_;
 };
 
 // Mixin that sets up session state to indicate certain EOL status:
@@ -288,6 +327,8 @@
  protected:
   EolStatusMixin eol_status_mixin_{&mixin_host_};
 
+  NotificationDisplayServiceMixin notifications_mixin_{&mixin_host_};
+
   ash::LoggedInUserMixin logged_in_user_mixin_{
       &mixin_host_, LoggedInUserMixin::LogInType::kRegular,
       embedded_test_server(), this};
@@ -308,6 +349,8 @@
  protected:
   EolStatusMixin eol_status_mixin_{&mixin_host_};
 
+  NotificationDisplayServiceMixin notifications_mixin_{&mixin_host_};
+
   ash::DeviceStateMixin device_state_{
       &mixin_host_,
       ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
@@ -338,6 +381,8 @@
  protected:
   EolStatusMixin eol_status_mixin_{&mixin_host_};
 
+  NotificationDisplayServiceMixin notifications_mixin_{&mixin_host_};
+
   ash::LoggedInUserMixin logged_in_user_mixin_{
       &mixin_host_,
       LoggedInUserMixin::LogInType::kChild,
@@ -382,11 +427,12 @@
                 /*now_string=*/"12 May 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -401,7 +447,7 @@
   if (NotificationHasClaimButton()) {
     notification_display_service->SimulateClick(
         NotificationHandler::Type::TRANSIENT, notification->id(),
-        /*action_id=*/0, /*reply=*/absl::nullopt);
+        /*action_index=*/0, /*reply=*/absl::nullopt);
     content::WebContents* active_contents =
         chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
     ASSERT_TRUE(active_contents);
@@ -431,11 +477,12 @@
                 /*now_string=*/"12 May 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -443,7 +490,7 @@
   ASSERT_TRUE(notification);
   notification_display_service->SimulateClick(
       NotificationHandler::Type::TRANSIENT, notification->id(),
-      /*action_id=*/0, /*reply=*/absl::nullopt);
+      /*action_index=*/0, /*reply=*/absl::nullopt);
 }
 
 IN_PROC_BROWSER_TEST_P(EolNotificationTest,
@@ -453,11 +500,12 @@
                 /*now_string=*/"12 May 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -473,11 +521,12 @@
                                   /*eol_string=*/"01 June 2023",
                                   /*profile_creation_string=*/"01 April 2023"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -490,7 +539,7 @@
 
   notification_display_service->SimulateClick(
       NotificationHandler::Type::TRANSIENT, notification->id(),
-      /*action_id=*/0, /*reply=*/absl::nullopt);
+      /*action_index=*/0, /*reply=*/absl::nullopt);
   content::WebContents* active_contents =
       chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(active_contents);
@@ -503,11 +552,12 @@
                 /*now_string=*/"03 June 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -520,7 +570,7 @@
   if (NotificationHasClaimButton()) {
     notification_display_service->SimulateClick(
         NotificationHandler::Type::TRANSIENT, notification->id(),
-        /*action_id=*/0, /*reply=*/absl::nullopt);
+        /*action_index=*/0, /*reply=*/absl::nullopt);
     content::WebContents* active_contents =
         chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
     ASSERT_TRUE(active_contents);
@@ -538,11 +588,12 @@
                 /*now_string=*/"03 June 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -551,7 +602,7 @@
 
   notification_display_service->SimulateClick(
       NotificationHandler::Type::TRANSIENT, notification->id(),
-      /*action_id=*/0, /*reply=*/absl::nullopt);
+      /*action_index=*/0, /*reply=*/absl::nullopt);
 
   // Verify quick settings notice still shows.
   EXPECT_EQ(
@@ -566,11 +617,12 @@
                 /*now_string=*/"03 June 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -669,11 +721,12 @@
                                   /*eol_string=*/"01 June 2023",
                                   /*profile_creation_string=*/"05 May 2023"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -685,7 +738,7 @@
 
   notification_display_service->SimulateClick(
       NotificationHandler::Type::TRANSIENT, notification->id(),
-      /*action_id=*/0, /*reply=*/absl::nullopt);
+      /*action_index=*/0, /*reply=*/absl::nullopt);
   content::WebContents* active_contents =
       chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(active_contents);
@@ -699,11 +752,12 @@
                                   /*eol_string=*/"01 June 2023",
                                   /*profile_creation_string=*/"05 May 2020"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -716,7 +770,7 @@
 
   notification_display_service->SimulateClick(
       NotificationHandler::Type::TRANSIENT, notification->id(),
-      /*action_id=*/0, /*reply=*/absl::nullopt);
+      /*action_index=*/0, /*reply=*/absl::nullopt);
   content::WebContents* active_contents =
       chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(active_contents);
@@ -770,11 +824,12 @@
                 /*now_string=*/"12 May 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -789,11 +844,12 @@
                 /*now_string=*/"03 June 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -820,11 +876,12 @@
                 /*now_string=*/"12 May 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
@@ -840,11 +897,12 @@
                 /*now_string=*/"03 June 2023", /*eol_string=*/"01 June 2023",
                 /*profile_creation_string=*/"05 December 2021"));
 
-  NotificationDisplayServiceWaiter notifications_waiter;
   logged_in_user_mixin_.LogInUser();
 
-  std::unique_ptr<NotificationDisplayServiceTester>
-      notification_display_service = notifications_waiter.Wait();
+  NotificationDisplayServiceTester* notification_display_service =
+      notifications_mixin_.WaitForDisplayService();
+  ASSERT_TRUE(notification_display_service);
+
   base::RunLoop().RunUntilIdle();
 
   absl::optional<message_center::Notification> notification =
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
index e9a3dc6..5817ee5 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service.cc
@@ -259,7 +259,7 @@
   if (!smartlock_state_handler_) {
     smartlock_state_handler_ = std::make_unique<SmartLockStateHandler>(
         GetAccountId(), GetHardlockState(),
-        proximity_auth::ScreenlockBridge::Get(), GetProximityAuthPrefManager());
+        proximity_auth::ScreenlockBridge::Get());
   }
   return smartlock_state_handler_.get();
 }
@@ -485,7 +485,6 @@
 
   if (GetSmartLockStateHandler()) {
     smartlock_state_handler_->SetHardlockState(state);
-    smartlock_state_handler_->MaybeShowHardlockUI();
   }
   if (state != SmartLockStateHandler::NO_HARDLOCK)
     auth_attempt_.reset();
diff --git a/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.cc b/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.cc
index 63690fa..19a2a25 100644
--- a/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.cc
+++ b/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.cc
@@ -15,7 +15,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_metrics.h"
 #include "chrome/grit/generated_resources.h"
-#include "chromeos/ash/components/proximity_auth/proximity_auth_pref_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/devicetype_utils.h"
 
@@ -116,12 +115,10 @@
 SmartLockStateHandler::SmartLockStateHandler(
     const AccountId& account_id,
     HardlockState initial_hardlock_state,
-    proximity_auth::ScreenlockBridge* screenlock_bridge,
-    proximity_auth::ProximityAuthPrefManager* pref_manager)
+    proximity_auth::ScreenlockBridge* screenlock_bridge)
     : state_(SmartLockState::kInactive),
       account_id_(account_id),
       screenlock_bridge_(screenlock_bridge),
-      pref_manager_(pref_manager),
       hardlock_state_(initial_hardlock_state) {
   DCHECK(screenlock_bridge_);
   screenlock_bridge_->AddObserver(this);
@@ -172,7 +169,9 @@
   // TODO(crbug.com/1233614): Return early if kSmartLockUIRevamp is enabled.
 
   if (hardlock_state_ != NO_HARDLOCK) {
-    ShowHardlockUI();
+    // TODO(b/227674947): Hardlock is no longer used due to the deprecation of
+    // Sign in with Smart Lock. Eventually delete hardlock_state_ and remove
+    // this if-block.
     return;
   }
 
@@ -218,17 +217,10 @@
   // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about
   // to get unlocked. No need to update it in this case.
   if (hardlock_state_ != NO_HARDLOCK) {
-    hardlock_ui_shown_ = false;
-
     RefreshSmartLockState();
   }
 }
 
-void SmartLockStateHandler::MaybeShowHardlockUI() {
-  if (hardlock_state_ != NO_HARDLOCK)
-    ShowHardlockUI();
-}
-
 void SmartLockStateHandler::OnScreenDidLock(
     proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
   did_see_locked_phone_ = IsLockedState(state_);
@@ -239,7 +231,6 @@
     proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
   if (hardlock_state_ == LOGIN_FAILED)
     hardlock_state_ = NO_HARDLOCK;
-  hardlock_ui_shown_ = false;
 
   // Upon a successful unlock event, record whether the user's phone was locked
   // at any point while the lock screen was up.
@@ -257,94 +248,6 @@
   ChangeState(last_state);
 }
 
-void SmartLockStateHandler::ShowHardlockUI() {
-  DCHECK(hardlock_state_ != NO_HARDLOCK);
-
-  if (!screenlock_bridge_->IsLocked())
-    return;
-
-  // Do not override online signin.
-  const proximity_auth::mojom::AuthType existing_auth_type =
-      screenlock_bridge_->lock_handler()->GetAuthType(account_id_);
-  if (existing_auth_type == proximity_auth::mojom::AuthType::ONLINE_SIGN_IN)
-    return;
-
-  if (existing_auth_type != proximity_auth::mojom::AuthType::OFFLINE_PASSWORD) {
-    screenlock_bridge_->lock_handler()->SetAuthType(
-        account_id_, proximity_auth::mojom::AuthType::OFFLINE_PASSWORD,
-        std::u16string());
-  }
-
-  if (hardlock_state_ == NO_PAIRING) {
-    screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(account_id_);
-    hardlock_ui_shown_ = false;
-    return;
-  }
-
-  if (hardlock_ui_shown_)
-    return;
-
-  proximity_auth::ScreenlockBridge::UserPodCustomIconInfo icon_info;
-  if (hardlock_state_ == LOGIN_FAILED) {
-    icon_info.SetIcon(
-        proximity_auth::ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED);
-  } else if (hardlock_state_ == PAIRING_CHANGED ||
-             hardlock_state_ == PAIRING_ADDED) {
-    icon_info.SetIcon(proximity_auth::ScreenlockBridge::
-                          USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED);
-  } else {
-    icon_info.SetIcon(
-        proximity_auth::ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED);
-  }
-
-  std::u16string device_name = GetDeviceName();
-  std::u16string tooltip;
-  switch (hardlock_state_) {
-    case USER_HARDLOCK:
-      tooltip = l10n_util::GetStringFUTF16(
-          IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, device_name);
-      break;
-    case PAIRING_CHANGED:
-      tooltip = l10n_util::GetStringFUTF16(
-          IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED,
-          device_name);
-      break;
-    case PAIRING_ADDED:
-      tooltip = l10n_util::GetStringFUTF16(
-          IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED,
-          device_name);
-      break;
-    case LOGIN_FAILED:
-      tooltip = l10n_util::GetStringUTF16(
-          IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE);
-      break;
-    case LOGIN_DISABLED:
-      tooltip = l10n_util::GetStringUTF16(
-          IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_DISABLED);
-      break;
-    default:
-      LOG(ERROR) << "Unknown hardlock state: " << hardlock_state_;
-      NOTREACHED();
-  }
-
-  bool autoshow = true;
-  // TODO(crbug.com/1152491): Only call into SetHasShownLoginDisabledMessage()
-  // if this is a signin screen, not lock screen, context.
-  if (hardlock_state_ == LOGIN_DISABLED) {
-    // If Signin with Smart Lock is disabled, only automatically show the
-    // tooltip if it hasn't been shown yet. See https://crbug.com/848893 for
-    // details.
-    autoshow = !pref_manager_->HasShownLoginDisabledMessage();
-    pref_manager_->SetHasShownLoginDisabledMessage(true);
-  }
-
-  icon_info.SetTooltip(tooltip, autoshow);
-
-  screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(account_id_,
-                                                            icon_info);
-  hardlock_ui_shown_ = true;
-}
-
 void SmartLockStateHandler::UpdateTooltipOptions(
     proximity_auth::ScreenlockBridge::UserPodCustomIconInfo* icon_info) {
   size_t resource_id = 0;
diff --git a/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.h b/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.h
index 691ac645..56766034 100644
--- a/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.h
+++ b/chrome/browser/ash/login/easy_unlock/smartlock_state_handler.h
@@ -10,10 +10,6 @@
 #include "chromeos/ash/components/proximity_auth/screenlock_bridge.h"
 #include "components/account_id/account_id.h"
 
-namespace proximity_auth {
-class ProximityAuthPrefManager;
-}  // namespace proximity_auth
-
 namespace ash {
 
 enum class SmartLockState;
@@ -42,12 +38,9 @@
   // `initial_hardlock_state`: The initial hardlock state.
   // `screenlock_bridge`: The screenlock bridge used to update the Smart Lock
   //     state.
-  // `pref_manager`: Used primarily to track if the "Signin with Smart Lock is
-  //     disabled" message has been shown before.
   SmartLockStateHandler(const AccountId& account_id,
                         HardlockState initial_hardlock_state,
-                        proximity_auth::ScreenlockBridge* screenlock_bridge,
-                        proximity_auth::ProximityAuthPrefManager* pref_manager);
+                        proximity_auth::ScreenlockBridge* screenlock_bridge);
 
   SmartLockStateHandler(const SmartLockStateHandler&) = delete;
   SmartLockStateHandler& operator=(const SmartLockStateHandler&) = delete;
@@ -69,9 +62,6 @@
   // Updates the hardlock state.
   void SetHardlockState(HardlockState new_state);
 
-  // Shows the hardlock UI if the hardlock_state_ is not NO_HARDLOCK.
-  void MaybeShowHardlockUI();
-
   SmartLockState state() const { return state_; }
 
  private:
@@ -86,8 +76,6 @@
   // Forces refresh of the Smart Lock UI.
   void RefreshSmartLockState();
 
-  void ShowHardlockUI();
-
   // Updates icon's tooltip options.
   void UpdateTooltipOptions(
       proximity_auth::ScreenlockBridge::UserPodCustomIconInfo* icon_info);
@@ -102,11 +90,9 @@
   SmartLockState state_;
   const AccountId account_id_;
   proximity_auth::ScreenlockBridge* screenlock_bridge_ = nullptr;
-  proximity_auth::ProximityAuthPrefManager* pref_manager_ = nullptr;
 
   // State of hardlock.
   HardlockState hardlock_state_;
-  bool hardlock_ui_shown_ = false;
 
   // Whether the user's phone was ever locked while on the current lock screen.
   bool did_see_locked_phone_ = false;
diff --git a/chrome/browser/ash/login/lock/views_screen_locker.cc b/chrome/browser/ash/login/lock/views_screen_locker.cc
index e4a4c46..df411ee 100644
--- a/chrome/browser/ash/login/lock/views_screen_locker.cc
+++ b/chrome/browser/ash/login/lock/views_screen_locker.cc
@@ -150,10 +150,6 @@
       account_id, std::move(callback));
 }
 
-void ViewsScreenLocker::HandleHardlockPod(const AccountId& account_id) {
-  user_selection_screen_->HardLockPod(account_id);
-}
-
 void ViewsScreenLocker::HandleOnFocusPod(const AccountId& account_id) {
   user_selection_screen_->HandleFocusPod(account_id);
 
diff --git a/chrome/browser/ash/login/lock/views_screen_locker.h b/chrome/browser/ash/login/lock/views_screen_locker.h
index 3c8e67003..b6230cd 100644
--- a/chrome/browser/ash/login/lock/views_screen_locker.h
+++ b/chrome/browser/ash/login/lock/views_screen_locker.h
@@ -54,7 +54,6 @@
   void HandleAuthenticateUserWithChallengeResponse(
       const AccountId& account_id,
       base::OnceCallback<void(bool)> callback) override;
-  void HandleHardlockPod(const AccountId& account_id) override;
   void HandleOnFocusPod(const AccountId& account_id) override;
   void HandleOnNoPodFocused() override;
   bool HandleFocusLockScreenApps(bool reverse) override;
diff --git a/chrome/browser/ash/login/screens/user_selection_screen.cc b/chrome/browser/ash/login/screens/user_selection_screen.cc
index 4233bc1..2a8de48 100644
--- a/chrome/browser/ash/login/screens/user_selection_screen.cc
+++ b/chrome/browser/ash/login/screens/user_selection_screen.cc
@@ -807,16 +807,6 @@
               std::u16string());
 }
 
-void UserSelectionScreen::HardLockPod(const AccountId& account_id) {
-  view_->SetAuthType(account_id,
-                     proximity_auth::mojom::AuthType::OFFLINE_PASSWORD,
-                     std::u16string());
-  EasyUnlockService* service = GetEasyUnlockServiceForUser(account_id);
-  if (!service)
-    return;
-  service->SetHardlockState(SmartLockStateHandler::USER_HARDLOCK);
-}
-
 void UserSelectionScreen::AttemptEasyUnlock(const AccountId& account_id) {
   EasyUnlockService* service = GetEasyUnlockServiceForUser(account_id);
   if (!service)
diff --git a/chrome/browser/ash/login/screens/user_selection_screen.h b/chrome/browser/ash/login/screens/user_selection_screen.h
index 33aa623..e804e47 100644
--- a/chrome/browser/ash/login/screens/user_selection_screen.h
+++ b/chrome/browser/ash/login/screens/user_selection_screen.h
@@ -64,10 +64,7 @@
   void HandleNoPodFocused();
   void OnBeforeShow();
 
-  // Methods for easy unlock support.
-  void HardLockPod(const AccountId& account_id);
   void AttemptEasyUnlock(const AccountId& account_id);
-
   void InitEasyUnlock();
 
   void SetTpmLockedState(bool is_locked, base::TimeDelta time_left);
diff --git a/chrome/browser/ash/login/ui/login_display_host_mojo.cc b/chrome/browser/ash/login/ui/login_display_host_mojo.cc
index 98f63031..3ab099d 100644
--- a/chrome/browser/ash/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/ash/login/ui/login_display_host_mojo.cc
@@ -595,10 +595,6 @@
                      std::move(callback)));
 }
 
-void LoginDisplayHostMojo::HandleHardlockPod(const AccountId& account_id) {
-  user_selection_screen_->HardLockPod(account_id);
-}
-
 void LoginDisplayHostMojo::HandleOnFocusPod(const AccountId& account_id) {
   user_selection_screen_->HandleFocusPod(account_id);
   WallpaperControllerClientImpl::Get()->ShowUserWallpaper(account_id);
diff --git a/chrome/browser/ash/login/ui/login_display_host_mojo.h b/chrome/browser/ash/login/ui/login_display_host_mojo.h
index 5830b761..0c94b006 100644
--- a/chrome/browser/ash/login/ui/login_display_host_mojo.h
+++ b/chrome/browser/ash/login/ui/login_display_host_mojo.h
@@ -122,7 +122,6 @@
   void HandleAuthenticateUserWithChallengeResponse(
       const AccountId& account_id,
       base::OnceCallback<void(bool)> callback) override;
-  void HandleHardlockPod(const AccountId& account_id) override;
   void HandleOnFocusPod(const AccountId& account_id) override;
   void HandleOnNoPodFocused() override;
   bool HandleFocusLockScreenApps(bool reverse) override;
diff --git a/chrome/browser/ash/web_applications/personalization_app/keyboard_backlight_color_metrics_provider.cc b/chrome/browser/ash/web_applications/personalization_app/keyboard_backlight_color_metrics_provider.cc
index 05bb3ca..d60e72d 100644
--- a/chrome/browser/ash/web_applications/personalization_app/keyboard_backlight_color_metrics_provider.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/keyboard_backlight_color_metrics_provider.cc
@@ -12,6 +12,8 @@
 #include "ash/webui/personalization_app/mojom/personalization_app.mojom-shared.h"
 #include "base/metrics/histogram_functions.h"
 
+using DisplayType = ash::KeyboardBacklightColorController::DisplayType;
+
 KeyboardBacklightColorMetricsProvider::KeyboardBacklightColorMetricsProvider() =
     default;
 KeyboardBacklightColorMetricsProvider::
@@ -26,8 +28,37 @@
 
   auto* keyboard_backlight_color_controller =
       ash::Shell::Get()->keyboard_backlight_color_controller();
-  auto backlight_color = keyboard_backlight_color_controller->GetBacklightColor(
-      ash::Shell::Get()->session_controller()->GetActiveAccountId());
-  base::UmaHistogramEnumeration(
-      "Ash.Personalization.KeyboardBacklight.Color.Settled", backlight_color);
+
+  const AccountId account_id =
+      ash::Shell::Get()->session_controller()->GetActiveAccountId();
+
+  const auto displayType =
+      keyboard_backlight_color_controller->GetDisplayType(account_id);
+  switch (displayType) {
+    case DisplayType::kStatic: {
+      auto backlight_color =
+          keyboard_backlight_color_controller->GetBacklightColor(account_id);
+      base::UmaHistogramEnumeration(
+          "Ash.Personalization.KeyboardBacklight.Color.Settled",
+          backlight_color);
+      return;
+    }
+    case DisplayType::kMultiZone: {
+      if (!ash::features::IsMultiZoneRgbKeyboardEnabled() ||
+          ash::Shell::Get()->rgb_keyboard_manager()->GetZoneCount() <= 1) {
+        return;
+      }
+      auto zone_colors =
+          keyboard_backlight_color_controller->GetBacklightZoneColors(
+              account_id);
+      for (size_t i = 0; i < zone_colors.size(); i++) {
+        base::UmaHistogramEnumeration(
+            base::StringPrintf("Ash.Personalization.KeyboardBacklight."
+                               "ZoneColors.Zone%zu.Settled",
+                               i + 1),
+            zone_colors[i]);
+      }
+      return;
+    }
+  }
 }
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.cc
index 61b082f..2b67c137 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.cc
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.cc
@@ -32,7 +32,7 @@
     : profile_(Profile::FromWebUI(web_ui)) {
   pref_change_registrar_.Init(profile_->GetPrefs());
   if (chromeos::features::IsJellyEnabled()) {
-    color_palette_controller_ = ColorPaletteController::Create();
+    color_palette_controller_ = Shell::Get()->color_palette_controller();
   }
 }
 
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.h
index 753b438..67571fa8 100644
--- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.h
+++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_theme_provider_impl.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_PERSONALIZATION_APP_THEME_PROVIDER_IMPL_H_
 
 #include "ash/public/cpp/style/color_mode_observer.h"
-#include "ash/style/color_palette_controller.h"
 #include "ash/style/dark_light_mode_controller_impl.h"
 #include "ash/webui/personalization_app/personalization_app_theme_provider.h"
 #include "base/memory/raw_ptr.h"
@@ -19,6 +18,10 @@
 
 class Profile;
 
+namespace ash {
+class ColorPaletteController;
+}  // namespace ash
+
 namespace content {
 class WebUI;
 }  // namespace content
@@ -93,7 +96,8 @@
 
   PrefChangeRegistrar pref_change_registrar_;
 
-  std::unique_ptr<ColorPaletteController> color_palette_controller_;
+  base::raw_ptr<ColorPaletteController> color_palette_controller_ =
+      nullptr;  // owned by Shell
 
   base::ScopedObservation<ash::DarkLightModeControllerImpl,
                           ash::ColorModeObserver>
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
index 876a280b..8c325d5c 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillUiUtils.java
@@ -525,4 +525,20 @@
                 true);
         return new BitmapDrawable(resources, scaledBitmap);
     }
+
+    public static int getSettingsPageIconWidthId() {
+        if (ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES)) {
+            return R.dimen.settings_page_card_icon_width_new;
+        }
+        return R.dimen.settings_page_card_icon_width;
+    }
+
+    public static int getSettingsPageIconHeightId() {
+        if (ChromeFeatureList.isEnabled(
+                    ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES)) {
+            return R.dimen.settings_page_card_icon_height_new;
+        }
+        return R.dimen.settings_page_card_icon_height;
+    }
 }
diff --git a/chrome/browser/autofill/autofill_popup_controller_utils.cc b/chrome/browser/autofill/autofill_popup_controller_utils.cc
index ad22f07..f076bf4 100644
--- a/chrome/browser/autofill/autofill_popup_controller_utils.cc
+++ b/chrome/browser/autofill/autofill_popup_controller_utils.cc
@@ -59,7 +59,7 @@
     {kAmericanExpressCard, IDR_AUTOFILL_METADATA_CC_AMEX},
     {kDinersCard, IDR_AUTOFILL_METADATA_CC_DINERS},
     {kDiscoverCard, IDR_AUTOFILL_METADATA_CC_DISCOVER},
-    {kEloCard, IDR_AUTOFILL_CC_ELO},
+    {kEloCard, IDR_AUTOFILL_METADATA_CC_ELO},
     {kGenericCard, IDR_AUTOFILL_METADATA_CC_GENERIC},
     {kJCBCard, IDR_AUTOFILL_METADATA_CC_JCB},
     {kMasterCard, IDR_AUTOFILL_METADATA_CC_MASTERCARD},
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index 00ba707..1a79b56ec 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -233,11 +233,19 @@
 void LacrosInstallerPolicy::ComponentReady(const base::Version& version,
                                            const base::FilePath& path,
                                            base::Value::Dict manifest) {
-  // Each version of Lacros guarantees it will be compatible through the next
-  // major ash/OS version. For example, Lacros 89 will work with ash/OS 90,
-  // but may not work with ash/OS 91.
+  // Each version of Lacros guarantees it will be compatible through the same
+  // major ash/OS version and -2. For example, Lacros 89 will work with ash/OS
+  // 89, 88, and 87. But it may not work with ash/OS 86 or 90.
+  //
+  // As you see we (client side) only enforces the Lacros/Ash same version
+  // check here, while the code does not check the -2 version skew requirement.
+  // This is because go/lacros-version-skew-guide mentions the restriction on
+  // lacros being too new is enforced on the Omaha server side - and the too
+  // old check is enforced client side. Supposedly this makes it easy for us to
+  // start supporting newer lacros versions by just updating the Omaha server
+  // code.
   uint32_t lacros_major_version = version.components()[0];
-  if (lacros_major_version + 1 < GetAshMajorVersion()) {
+  if (lacros_major_version < GetAshMajorVersion()) {
     // Current lacros install is not compatible.
     return;
   }
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc b/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc
index d3bfc08..8c852d0 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc
@@ -439,11 +439,28 @@
                         /*manifest=*/base::Value::Dict());
   EXPECT_TRUE(installer->GetCompatiblePath("lacros-fishfood").empty());
 
-  // Simulate finding a compatible existing install.
   policy.ComponentReady(base::Version("9.0.0.0"),
                         base::FilePath("/lacros/9.0.0.0"),
                         /*manifest=*/base::Value::Dict());
-  EXPECT_EQ("/lacros/9.0.0.0",
+  EXPECT_TRUE(installer->GetCompatiblePath("lacros-fishfood").empty());
+
+  // Simulate finding a compatible existing install.
+  policy.ComponentReady(base::Version("10.0.0.0"),
+                        base::FilePath("/lacros/10.0.0.0"),
+                        /*manifest=*/base::Value::Dict());
+  EXPECT_EQ("/lacros/10.0.0.0",
+            installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII());
+
+  policy.ComponentReady(base::Version("11.0.0.0"),
+                        base::FilePath("/lacros/11.0.0.0"),
+                        /*manifest=*/base::Value::Dict());
+  EXPECT_EQ("/lacros/11.0.0.0",
+            installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII());
+
+  policy.ComponentReady(base::Version("12.0.0.0"),
+                        base::FilePath("/lacros/12.0.0.0"),
+                        /*manifest=*/base::Value::Dict());
+  EXPECT_EQ("/lacros/12.0.0.0",
             installer->GetCompatiblePath("lacros-fishfood").MaybeAsASCII());
 
   LacrosInstallerPolicy::SetAshVersionForTest(nullptr);
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index 5c7ebec..53b0340 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -159,7 +159,8 @@
                          : "chrome://theme/IDR_AUTOFILL_CC_DISCOVER";
   }
   if (network == autofill::kEloCard) {
-    return "chrome://theme/IDR_AUTOFILL_CC_ELO";
+    return metadata_icon ? "chrome://theme/IDR_AUTOFILL_METADATA_CC_ELO"
+                         : "chrome://theme/IDR_AUTOFILL_CC_ELO";
   }
   if (network == autofill::kJCBCard) {
     return metadata_icon ? "chrome://theme/IDR_AUTOFILL_METADATA_CC_JCB"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 58705666d..de93ab8d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -494,11 +494,6 @@
     "expiry_milestone": 120
   },
   {
-    "name": "autofill-enable-cvc-for-vcn-yellow-path",
-     "owners": ["vinnypersky@google.com"],
-     "expiry_milestone": 120
-  },
-  {
     "name": "autofill-enable-fido-progress-dialog",
     "owners": [ "siashah", "yiian" ],
     "expiry_milestone": 120
@@ -1167,8 +1162,11 @@
   },
   {
     "name": "content-languages-in-language-picker",
-    "owners": [ "sclittle", "basiaz@google.com", "chrome-language@google.com" ],
-    "expiry_milestone": 114
+    "owners": [
+      "basiaz@google.com",
+      "chrome-language@google.com"
+    ],
+    "expiry_milestone": 117
   },
   {
     "name": "content-suggestions-ui-module-refresh",
@@ -4980,11 +4978,6 @@
     "expiry_milestone": 115
   },
   {
-    "name": "mouse-subframe-no-implicit-capture",
-    "owners": [ "eirage", "nzolghadr", "input-dev" ],
-    "expiry_milestone": 84
-  },
-  {
     "name": "multi-zone-rgb-keyboard",
     "owners": [ "jasontt", "assistive-eng@google.com"],
     "expiry_milestone": 120
@@ -6301,7 +6294,7 @@
   },
   {
     "name": "request-desktop-site-additions",
-    "owners": [ "shuyng@google.com", "twellington", "clank-app-team@google.com" ],
+    "owners": [ "shuyng@google.com", "skavuluru@google.com", "twellington", "clank-app-team@google.com" ],
     "expiry_milestone": 116
   },
   {
@@ -6316,18 +6309,18 @@
   },
   {
     "name": "request-desktop-site-defaults-logging",
-    "owners": [ "shuyng@google.com", "clank-app-team@google.com" ],
+    "owners": [ "shuyng@google.com", "skavuluru@google.com", "clank-app-team@google.com" ],
     "expiry_milestone": 116
   },
   {
     "name": "request-desktop-site-exceptions",
-    "owners": [ "shuyng@google.com", "twellington", "clank-app-team@google.com" ],
-    "expiry_milestone": 114
+    "owners": [ "shuyng@google.com", "skavuluru@google.com", "twellington", "clank-app-team@google.com" ],
+    "expiry_milestone": 116
   },
   {
     "name": "request-desktop-site-exceptions-downgrade",
-    "owners": [ "aishwaryarj", "twellington", "clank-app-team@google.com" ],
-    "expiry_milestone": 114
+    "owners": [ "aishwaryarj", "skavuluru@google.com", "twellington", "clank-app-team@google.com" ],
+    "expiry_milestone": 116
   },
   {
     "name": "request-desktop-site-per-site-iph",
@@ -7105,8 +7098,11 @@
   },
   {
     "name": "translate-message-ui",
-    "owners": [ "sclittle", "chrome-language@google.com" ],
-    "expiry_milestone": 114
+    "owners": [
+      "basiaz@google.com",
+      "chrome-language@google.com"
+    ],
+    "expiry_milestone": 117
   },
   {
     "name": "trending-queries-module",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ee39d88..bf1d47ae 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1960,11 +1960,6 @@
     "If enabled Mojo on Linux based platforms can use shared memory as an "
     "alternate channel for most messages.";
 
-const char kMouseSubframeNoImplicitCaptureName[] =
-    "Disable mouse implicit capture for iframe";
-const char kMouseSubframeNoImplicitCaptureDescription[] =
-    "When enable, mouse down does not implicit capture for iframe.";
-
 const char kCanvas2DLayersName[] =
     "Enables canvas 2D methods BeginLayer and EndLayer";
 const char kCanvas2DLayersDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f51ad7b..6f80e8d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1102,9 +1102,6 @@
 extern const char kMojoLinuxChannelSharedMemName[];
 extern const char kMojoLinuxChannelSharedMemDescription[];
 
-extern const char kMouseSubframeNoImplicitCaptureName[];
-extern const char kMouseSubframeNoImplicitCaptureDescription[];
-
 extern const char kUsernameFirstFlowFallbackCrowdsourcingName[];
 extern const char kUsernameFirstFlowFallbackCrowdsourcingDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index f07baae..893a017 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -94,6 +94,7 @@
     &autofill::features::kAutofillEnableManualFallbackForVirtualCards,
     &autofill::features::kAutofillKeyboardAccessory,
     &autofill::features::kAutofillManualFallbackAndroid,
+    &autofill::features::kAutofillEnableNewCardArtAndNetworkImages,
     &autofill::features::kAutofillEnableSupportForHonorificPrefixes,
     &autofill::features::kAutofillEnableUpdateVirtualCardEnrollment,
     &autofill::features::kAutofillEnableVirtualCardMetadata,
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 11679417..94d0e799 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
@@ -194,6 +194,8 @@
     public static final String AUTOFILL_ENABLE_CARD_PRODUCT_NAME = "AutofillEnableCardProductName";
     public static final String AUTOFILL_ENABLE_MANUAL_FALLBACK_FOR_VIRTUAL_CARDS =
             "AutofillEnableManualFallbackForVirtualCards";
+    public static final String AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES =
+            "AutofillEnableNewCardArtAndNetworkImages";
     public static final String AUTOFILL_ENABLE_SUPPORT_FOR_HONORIFIC_PREFIXES =
             "AutofillEnableSupportForHonorificPrefixes";
     public static final String AUTOFILL_ENABLE_SUPPORT_FOR_MORE_STRUCTURE_IN_ADDRESSES =
diff --git a/chrome/browser/hid/hid_connection_tracker.cc b/chrome/browser/hid/hid_connection_tracker.cc
index b1307f3..3304d8c 100644
--- a/chrome/browser/hid/hid_connection_tracker.cc
+++ b/chrome/browser/hid/hid_connection_tracker.cc
@@ -74,7 +74,7 @@
   }
 
   if (connection_count_ == 1) {
-    hid_system_tray_icon->AddProfile(profile_);
+    hid_system_tray_icon->StageProfile(profile_);
   } else {
     hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
   }
@@ -88,7 +88,7 @@
   }
 
   if (connection_count_ == 0) {
-    hid_system_tray_icon->RemoveProfile(profile_);
+    hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/false);
   } else {
     hid_system_tray_icon->NotifyConnectionCountUpdated(profile_);
   }
@@ -144,6 +144,6 @@
     connection_count_ = 0;
     auto* hid_system_tray_icon = g_browser_process->hid_system_tray_icon();
     if (hid_system_tray_icon)
-      hid_system_tray_icon->RemoveProfile(profile_);
+      hid_system_tray_icon->UnstageProfile(profile_, /*immediate=*/true);
   }
 }
diff --git a/chrome/browser/hid/hid_connection_tracker_unittest.cc b/chrome/browser/hid/hid_connection_tracker_unittest.cc
index ce691e0..e39d4e8 100644
--- a/chrome/browser/hid/hid_connection_tracker_unittest.cc
+++ b/chrome/browser/hid/hid_connection_tracker_unittest.cc
@@ -56,6 +56,8 @@
 
 class MockHidSystemTrayIcon : public HidSystemTrayIcon {
  public:
+  MOCK_METHOD(void, StageProfile, (Profile*), (override));
+  MOCK_METHOD(void, UnstageProfile, (Profile*, bool), (override));
   MOCK_METHOD(void, AddProfile, (Profile*), (override));
   MOCK_METHOD(void, RemoveProfile, (Profile*), (override));
   MOCK_METHOD(void, NotifyConnectionCountUpdated, (Profile*), (override));
@@ -204,13 +206,14 @@
 }  // namespace
 
 TEST_F(HidConnectionTrackerTest, DeviceConnection) {
-  EXPECT_CALL(hid_system_tray_icon(), AddProfile(profile()));
+  EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile()));
   hid_connection_tracker().IncrementConnectionCount();
   EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
   hid_connection_tracker().IncrementConnectionCount();
   EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
   hid_connection_tracker().DecrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile()));
+  EXPECT_CALL(hid_system_tray_icon(),
+              UnstageProfile(profile(), /*immediate*/ false));
   hid_connection_tracker().DecrementConnectionCount();
 }
 
@@ -226,11 +229,12 @@
 
 TEST_F(HidConnectionTrackerTest, ProfileDestroyed) {
   CreateTestingProfile(kTestProfileName);
-  EXPECT_CALL(hid_system_tray_icon(), AddProfile(profile()));
+  EXPECT_CALL(hid_system_tray_icon(), StageProfile(profile()));
   hid_connection_tracker().IncrementConnectionCount();
   EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile()));
   hid_connection_tracker().IncrementConnectionCount();
-  EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile()));
+  EXPECT_CALL(hid_system_tray_icon(),
+              UnstageProfile(profile(), /*immediate*/ true));
   profile_manager()->DeleteTestingProfile(kTestProfileName);
 }
 
diff --git a/chrome/browser/hid/hid_pinned_notification.h b/chrome/browser/hid/hid_pinned_notification.h
index a66b2bcf..20301283d 100644
--- a/chrome/browser/hid/hid_pinned_notification.h
+++ b/chrome/browser/hid/hid_pinned_notification.h
@@ -20,13 +20,14 @@
   HidPinnedNotification& operator=(const HidPinnedNotification&) = delete;
   ~HidPinnedNotification() override;
 
-  void AddProfile(Profile* profile) override;
-  void RemoveProfile(Profile* profile) override;
   void NotifyConnectionCountUpdated(Profile* profile) override;
 
   static std::string GetNotificationId(Profile* profile);
 
  private:
+  void AddProfile(Profile* profile) override;
+  void RemoveProfile(Profile* profile) override;
+
   // Create a pinned notification for |profile| to indicate at least one HID
   // device is being accessed.
   std::unique_ptr<message_center::Notification> CreateNotification(
diff --git a/chrome/browser/hid/hid_pinned_notification_unittest.cc b/chrome/browser/hid/hid_pinned_notification_unittest.cc
index d287520..0ac245938 100644
--- a/chrome/browser/hid/hid_pinned_notification_unittest.cc
+++ b/chrome/browser/hid/hid_pinned_notification_unittest.cc
@@ -89,6 +89,10 @@
   TestSingleProfile();
 }
 
+TEST_F(HidPinnedNotificationTest, ProfileShownWhileUnstaging) {
+  TestProfileShownWhileUnstaging();
+}
+
 TEST_F(HidPinnedNotificationTest, SingleProfileNonEmptyName) {
   TestSingleProfile();
 }
diff --git a/chrome/browser/hid/hid_status_icon.h b/chrome/browser/hid/hid_status_icon.h
index b914a78..d383aed 100644
--- a/chrome/browser/hid/hid_status_icon.h
+++ b/chrome/browser/hid/hid_status_icon.h
@@ -20,14 +20,15 @@
   HidStatusIcon& operator=(const HidStatusIcon&) = delete;
   ~HidStatusIcon() override;
 
-  void AddProfile(Profile* profile) override;
-  void RemoveProfile(Profile* profile) override;
   void NotifyConnectionCountUpdated(Profile* profile) override;
 
  private:
   // For using ExecuteCommand to simulate button click.
   friend class WebHidExtensionBrowserTest;
 
+  void AddProfile(Profile* profile) override;
+  void RemoveProfile(Profile* profile) override;
+
   // Get the total connection count from all the profiles being tracked.
   size_t GetTotalConnectionCount();
 
diff --git a/chrome/browser/hid/hid_status_icon_unittest.cc b/chrome/browser/hid/hid_status_icon_unittest.cc
index eb88be2..543bd32a 100644
--- a/chrome/browser/hid/hid_status_icon_unittest.cc
+++ b/chrome/browser/hid/hid_status_icon_unittest.cc
@@ -153,6 +153,10 @@
   TestSingleProfile();
 }
 
+TEST_F(HidStatusIconTest, ProfileShownWhileUnstaging) {
+  TestProfileShownWhileUnstaging();
+}
+
 TEST_F(HidStatusIconTest, MultipleProfiles) {
   TestMultipleProfiles();
 }
diff --git a/chrome/browser/hid/hid_system_tray_icon.cc b/chrome/browser/hid/hid_system_tray_icon.cc
index 5bc8adff..5a9dcd0 100644
--- a/chrome/browser/hid/hid_system_tray_icon.cc
+++ b/chrome/browser/hid/hid_system_tray_icon.cc
@@ -6,14 +6,35 @@
 
 #include <vector>
 
+#include "base/containers/cxx20_erase.h"
+#include "base/functional/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
+#include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 
+namespace {
+
+bool ContainsProfile(const std::vector<base::WeakPtr<Profile>>& profiles,
+                     Profile* profile) {
+  return base::ranges::count_if(profiles, [profile](const auto& entry) {
+           return entry && entry.get() == profile;
+         }) > 0;
+}
+
+size_t EraseProfile(std::vector<base::WeakPtr<Profile>>& profiles,
+                    Profile* profile) {
+  return base::EraseIf(profiles, [profile](const auto& entry) {
+    return entry && entry.get() == profile;
+  });
+}
+
+}  // namespace
+
 // static
 gfx::ImageSkia HidSystemTrayIcon::GetStatusTrayIcon() {
   return gfx::CreateVectorIcon(vector_icons::kVideogameAssetIcon,
@@ -39,3 +60,57 @@
   return l10n_util::GetPluralStringFUTF16(IDS_WEBHID_SYSTEM_TRAY_ICON_TOOLTIP,
                                           static_cast<int>(num_devices));
 }
+
+HidSystemTrayIcon::HidSystemTrayIcon() = default;
+HidSystemTrayIcon::~HidSystemTrayIcon() = default;
+
+void HidSystemTrayIcon::StageProfile(Profile* profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (EraseProfile(unstaging_profiles_, profile) > 0) {
+    // Connection tracker's connection count is updated even the profile is just
+    // moved from unstaging to staging.
+    NotifyConnectionCountUpdated(profile);
+    return;
+  }
+  AddProfile(profile);
+}
+
+void HidSystemTrayIcon::UnstageProfile(Profile* profile, bool immediate) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (immediate) {
+    RemoveProfile(profile);
+    EraseProfile(unstaging_profiles_, profile);
+    return;
+  }
+  if (ContainsProfile(unstaging_profiles_, profile)) {
+    return;
+  }
+  // In order to avoid bouncing the system tray icon, schedule |profile| to be
+  // removed from the system tray icon later.
+  unstaging_profiles_.push_back(profile->GetWeakPtr());
+  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+      ->PostDelayedTask(
+          FROM_HERE,
+          // This class is supposedly safe as it is owned by
+          // g_browser_process. However, to avoid corner
+          // scenarios in tests, use weak ptr just to be safe.
+          base::BindOnce(&HidSystemTrayIcon::CleanUpProfiles,
+                         weak_factory_.GetWeakPtr(), profile->GetWeakPtr()),
+          kProfileUnstagingTime);
+  // Connection tracker's connection count is updated even in scheduled
+  // removal case.
+  NotifyConnectionCountUpdated(profile);
+}
+
+void HidSystemTrayIcon::CleanUpProfiles(base::WeakPtr<Profile> profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (profile) {
+    if (EraseProfile(unstaging_profiles_, profile.get()) > 0) {
+      RemoveProfile(profile.get());
+    }
+    return;
+  }
+  // When removing |profile| from |unstaging_profiles_|, cleans up other
+  // destroyed profiles too as it loops through the |unstaging_profiles_|.
+  base::EraseIf(unstaging_profiles_, [](const auto& entry) { return !entry; });
+}
diff --git a/chrome/browser/hid/hid_system_tray_icon.h b/chrome/browser/hid/hid_system_tray_icon.h
index 5bb644d..06472b05 100644
--- a/chrome/browser/hid/hid_system_tray_icon.h
+++ b/chrome/browser/hid/hid_system_tray_icon.h
@@ -7,27 +7,36 @@
 
 #include <string>
 
+#include "base/containers/flat_set.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "ui/gfx/image/image_skia.h"
 
 class Profile;
 
 class HidSystemTrayIcon {
  public:
-  HidSystemTrayIcon() = default;
+  HidSystemTrayIcon();
   HidSystemTrayIcon(const HidSystemTrayIcon&) = delete;
   HidSystemTrayIcon& operator=(const HidSystemTrayIcon&) = delete;
-  virtual ~HidSystemTrayIcon() = default;
+  virtual ~HidSystemTrayIcon();
 
-  // Add a profile to the system tray icon.
-  virtual void AddProfile(Profile* profile) = 0;
+  // Stage |profile| to be shown in the system tray icon.
+  virtual void StageProfile(Profile* profile);
 
-  // Remove a profile from the system tray icon.
-  virtual void RemoveProfile(Profile* profile) = 0;
+  // Unstage |profile| that is being shown in the system tray icon. The profile
+  // will be removed immediately when |immediate| is true, otherwise it is
+  // scheduled to be removed later.
+  virtual void UnstageProfile(Profile* profile, bool immediate);
 
   // Notify the system tray icon the connection count of the |profile| has
   // changed.
   virtual void NotifyConnectionCountUpdated(Profile* profile) = 0;
 
+  // The time period that a profile is shown in the system tray icon while it is
+  // unstaging.
+  static constexpr base::TimeDelta kProfileUnstagingTime = base::Seconds(10);
+
  protected:
   // Get the image for the status tray icon.
   static gfx::ImageSkia GetStatusTrayIcon();
@@ -38,6 +47,27 @@
 
   // Get the label of the tooltip of the HID system tray icon.
   static std::u16string GetTooltipLabel(size_t num_devices);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(HidSystemTrayIconTest, UnstageProfile);
+  FRIEND_TEST_ALL_PREFIXES(HidSystemTrayIconTest,
+                           CallbackAfterHidSystemTrayIconDestroyed);
+
+  // Add a profile to the system tray icon.
+  virtual void AddProfile(Profile* profile) = 0;
+
+  // Remove a profile from the system tray icon.
+  virtual void RemoveProfile(Profile* profile) = 0;
+
+  // Remove |profile| from the system tray icon if it is still in
+  // |unstaging_profiles_|.
+  void CleanUpProfiles(base::WeakPtr<Profile> profile);
+
+  // A list of profiles that are unstaging, which are scheduled to be removed.
+  // later.
+  std::vector<base::WeakPtr<Profile>> unstaging_profiles_;
+
+  base::WeakPtrFactory<HidSystemTrayIcon> weak_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_HID_HID_SYSTEM_TRAY_ICON_H_
diff --git a/chrome/browser/hid/hid_system_tray_icon_unittest.cc b/chrome/browser/hid/hid_system_tray_icon_unittest.cc
index 5a44059f..0fb2e8c 100644
--- a/chrome/browser/hid/hid_system_tray_icon_unittest.cc
+++ b/chrome/browser/hid/hid_system_tray_icon_unittest.cc
@@ -4,14 +4,17 @@
 
 #include "chrome/browser/hid/hid_system_tray_icon_unittest.h"
 
+#include <memory>
 #include <string>
 
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/hid/hid_connection_tracker.h"
 #include "chrome/browser/hid/hid_connection_tracker_factory.h"
+#include "chrome/browser/hid/hid_system_tray_icon.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -20,6 +23,17 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace {
+
+bool ContainsProfile(std::vector<base::WeakPtr<Profile>> profiles,
+                     Profile* profile) {
+  return base::ranges::count_if(profiles, [profile](const auto& entry) {
+           return entry && entry.get() == profile;
+         }) > 0;
+}
+
+}  // namespace
+
 MockHidConnectionTracker::MockHidConnectionTracker(Profile* profile)
     : HidConnectionTracker(profile) {}
 
@@ -95,9 +109,51 @@
   CheckIcon({{profile, 1}});
 
   hid_connection_tracker->DecrementConnectionCount();
+  task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
   CheckIconHidden();
 }
 
+void HidSystemTrayIconTestBase::TestProfileShownWhileUnstaging() {
+  Profile* profile = CreateTestingProfile("user");
+  HidConnectionTracker* hid_connection_tracker =
+      HidConnectionTrackerFactory::GetForProfile(profile, /*create=*/true);
+  CheckIconHidden();
+
+  // Check the profile is visible while unstaging during 1000ms interval and
+  // removed after that.
+  {
+    hid_connection_tracker->IncrementConnectionCount();
+    CheckIcon({{profile, 1}});
+
+    hid_connection_tracker->DecrementConnectionCount();
+    task_environment()->FastForwardBy(base::Seconds(6));
+    // Connection count is updated immediately while the profile is scheduled
+    // to be removed later.
+    CheckIcon({{profile, 0}});
+    task_environment()->FastForwardBy(base::Seconds(4));
+    CheckIconHidden();
+  }
+
+  // Simulate bouncing the device connection and make sure the profile exist
+  // during 1000ms interval and removed eventually.
+  {
+    hid_connection_tracker->IncrementConnectionCount();
+    CheckIcon({{profile, 1}});
+    hid_connection_tracker->DecrementConnectionCount();
+    CheckIcon({{profile, 0}});
+    hid_connection_tracker->IncrementConnectionCount();
+    CheckIcon({{profile, 1}});
+    hid_connection_tracker->DecrementConnectionCount();
+    CheckIcon({{profile, 0}});
+    hid_connection_tracker->IncrementConnectionCount();
+    CheckIcon({{profile, 1}});
+    hid_connection_tracker->DecrementConnectionCount();
+    CheckIcon({{profile, 0}});
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    CheckIconHidden();
+  }
+}
+
 void HidSystemTrayIconTestBase::TestMultipleProfiles() {
   size_t num_profiles = 3;
   std::vector<Profile*> profiles;
@@ -121,13 +177,184 @@
   CheckIcon({{profiles[0], 1}, {profiles[1], 1}, {profiles[2], 1}});
 
   // Destroyed a profile will remove it from being tracked in the hid system
-  // tray icon.
+  // tray icon immediately.
   profile_manager()->DeleteTestingProfile(profiles[0]->GetProfileUserName());
   CheckIcon({{profiles[1], 1}, {profiles[2], 1}});
 
+  // The remaining two profiles are removed 5 seconds apart.
   hid_connection_trackers[2]->DecrementConnectionCount();
-  CheckIcon({{profiles[1], 1}});
+  // Connection count is updated immediately while the profile is scheduled
+  // to be removed later.
+  CheckIcon({{profiles[1], 1}, {profiles[2], 0}});
 
+  task_environment()->FastForwardBy(base::Seconds(5));
   hid_connection_trackers[1]->DecrementConnectionCount();
+  CheckIcon({{profiles[1], 0}, {profiles[2], 0}});
+
+  task_environment()->FastForwardBy(base::Seconds(5));
+  CheckIcon({{profiles[1], 0}});
+  task_environment()->FastForwardBy(base::Seconds(5));
   CheckIconHidden();
 }
+
+class MockHidSystemTrayIcon : public HidSystemTrayIcon {
+ public:
+  MOCK_METHOD(void, AddProfile, (Profile*), (override));
+  MOCK_METHOD(void, RemoveProfile, (Profile*), (override));
+  MOCK_METHOD(void, NotifyConnectionCountUpdated, (Profile*), (override));
+};
+
+class HidSystemTrayIconTest : public HidSystemTrayIconTestBase {
+ public:
+  void SetUp() override {
+    HidSystemTrayIconTestBase::SetUp();
+    hid_system_tray_icon_ = std::make_unique<MockHidSystemTrayIcon>();
+  }
+
+  // HidSystemTrayIconTestBase
+  void CheckIcon(const std::vector<std::pair<Profile*, size_t>>&
+                     profile_connection_counts) override {}
+  void CheckIconHidden() override {}
+
+  MockHidSystemTrayIcon& hid_system_tray_icon() {
+    return *hid_system_tray_icon_.get();
+  }
+
+ private:
+  std::unique_ptr<MockHidSystemTrayIcon> hid_system_tray_icon_;
+};
+
+TEST_F(HidSystemTrayIconTest, UnstageProfile) {
+  Profile* profile = CreateTestingProfile("user");
+
+  // When immediate flag is set to true.
+  {
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ true);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // When immediate flag is set to false.
+  {
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile)).Times(0);
+    EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    EXPECT_TRUE(
+        ContainsProfile(hid_system_tray_icon().unstaging_profiles_, profile));
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile));
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // A profile is scheduled to be removed followed by an immediate removal
+  // request.
+  {
+    EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ true);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile)).Times(0);
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // A profile is scheduled to be removed then stage profile request comes in.
+  {
+    // NotifyConnectionCountUpdated is called twice: once when the profile is
+    // unstaged, and again when the profile is staged.
+    EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile))
+        .Times(2);
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    EXPECT_CALL(hid_system_tray_icon(), AddProfile(profile)).Times(0);
+    hid_system_tray_icon().StageProfile(profile);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile)).Times(0);
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // Back-to-back requests of scheduled profile removal.
+  {
+    EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile));
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // CleanUpProfiles is called after an unstaging profile is destroyed.
+  {
+    Profile* profile_to_be_destroyed = CreateTestingProfile("user2");
+    EXPECT_CALL(hid_system_tray_icon(),
+                NotifyConnectionCountUpdated(profile_to_be_destroyed));
+    hid_system_tray_icon().UnstageProfile(profile_to_be_destroyed,
+                                          /*immediate*/ false);
+
+    profile_manager()->DeleteTestingProfile(
+        profile_to_be_destroyed->GetProfileUserName());
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile_to_be_destroyed))
+        .Times(0);
+    task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+    // The |unstaging_profiles_| should still be cleared to empty.
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+
+  // Two profiles removed 5 seconds apart.
+  {
+    Profile* second_profile = CreateTestingProfile("user2");
+    EXPECT_CALL(hid_system_tray_icon(), NotifyConnectionCountUpdated(profile));
+    hid_system_tray_icon().UnstageProfile(profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    task_environment()->FastForwardBy(base::Seconds(5));
+    EXPECT_CALL(hid_system_tray_icon(),
+                NotifyConnectionCountUpdated(second_profile));
+    hid_system_tray_icon().UnstageProfile(second_profile, /*immediate*/ false);
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 2u);
+
+    // 10 seconds later, |profile| is removed.
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(profile));
+    task_environment()->FastForwardBy(base::Seconds(5));
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 1u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+
+    // 15 second later, |second_profile) is removed.
+    EXPECT_CALL(hid_system_tray_icon(), RemoveProfile(second_profile));
+    task_environment()->FastForwardBy(base::Seconds(5));
+    EXPECT_EQ(hid_system_tray_icon().unstaging_profiles_.size(), 0u);
+    testing::Mock::VerifyAndClearExpectations(&hid_system_tray_icon());
+  }
+}
+
+// This test case just to make sure it can run through the scenario without
+// causing any unexpected crash.
+TEST_F(HidSystemTrayIconTest, CallbackAfterHidSystemTrayIconDestroyed) {
+  Profile* profile = CreateTestingProfile("user");
+  auto hid_system_tray_icon = std::make_unique<MockHidSystemTrayIcon>();
+  EXPECT_CALL(*hid_system_tray_icon, NotifyConnectionCountUpdated(profile));
+  hid_system_tray_icon->UnstageProfile(profile, /*immediate*/ false);
+  EXPECT_EQ(hid_system_tray_icon->unstaging_profiles_.size(), 1u);
+  EXPECT_TRUE(
+      ContainsProfile(hid_system_tray_icon->unstaging_profiles_, profile));
+
+  hid_system_tray_icon.reset();
+  task_environment()->FastForwardBy(HidSystemTrayIcon::kProfileUnstagingTime);
+}
diff --git a/chrome/browser/hid/hid_system_tray_icon_unittest.h b/chrome/browser/hid/hid_system_tray_icon_unittest.h
index a29dae1..af07d78 100644
--- a/chrome/browser/hid/hid_system_tray_icon_unittest.h
+++ b/chrome/browser/hid/hid_system_tray_icon_unittest.h
@@ -22,6 +22,9 @@
 
 class HidSystemTrayIconTestBase : public BrowserWithTestWindowTest {
  public:
+  HidSystemTrayIconTestBase()
+      : BrowserWithTestWindowTest(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
   // Check if the hid system tray icon is shown and all the action buttons work
   // correctly with the given |profile_connection_counts|.
   virtual void CheckIcon(const std::vector<std::pair<Profile*, size_t>>&
@@ -44,6 +47,9 @@
   // destruction.
   void TestMultipleProfiles();
 
+  // Test the scenario when a profile is unstaging.
+  void TestProfileShownWhileUnstaging();
+
   // Test the scenario with single profile.
   void TestSingleProfile();
 };
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
index bc562d2..a8fc650 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialog.java
@@ -60,7 +60,8 @@
     /** Annotation for row item type. Either a LanguageItem or separator */
     @IntDef({ItemType.LANGUAGE, ItemType.SEPARATOR, ItemType.MORE_LANGUAGES})
     @Retention(RetentionPolicy.SOURCE)
-    private @interface ItemType {
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @interface ItemType {
         int LANGUAGE = 0;
         int SEPARATOR = 1;
         int MORE_LANGUAGES = 2;
@@ -212,12 +213,16 @@
 
         /**
          * Set the currently selected LanguageItem based on the position.
-         * TODO(https://crbug.com/1325522) Refactor to not use notifyDataSetChanged.
          * @param position Offset of the LanguageItem to select.
          */
         public void setSelectedLanguage(int position) {
+            int oldPosition = getPositionForLanguageItem(mCurrentLanguage);
+            // Exit early if the current language was selected
+            if (oldPosition == position) return;
+
             mCurrentLanguage = getLanguageItemAt(position);
-            notifyDataSetChanged();
+            notifyItemChanged(oldPosition);
+            notifyItemChanged(position);
         }
 
         /**
@@ -246,7 +251,8 @@
             return mShowOtherLanguages;
         }
 
-        protected LanguageItem getLanguageItemAt(int position) {
+        @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+        LanguageItem getLanguageItemAt(int position) {
             if (position < mTopLanguages.size()) {
                 return mTopLanguages.get(position);
             } else if (position > mTopLanguages.size()) {
@@ -256,6 +262,19 @@
             assert false : "The language item at the separator can not be accessed";
             return null;
         }
+
+        @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+        int getPositionForLanguageItem(LanguageItem languageItem) {
+            int position = mTopLanguages.indexOf(languageItem);
+            // Return the position if |languageItem| is found in top languages.
+            if (position != -1) return position;
+
+            position = mOtherLanguages.indexOf(languageItem);
+            // If |languageItem| is in other languages add the size of the top languages
+            // plus one for the separator.
+            if (position != -1) return position + mTopLanguages.size() + 1;
+            return -1;
+        }
     }
 
     /**
@@ -322,7 +341,6 @@
 
         @Override
         public void onClick(View row) {
-            // TODO(https://crbug.com/1325471) Add meteric recording action.
             LanguageItemAdapter adapter = (LanguageItemAdapter) getBindingAdapter();
             adapter.showOtherLanguages();
         }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialogTest.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialogTest.java
index 79424a4b..8838c69 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialogTest.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLanguagePromoDialogTest.java
@@ -27,6 +27,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LinkedHashSet;
 
 /**
@@ -44,6 +45,7 @@
     LanguageItem mLangAz;
     LanguageItem mLangEnGb;
     LanguageItem mLangEnUs;
+    LanguageItem mLangEs;
     LanguageItem mLangZu;
     // List of potential UI languages.
     LinkedHashSet<LanguageItem> mUiLanguages;
@@ -82,6 +84,7 @@
         mLangEnGb = new LanguageItem("en-GB", "English (UK)", "English (UK)", true);
         mLangEnUs = new LanguageItem(
                 "en-US", "English (United States)", "English (United States", true);
+        mLangEs = new LanguageItem("es", "Spanish", "español", true);
         mLangZu = new LanguageItem("zu", "Zulu", "isiZulu", true);
         mUiLanguages =
                 new LinkedHashSet<>(Arrays.asList(mLangAf, mLangAz, mLangEnGb, mLangEnUs, mLangZu));
@@ -162,7 +165,7 @@
                 new ArrayList<>(topLanguages), Arrays.asList(mFollowSystem, mLangAf, mLangZu));
     }
 
-    // Test isOverrideLanguageOriginalSystemLanguage
+    // Test getPotentialUILanguage
     @Test
     @SmallTest
     public void testGetPotentialUILanguage() {
@@ -180,23 +183,100 @@
                 AppLanguagePromoDialog.getPotentialUILanguage("es-419", uiLanguages), "es-419");
     }
 
-    // Test LanguageItemAdapter
+    // Test LanguageItemAdapter getItemCount
     @Test
     @SmallTest
-    public void testLanguageItemAdapter() {
-        ArrayList<LanguageItem> topLanguages = new ArrayList<>(Arrays.asList(mLangAf, mLangAz));
-        ArrayList<LanguageItem> otherLanguages =
-                new ArrayList<>(Arrays.asList(mLangEnGb, mLangEnUs, mLangZu));
-        LanguageItem currentLanguage = mLangAf;
+    public void testLanguageItemAdapterGetItemCount() {
         LanguageItemAdapter adapter =
-                new LanguageItemAdapter(topLanguages, otherLanguages, currentLanguage);
+                makeLanguageItemAdapter(Arrays.asList(mLangAf, mLangAz), // top languages
+                        Arrays.asList(mLangEnGb, mLangEnUs, mLangZu), // other languages,
+                        mLangAf // current language
+                );
 
         // Only the top languages plus "More languages" item are showing to start.
         Assert.assertEquals(3, adapter.getItemCount());
+        Assert.assertFalse(adapter.areOtherLanguagesShown());
 
         adapter.showOtherLanguages();
         // All languages should now be showing.
         Assert.assertEquals(6, adapter.getItemCount());
+        Assert.assertTrue(adapter.areOtherLanguagesShown());
+    }
+
+    // Test LanguageItemAdapter getLanguageItemAt
+    @Test
+    @SmallTest
+    public void testLanguageItemAdapterGetLanguageItemAt() {
+        LanguageItemAdapter adapter =
+                makeLanguageItemAdapter(Arrays.asList(mLangAf, mLangAz), // top languages
+                        Arrays.asList(mLangEnGb, mLangEnUs, mLangZu), // other languages,
+                        mLangAf // current language
+                );
+
+        Assert.assertEquals(mLangAz, adapter.getLanguageItemAt(1)); // topLanguage
+        Assert.assertEquals(mLangEnGb, adapter.getLanguageItemAt(3)); // otherLanguage
+        Assert.assertThrows(AssertionError.class, () -> adapter.getLanguageItemAt(2)); // separator
+    }
+
+    // Test LanguageItemAdapter getPositionForLanguageItem
+    @Test
+    @SmallTest
+    public void testLanguageItemAdapterGetPositionForLanguageItem() {
+        LanguageItemAdapter adapter =
+                makeLanguageItemAdapter(Arrays.asList(mLangAf, mLangAz), // top languages
+                        Arrays.asList(mLangEnGb, mLangEnUs, mLangZu), // other languages,
+                        mLangAf // current language
+                );
+
+        Assert.assertEquals(1, adapter.getPositionForLanguageItem(mLangAz)); // topLanguage
+        Assert.assertEquals(3, adapter.getPositionForLanguageItem(mLangEnGb)); // otherLanguage
+        Assert.assertEquals(-1, adapter.getPositionForLanguageItem(mLangEs)); // not found
+    }
+
+    // Test LanguageItemAdapter getItemViewType
+    @Test
+    @SmallTest
+    public void testLanguageItemAdapterGetItemViewType() {
+        LanguageItemAdapter adapter =
+                makeLanguageItemAdapter(Arrays.asList(mLangAf, mLangAz), // top languages
+                        Arrays.asList(mLangEnGb, mLangEnUs, mLangZu), // other languages,
+                        mLangAf // current language
+                );
+
+        // More Languages is showing to start
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(0));
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(1));
+        Assert.assertEquals(
+                AppLanguagePromoDialog.ItemType.MORE_LANGUAGES, adapter.getItemViewType(2));
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(4));
+
+        adapter.showOtherLanguages();
+
+        // The separator is showing after
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(0));
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(1));
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.SEPARATOR, adapter.getItemViewType(2));
+        Assert.assertEquals(AppLanguagePromoDialog.ItemType.LANGUAGE, adapter.getItemViewType(4));
+    }
+
+    // Test LanguageItemAdapter setSelectedLanguage
+    @Test
+    @SmallTest
+    public void testLanguageItemAdapterSetSelectedLanguage() {
+        LanguageItemAdapter adapter =
+                makeLanguageItemAdapter(Arrays.asList(mLangAf, mLangAz), // top languages
+                        Arrays.asList(mLangEnGb, mLangEnUs, mLangZu), // other languages,
+                        mLangAf // current language
+                );
+
+        Assert.assertTrue(adapter.isTopLanguageSelected());
+        Assert.assertEquals(mLangAf, adapter.getSelectedLanguage());
+        adapter.setSelectedLanguage(1);
+        Assert.assertEquals(mLangAz, adapter.getSelectedLanguage());
+        Assert.assertThrows(AssertionError.class, () -> adapter.setSelectedLanguage(2));
+        adapter.setSelectedLanguage(4);
+        Assert.assertFalse(adapter.isTopLanguageSelected());
+        Assert.assertEquals(mLangEnUs, adapter.getSelectedLanguage());
     }
 
     // Test shouldShowPrompt conditions
@@ -238,4 +318,11 @@
         ShadowChromeFeatureList.sEnableForceAppLanguagePrompt = true;
         Assert.assertTrue(AppLanguagePromoDialog.shouldShowPrompt(online));
     }
+
+    private static LanguageItemAdapter makeLanguageItemAdapter(
+            Collection<LanguageItem> topLanguages, Collection<LanguageItem> otherLanguages,
+            LanguageItem currentLanguage) {
+        return new AppLanguagePromoDialog.LanguageItemAdapter(
+                topLanguages, otherLanguages, currentLanguage);
+    }
 }
diff --git a/chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc
index 66b363d..e4065f4 100644
--- a/chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc
@@ -13,9 +13,9 @@
 namespace {
 
 const char kSearchInputToNavigationStart[] =
-    "Omnibox.SuggestionUsed.Search.InputToNavigationStart";
+    "Omnibox.SuggestionUsed.Search.InputToNavigationStart2";
 const char kURLInputToNavigationStart[] =
-    "Omnibox.SuggestionUsed.URL.InputToNavigationStart";
+    "Omnibox.SuggestionUsed.URL.InputToNavigationStart2";
 
 const char kSearchFirstContentfulPaint[] =
     "Omnibox.SuggestionUsed.Search.NavigationToFirstContentfulPaint";
@@ -84,15 +84,21 @@
     if (ui::PageTransitionCoreTypeIs(transition_type_,
                                      ui::PAGE_TRANSITION_GENERATED)) {
       if (timing.input_to_navigation_start) {
-        PAGE_LOAD_HISTOGRAM(kSearchInputToNavigationStart,
-                            timing.input_to_navigation_start.value());
+        // Use `PAGE_LOAD_SHORT_HISTOGRAM()`, and not `PAGE_LOAD_HISTOGRAM()`,
+        // as this has many (30-55%) of events <10ms, and almost no events
+        // >1minute.
+        PAGE_LOAD_SHORT_HISTOGRAM(kSearchInputToNavigationStart,
+                                  timing.input_to_navigation_start.value());
       }
       PAGE_LOAD_HISTOGRAM(kSearchFirstContentfulPaint, fcp);
     } else if (ui::PageTransitionCoreTypeIs(transition_type_,
                                             ui::PAGE_TRANSITION_TYPED)) {
       if (timing.input_to_navigation_start) {
-        PAGE_LOAD_HISTOGRAM(kURLInputToNavigationStart,
-                            timing.input_to_navigation_start.value());
+        // Use `PAGE_LOAD_SHORT_HISTOGRAM()`, and not `PAGE_LOAD_HISTOGRAM()`,
+        // as this has many (30-55%) of events <10ms, and almost no events
+        // >1minute.
+        PAGE_LOAD_SHORT_HISTOGRAM(kURLInputToNavigationStart,
+                                  timing.input_to_navigation_start.value());
       }
       PAGE_LOAD_HISTOGRAM(kURLFirstContentfulPaint, fcp);
     }
diff --git a/chrome/browser/performance_manager/mechanisms/page_discarder.cc b/chrome/browser/performance_manager/mechanisms/page_discarder.cc
index 809a05a..ada64e35 100644
--- a/chrome/browser/performance_manager/mechanisms/page_discarder.cc
+++ b/chrome/browser/performance_manager/mechanisms/page_discarder.cc
@@ -7,6 +7,7 @@
 #include "base/functional/bind.h"
 #include "base/task/task_traits.h"
 #include "build/build_config.h"
+#include "chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -71,9 +72,10 @@
     base::OnceCallback<void(bool)> post_discard_cb) {
   std::vector<std::pair<WebContentsProxy, uint64_t>> proxies_and_pmf;
   proxies_and_pmf.reserve(page_nodes.size());
-  for (auto* page_node : page_nodes) {
-    proxies_and_pmf.emplace_back(page_node->GetContentsProxy(),
-                                 page_node->EstimatePrivateFootprintSize());
+  for (const auto* page_node : page_nodes) {
+    proxies_and_pmf.emplace_back(
+        page_node->GetContentsProxy(),
+        user_tuning::GetDiscardedMemoryEstimateForPage(page_node));
   }
   content::GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(
       FROM_HERE,
diff --git a/chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h b/chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h
index 76238a5..55f407cc 100644
--- a/chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h
+++ b/chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_USER_TUNING_UTILS_H_
 #define CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_USER_TUNING_UTILS_H_
 
+#include "components/performance_manager/public/graph/page_node.h"
+
 namespace performance_manager::user_tuning {
 
 // Convenience shortcut for metrics code.
@@ -12,6 +14,17 @@
 // mode is currently active.
 bool IsRefreshRateThrottled();
 
+// Helper for logic to get the memory footprint estimate for a discarded page.
+// This must be called from the |PerformanceManager| sequence.
+uint64_t GetDiscardedMemoryEstimateForPage(
+    const performance_manager::PageNode* node);
+
+// Gets the discarded memory estimate and then calls the |result_callback| with
+// the memory estimate. This must be called on the UI Thread.
+void GetDiscardedMemoryEstimateForWebContents(
+    content::WebContents* web_contents,
+    base::OnceCallback<void(uint64_t)> result_callback);
+
 }  // namespace performance_manager::user_tuning
 
 #endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_PUBLIC_USER_TUNING_USER_TUNING_UTILS_H_
diff --git a/chrome/browser/performance_manager/user_tuning/user_tuning_utils.cc b/chrome/browser/performance_manager/user_tuning/user_tuning_utils.cc
index 25bce96a..6b51409 100644
--- a/chrome/browser/performance_manager/user_tuning/user_tuning_utils.cc
+++ b/chrome/browser/performance_manager/user_tuning/user_tuning_utils.cc
@@ -9,6 +9,10 @@
 #include "build/buildflag.h"
 #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
 #include "components/performance_manager/public/features.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/performance_manager.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace performance_manager::user_tuning {
 
@@ -27,4 +31,32 @@
 #endif
 }
 
+uint64_t GetDiscardedMemoryEstimateForPage(const PageNode* node) {
+  DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph());
+
+  return node->EstimatePrivateFootprintSize();
+}
+
+void GetDiscardedMemoryEstimateForWebContents(
+    content::WebContents* web_contents,
+    base::OnceCallback<void(uint64_t)> result_callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  base::WeakPtr<PageNode> page_node =
+      PerformanceManager::GetPrimaryPageNodeForWebContents(web_contents);
+  PerformanceManager::CallOnGraph(
+      FROM_HERE,
+      base::BindOnce(
+          [](base::WeakPtr<PageNode> page_node,
+             base::OnceCallback<void(uint64_t)> result_callback) {
+            uint64_t estimate =
+                page_node ? GetDiscardedMemoryEstimateForPage(page_node.get())
+                          : 0;
+            content::GetUIThreadTaskRunner({})->PostTask(
+                FROM_HERE,
+                base::BindOnce(std::move(result_callback), estimate));
+          },
+          page_node, std::move(result_callback)));
+}
+
 }  //  namespace performance_manager::user_tuning
diff --git a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.cc b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.cc
index 097a9ed..2fc75186 100644
--- a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.cc
+++ b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.cc
@@ -11,15 +11,19 @@
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/policy/messaging_layer/upload/network_condition_service.h"
 #include "components/reporting/proto/synced/record.pb.h"
+#include "event_upload_size_controller.h"
+#include "file_upload_impl.h"
 
 namespace reporting {
 
 EventUploadSizeController::EventUploadSizeController(
     const NetworkConditionService& network_condition_service,
     uint64_t new_events_rate,
-    uint64_t remaining_storage_capacity)
+    uint64_t remaining_storage_capacity,
+    uint64_t max_file_upload_buffer_size)
     : new_events_rate_(new_events_rate > 0 ? new_events_rate : 1),
       remaining_storage_capacity_(remaining_storage_capacity),
+      max_file_upload_buffer_size_(max_file_upload_buffer_size),
       max_upload_size_(ComputeMaxUploadSize(network_condition_service)) {
   base::UmaHistogramCounts10000(
       "Browser.ERP.EventUploadSizeAdjustment.NewEventsRate", new_events_rate_);
@@ -39,7 +43,11 @@
 
 void EventUploadSizeController::AccountForRecord(
     const EncryptedRecord& record) {
-  uploaded_size_ += record.ByteSizeLong();
+  AccountForData(record.ByteSizeLong());
+}
+
+void EventUploadSizeController::AccountForData(size_t size) {
+  uploaded_size_ += size;
 }
 
 // static
@@ -77,6 +85,13 @@
   for (auto& record : encrypted_records) {
     // Check if we have uploaded enough records after adding each record
     controller.AccountForRecord(record);
+    if (record.has_record_copy()) {
+      // Add potential maximum upload size.
+      // Given that the records featuring upload are rare, this should not
+      // significantly impact the capacity. Each event usually triggers the
+      // buffer-size upload, so we reserve that much.
+      controller.AccountForData(controller.max_file_upload_buffer_size_);
+    }
     records.push_back(std::move(record));
     if (controller.IsMaximumUploadSizeReached()) {
       break;
diff --git a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h
index 15b300e..cb9f1af 100644
--- a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h
+++ b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller.h
@@ -37,7 +37,8 @@
   EventUploadSizeController(
       const NetworkConditionService& network_condition_service,
       uint64_t new_events_rate,
-      uint64_t remaining_storage_capacity);
+      uint64_t remaining_storage_capacity,
+      uint64_t max_file_upload_buffer_size);
 
   // Build the vector of encrypted records based on the records in the upload
   // request. Event upload size is adjusted.
@@ -50,6 +51,7 @@
   friend class EventUploadSizeControllerTest;
   FRIEND_TEST_ALL_PREFIXES(EventUploadSizeControllerTest,
                            AccountForRecordAddUp);
+  FRIEND_TEST_ALL_PREFIXES(EventUploadSizeControllerTest, AccountForFileUpload);
 
   // The maximum time in seconds during which a single connection should
   // remain open, a constant set heuristically.
@@ -75,11 +77,15 @@
   bool IsMaximumUploadSizeReached() const;
   // Bumps up by the size of the record to be uploaded.
   void AccountForRecord(const EncryptedRecord& record);
+  // Bumpls up by the size of the data chunk to be uploaded;
+  void AccountForData(size_t size);
 
   // The rate (bytes per seconds) at which new events are accepted by missive.
   const uint64_t new_events_rate_;
   // How much local storage is left as informed by missive.
   const uint64_t remaining_storage_capacity_;
+  // maximum file upl
+  const uint64_t max_file_upload_buffer_size_;
   // maximum upload size.
   const uint64_t max_upload_size_;
   // Already uploaded size.
diff --git a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller_unittest.cc b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller_unittest.cc
index 3cfc895..822b396 100644
--- a/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller_unittest.cc
+++ b/chrome/browser/policy/messaging_layer/upload/event_upload_size_controller_unittest.cc
@@ -42,7 +42,8 @@
   EventUploadSizeController event_upload_size_controller(
       network_condition_service,
       /*new_events_rate=*/1U,
-      /*remaining_storage_capacity=*/std::numeric_limits<uint64_t>::max());
+      /*remaining_storage_capacity=*/std::numeric_limits<uint64_t>::max(),
+      /*max_file_upload_buffer_size=*/1024UL);
   // This number may change from time to time if we adapt the formula in the
   // future.
   const uint64_t max_upload_size =
@@ -87,6 +88,36 @@
   ASSERT_FALSE(event_upload_size_controller.IsMaximumUploadSizeReached());
 }
 
-// TODO(b/214039157): Add test for |BuildEncryptedRecords|.
+TEST_F(EventUploadSizeControllerTest, AccountForFileUpload) {
+  TestingNetworkConditionService network_condition_service(&task_environment_);
+  network_condition_service.SetUploadRate(10000);
+  EventUploadSizeController event_upload_size_controller(
+      network_condition_service,
+      /*new_events_rate=*/1U,
+      /*remaining_storage_capacity=*/std::numeric_limits<uint64_t>::max(),
+      /*max_file_upload_buffer_size*/ 1024UL);
+  // This number may change from time to time if we adapt the formula in the
+  // future.
+  const uint64_t max_upload_size =
+      event_upload_size_controller.ComputeMaxUploadSize(
+          network_condition_service);
+  LOG(INFO) << "The computed max upload size is " << max_upload_size;
+
+  // Add this single record, accounting for the max data buffer,
+  // make sure |IsMaximumUploadSizeReached| gives the correct answer.
+  ASSERT_FALSE(event_upload_size_controller.IsMaximumUploadSizeReached());
+  event_upload_size_controller.AccountForData(/*size=*/max_upload_size);
+  ASSERT_TRUE(event_upload_size_controller.IsMaximumUploadSizeReached())
+      << "The maximum upload size is not reached when record with copy must "
+         "have been accounted for.";
+
+  // If disabled, |IsMaximumUploadSizeReached| returns false.
+  EventUploadSizeController::Enabler::Set(false);
+  ASSERT_FALSE(EventUploadSizeController::Enabler::Get());
+  ASSERT_FALSE(event_upload_size_controller.IsMaximumUploadSizeReached());
+}
+
+// TODO(b/214039157): Add test for |BuildEncryptedRecords|, including file
+// upload buffer accounting.
 
 }  // namespace reporting
diff --git a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc
index 5e09feb..8d0050b 100644
--- a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc
+++ b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc
@@ -857,7 +857,7 @@
         }
       )"));
 
-  max_upload_buffer_size_ = 1L * 1024L * 1024L;  // 1 MiB
+  max_upload_buffer_size_ = kMaxUploadBufferSize;
 }
 
 std::unique_ptr<OAuth2AccessTokenManager::Request>
diff --git a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.h b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.h
index 2c8988d..7466f6a4 100644
--- a/chrome/browser/policy/messaging_layer/upload/file_upload_impl.h
+++ b/chrome/browser/policy/messaging_layer/upload/file_upload_impl.h
@@ -30,6 +30,8 @@
 
 class FileUploadDelegate : public FileUploadJob::Delegate {
  public:
+  static constexpr int64_t kMaxUploadBufferSize = 1L * 1024L * 1024L;  // 1 MiB
+
   FileUploadDelegate();
   ~FileUploadDelegate() override;
 
diff --git a/chrome/browser/printing/print_backend_browsertest.cc b/chrome/browser/printing/print_backend_browsertest.cc
index d10a186..ddc35c2 100644
--- a/chrome/browser/printing/print_backend_browsertest.cc
+++ b/chrome/browser/printing/print_backend_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/printing/print_backend_service_test_impl.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
@@ -444,6 +445,7 @@
             kDefaultPrinterName);
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest,
                        GetPrinterSemanticCapsAndDefaults) {
   LaunchService();
@@ -493,6 +495,7 @@
   ASSERT_TRUE(printer_caps->is_result_code());
   EXPECT_EQ(printer_caps->get_result_code(), mojom::ResultCode::kAccessDenied);
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, FetchCapabilities) {
   LaunchService();
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc
index 40e9ea2..84d4a27 100644
--- a/chrome/browser/printing/print_backend_service_manager.cc
+++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -21,6 +21,7 @@
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
@@ -235,6 +236,7 @@
                      base::Unretained(this), std::move(context)));
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintBackendServiceManager::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
@@ -256,6 +258,7 @@
           &PrintBackendServiceManager::OnDidGetPrinterSemanticCapsAndDefaults,
           base::Unretained(this), std::move(context)));
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 PrintBackendServiceManager::ContextId
 PrintBackendServiceManager::EstablishPrintingContext(
diff --git a/chrome/browser/printing/print_backend_service_manager.h b/chrome/browser/printing/print_backend_service_manager.h
index 753a073..148a9f91 100644
--- a/chrome/browser/printing/print_backend_service_manager.h
+++ b/chrome/browser/printing/print_backend_service_manager.h
@@ -16,6 +16,7 @@
 #include "base/unguessable_token.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
@@ -132,10 +133,12 @@
       mojom::PrintBackendService::FetchCapabilitiesCallback callback);
   void GetDefaultPrinterName(
       mojom::PrintBackendService::GetDefaultPrinterNameCallback callback);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
           callback);
+#endif
   ContextId EstablishPrintingContext(ClientId client_id,
                                      const std::string& printer_name
 #if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
diff --git a/chrome/browser/printing/print_backend_service_test_impl.cc b/chrome/browser/printing/print_backend_service_test_impl.cc
index 2aa81266..6b077e91 100644
--- a/chrome/browser/printing/print_backend_service_test_impl.cc
+++ b/chrome/browser/printing/print_backend_service_test_impl.cc
@@ -12,6 +12,8 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/values.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/printing/print_backend_service_manager.h"
 #include "printing/backend/test_print_backend.h"
 
@@ -113,6 +115,7 @@
   PrintBackendServiceImpl::GetDefaultPrinterName(std::move(callback));
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintBackendServiceTestImpl::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
@@ -125,6 +128,7 @@
   PrintBackendServiceImpl::GetPrinterSemanticCapsAndDefaults(
       printer_name, std::move(callback));
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void PrintBackendServiceTestImpl::FetchCapabilities(
     const std::string& printer_name,
diff --git a/chrome/browser/printing/print_backend_service_test_impl.h b/chrome/browser/printing/print_backend_service_test_impl.h
index f10b3dd..d97238d 100644
--- a/chrome/browser/printing/print_backend_service_test_impl.h
+++ b/chrome/browser/printing/print_backend_service_test_impl.h
@@ -12,6 +12,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/services/printing/print_backend_service_impl.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -89,10 +90,12 @@
   void GetDefaultPrinterName(
       mojom::PrintBackendService::GetDefaultPrinterNameCallback callback)
       override;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
           callback) override;
+#endif
   void FetchCapabilities(
       const std::string& printer_name,
       mojom::PrintBackendService::FetchCapabilitiesCallback callback) override;
diff --git a/chrome/browser/printing/system_access_process_print_browsertest.cc b/chrome/browser/printing/system_access_process_print_browsertest.cc
index c4927e6..f743f25 100644
--- a/chrome/browser/printing/system_access_process_print_browsertest.cc
+++ b/chrome/browser/printing/system_access_process_print_browsertest.cc
@@ -391,15 +391,22 @@
     print_job->AddObserver(*this);
   }
 
-  void SetUpPrintViewManager(content::WebContents* web_contents) {
+  TestPrintViewManager* SetUpAndReturnPrintViewManager(
+      content::WebContents* web_contents) {
     auto manager = std::make_unique<TestPrintViewManager>(
         web_contents,
         base::BindRepeating(
             &SystemAccessProcessPrintBrowserTestBase::OnCreatedPrintJob,
             base::Unretained(this)));
     manager->AddObserver(*this);
+    TestPrintViewManager* manager_ptr = manager.get();
     web_contents->SetUserData(PrintViewManager::UserDataKey(),
                               std::move(manager));
+    return manager_ptr;
+  }
+
+  void SetUpPrintViewManager(content::WebContents* web_contents) {
+    std::ignore = SetUpAndReturnPrintViewManager(web_contents);
   }
 
   void PrintAfterPreviewIsReadyAndLoaded() {
@@ -1630,6 +1637,17 @@
 
 IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest,
                        StartBasicPrintConcurrent) {
+  // Linux allows concurrent printing, so regular setup for printing is needed.
+  // It is uninteresting to do a full print in this case, it is better to exit
+  // the print sequence early, but at a known time after when PrintNow() would
+  // fail if concurrent printing isn't allowed.  That can be achieved by just
+  // canceling out from asking for settings.
+#if BUILDFLAG(IS_LINUX)
+  AddPrinter("printer1");
+  SetPrinterNameForSubsequentContexts("printer1");
+  PrimeForCancelInAskUserForSettings();
+#endif
+
   ASSERT_TRUE(embedded_test_server()->Started());
   GURL url(embedded_test_server()->GetURL("/printing/test3.html"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
@@ -1638,16 +1656,29 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(web_contents);
   TestPrintViewManager* print_view_manager =
-      TestPrintViewManager::CreateForWebContents(web_contents);
+      SetUpAndReturnPrintViewManager(web_contents);
 
   // Pretend that a window has started a system print.
   absl::optional<PrintBackendServiceManager::ClientId> client_id =
       PrintBackendServiceManager::GetInstance().RegisterQueryWithUiClient();
   ASSERT_TRUE(client_id.has_value());
 
+#if BUILDFLAG(IS_LINUX)
+  // The expected events for this are:
+  // 1.  Get the default settings.
+  // 2.  Ask the user for settings, which indicates to cancel the print
+  //     request.  No further printing calls are made.
+  // No print job is created because of such an early cancel.
+  SetNumExpectedMessages(/*num=*/2);
+#endif
+
   // Now initiate a system print that would exist concurrently with that.
   StartBasicPrint(web_contents);
 
+#if BUILDFLAG(IS_LINUX)
+  WaitUntilCallbackReceived();
+#endif
+
   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.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
index 58dfa41..b67ea471 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
@@ -129,7 +129,9 @@
 
 // Tests that different lessons are shown when choosing an experience from the
 // main menu.
-AX_TEST_F('ChromeVoxTutorialTest', 'LessonSetTest', async function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_LessonSetTest', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -162,8 +164,10 @@
 });
 
 // Tests that a static lesson does not show the 'Practice area' button.
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
 AX_TEST_F(
-    'ChromeVoxTutorialTest', 'NoPracticeAreaTest', async function() {
+    'ChromeVoxTutorialTest', 'DISABLED_NoPracticeAreaTest', async function() {
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithLoadedTree(this.simpleDoc);
       await this.launchAndWaitForTutorial();
@@ -188,8 +192,10 @@
     });
 
 // Tests that an interactive lesson shows the 'Practice area' button.
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
 AX_TEST_F(
-    'ChromeVoxTutorialTest', 'HasPracticeAreaTest', async function() {
+    'ChromeVoxTutorialTest', 'DISABLED_HasPracticeAreaTest', async function() {
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithLoadedTree(this.simpleDoc);
       await this.launchAndWaitForTutorial();
@@ -240,8 +246,48 @@
   await mockFeedback.replay();
 });
 
+// Tests nudges given in the practice area context. Note, each practice area
+// can have different nudge messages; this test confirms that nudges given in
+// the practice area differ from those given in the general tutorial context.
+AX_TEST_F(
+    'ChromeVoxTutorialTest', 'DISABLED_PracticeAreaNudgesTest',
+    async function() {
+      const mockFeedback = this.createMockFeedback();
+      const root = await this.runWithLoadedTree(this.simpleDoc);
+      await this.launchAndWaitForTutorial();
+      const tutorial = this.getTutorial();
+      const giveNudge = () => {
+        tutorial.giveNudge();
+      };
+      mockFeedback.expectSpeech('ChromeVox tutorial')
+          .call(doCmd('nextObject'))
+          .expectSpeech('Quick orientation')
+          .call(doCmd('nextObject'))
+          .expectSpeech('Essential keys')
+          .call(doCmd('nextObject'))
+          .expectSpeech('Navigation')
+          .call(doCmd('forceClickOnCurrentItem'))
+          .expectSpeech(/Navigation Tutorial, [0-9]+ Lessons/)
+          .call(() => {
+            tutorial.showLesson_(0);
+          })
+          .expectSpeech('Basic Navigation', 'Heading 1')
+          .call(doCmd('nextButton'))
+          .expectSpeech('Practice area')
+          .call(doCmd('forceClickOnCurrentItem'))
+          .expectSpeech(/Try using basic navigation to navigate/)
+          .call(giveNudge)
+          .expectSpeech(
+              'Try pressing Search + left/right arrow. The search key is ' +
+              'directly above the shift key')
+          .call(giveNudge)
+          .expectSpeech('Press Search + Space to activate the current item.');
+      await mockFeedback.replay();
+    });
+
 // Tests that the tutorial closes when the 'Exit tutorial' button is clicked.
-AX_TEST_F('ChromeVoxTutorialTest', 'ExitButtonTest', async function() {
+// TODO(crbug.com/1332510): Failing on ChromeOS.
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_ExitButtonTest', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -250,14 +296,13 @@
       .call(doCmd('previousButton'))
       .expectSpeech('Exit tutorial')
       .call(doCmd('forceClickOnCurrentItem'))
-      // Match against any speech here, since the behavior is different
-      // in Lacros vs. ash Chrome.
-      .expectSpeech(/[\s\S]*/);
+      .expectSpeech('Some web content');
   await mockFeedback.replay();
 });
 
 // Tests that the tutorial closes when Escape is pressed.
-AX_TEST_F('ChromeVoxTutorialTest', 'EscapeTest', async function() {
+// TODO(crbug.com/1332510): Failing on ChromeOS.
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_EscapeTest', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -271,17 +316,14 @@
           stopPropagation: () => {},
         });
       })
-      // Match against any speech here, since the behavior is different
-      // in Lacros vs. ash Chrome.
-      .expectSpeech(/[\s\S]*/)
-      .call(() => {
-        assertFalse(tutorial.isVisible);
-      });
+      .expectSpeech('Some web content');
   await mockFeedback.replay();
 });
 
 // Tests that the main menu button navigates the user to the main menu screen.
-AX_TEST_F('ChromeVoxTutorialTest', 'MainMenuButton', async function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_MainMenuButton', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -307,8 +349,10 @@
 
 // Tests that the all lessons button navigates the user to the lesson menu
 // screen.
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
 AX_TEST_F(
-    'ChromeVoxTutorialTest', 'AllLessonsButton', async function() {
+    'ChromeVoxTutorialTest', 'DISABLED_AllLessonsButton', async function() {
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithLoadedTree(this.simpleDoc);
       await this.launchAndWaitForTutorial();
@@ -338,8 +382,10 @@
     });
 
 // Tests that the next and previous lesson buttons navigate properly.
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
 AX_TEST_F(
-    'ChromeVoxTutorialTest', 'NextPreviousButtons', async function() {
+    'ChromeVoxTutorialTest', 'DISABLED_NextPreviousButtons', async function() {
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithLoadedTree(this.simpleDoc);
       await this.launchAndWaitForTutorial();
@@ -390,7 +436,9 @@
 });
 
 // Tests that we read a hint for navigating a lesson when it is shown.
-AX_TEST_F('ChromeVoxTutorialTest', 'LessonHint', async function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_LessonHint', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -443,13 +491,16 @@
 
 // Tests that a lesson from the quick orientation blocks ChromeVox execution
 // until the specified keystroke is pressed.
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
 AX_TEST_F(
-    'ChromeVoxTutorialTest', 'QuickOrientationLessonTest', async function() {
+    'ChromeVoxTutorialTest', 'DISABLED_QuickOrientationLessonTest',
+    async function() {
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithLoadedTree(this.simpleDoc);
       await this.launchAndWaitForTutorial();
       const tutorial = this.getTutorial();
-      const keyboardHandler = BackgroundKeyboardHandler.instance;
+      const keyboardHandler = ChromeVoxState.instance.keyboardHandler_;
 
       // Helper functions. For this test, activate commands by hooking into
       // the BackgroundKeyboardHandler. This is necessary because
@@ -645,7 +696,8 @@
     });
 
 // Tests that gestures can be used in the tutorial to navigate.
-AX_TEST_F('ChromeVoxTutorialTest', 'Gestures', async function() {
+// TODO(crbug.com/1332510): Failing on ChromeOS.
+AX_TEST_F('ChromeVoxTutorialTest', 'DISABLED_Gestures', async function() {
   const mockFeedback = this.createMockFeedback();
   const root = await this.runWithLoadedTree(this.simpleDoc);
   await this.launchAndWaitForTutorial();
@@ -658,36 +710,47 @@
       .call(doGesture(Gesture.SWIPE_LEFT1))
       .expectSpeech('Quick orientation', 'Link')
       .call(doGesture(Gesture.SWIPE_LEFT2))
-      // Match against any speech here, since the behavior is different
-      // in Lacros vs. ash Chrome.
-      .expectSpeech(/[\s\S]*/);
+      .expectSpeech('Some web content');
   await mockFeedback.replay();
 });
 
 // Tests that touch orientation loads properly. Tests string content, but does
 // not test interactivity of lessons.
-AX_TEST_F('ChromeVoxTutorialTest', 'TouchOrientation', async function() {
-  const mockFeedback = this.createMockFeedback();
-  const root = await this.runWithLoadedTree(this.simpleDoc);
-  await this.launchAndWaitForTutorial();
-  const tutorial = this.getTutorial();
-  mockFeedback.expectSpeech('ChromeVox tutorial')
-      .call(() => {
-        tutorial.curriculum = 'touch_orientation';
-        tutorial.medium = 'touch';
-        tutorial.showLesson_(0);
-        this.assertActiveLessonIndex(0);
-        this.assertActiveScreen('lesson');
-      })
-      .expectSpeech('ChromeVox touch tutorial')
-      .expectSpeech(/Welcome to the ChromeVox tutorial/)
-      .call(doGesture(Gesture.CLICK))
-      .expectSpeech('Activate an item')
-      .expectSpeech(/To continue, double-tap now/)
-      .call(doGesture(Gesture.CLICK))
-      .expectSpeech('Move to the next or previous item');
-  await mockFeedback.replay();
-});
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+AX_TEST_F(
+    'ChromeVoxTutorialTest', 'DISABLED_TouchOrientation', async function() {
+      const mockFeedback = this.createMockFeedback();
+      const root = await this.runWithLoadedTree(this.simpleDoc);
+      await this.launchAndWaitForTutorial();
+      const tutorial = this.getTutorial();
+      mockFeedback.expectSpeech('ChromeVox tutorial')
+          .call(() => {
+            tutorial.curriculum = 'touch_orientation';
+            tutorial.medium = 'touch';
+            tutorial.showLesson_(0);
+            this.assertActiveLessonIndex(0);
+            this.assertActiveScreen('lesson');
+          })
+          .expectSpeech('ChromeVox touch tutorial')
+          .expectSpeech(/Welcome to the ChromeVox tutorial/)
+          .call(doGesture(Gesture.CLICK))
+          .expectSpeech('Activate an item')
+          .expectSpeech(/To continue, double-tap now/)
+          .call(doGesture(Gesture.CLICK))
+          .expectSpeech('Move to the next or previous item')
+          .call(() => {
+            // Jump to the penultimate lesson.
+            tutorial.showLesson_(6);
+          })
+          .expectSpeech('Move to the next or previous section')
+          .expectSpeech(/swipe from left to right with four fingers/)
+          .call(doGesture(Gesture.SWIPE_RIGHT4))
+          .expectSpeech(/swiping with four fingers from right to left/)
+          .call(doGesture(Gesture.SWIPE_LEFT4))
+          .expectSpeech('Touch tutorial complete');
+      await mockFeedback.replay();
+    });
 
 AX_TEST_F('ChromeVoxTutorialTest', 'GeneralTouchNudges', async function() {
   const mockFeedback = this.createMockFeedback();
diff --git a/chrome/browser/resources/settings/autofill_page/passkeys_subpage.html b/chrome/browser/resources/settings/autofill_page/passkeys_subpage.html
index 12eb1e9..f84ffc6 100644
--- a/chrome/browser/resources/settings/autofill_page/passkeys_subpage.html
+++ b/chrome/browser/resources/settings/autofill_page/passkeys_subpage.html
@@ -88,7 +88,7 @@
   <settings-simple-confirmation-dialog id="deleteConfirmDialog"
       title-text="$i18n{managePasskeysDeleteConfirmationTitle}"
       body-text="$i18n{managePasskeysDeleteConfirmationDescription}"
-      confirm-text="$i18n{delete}"
+      confirm-text="$i18n{delete}" no-primary-button
       on-close="onConfirmDialogClose_">
   </settings-simple-confirmation-dialog>
 </template>
diff --git a/chrome/browser/resources/settings/simple_confirmation_dialog.html b/chrome/browser/resources/settings/simple_confirmation_dialog.html
index 7720048..cfbf22d 100644
--- a/chrome/browser/resources/settings/simple_confirmation_dialog.html
+++ b/chrome/browser/resources/settings/simple_confirmation_dialog.html
@@ -5,7 +5,9 @@
     <cr-button  id="cancel" class="cancel-button" on-click="onCancelClick_">
       $i18n{cancel}
     </cr-button>
-    <cr-button id="confirm" on-click="onConfirmClick_">
+    <cr-button id="confirm"
+        class$="[[getConfirmButtonCssClass_(noPrimaryButton)]]"
+        on-click="onConfirmClick_">
       [[confirmText]]
     </cr-button>
   </div>
diff --git a/chrome/browser/resources/settings/simple_confirmation_dialog.ts b/chrome/browser/resources/settings/simple_confirmation_dialog.ts
index 23f1e30..9a4be4e 100644
--- a/chrome/browser/resources/settings/simple_confirmation_dialog.ts
+++ b/chrome/browser/resources/settings/simple_confirmation_dialog.ts
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -37,12 +37,18 @@
       titleText: String,
       bodyText: String,
       confirmText: String,
+
+      noPrimaryButton: {
+        type: Boolean,
+        value: false,
+      },
     };
   }
 
   titleText: string;
   bodyText: string;
   confirmText: string;
+  noPrimaryButton: boolean;
 
   /** @return Whether the user confirmed the dialog. */
   wasConfirmed(): boolean {
@@ -56,6 +62,10 @@
   private onConfirmClick_() {
     this.$.dialog.close();
   }
+
+  private getConfirmButtonCssClass_(): string {
+    return this.noPrimaryButton ? '' : 'action-button';
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/side_panel/companion/companion.ts b/chrome/browser/resources/side_panel/companion/companion.ts
index 5cc9a0d..bfccf8d 100644
--- a/chrome/browser/resources/side_panel/companion/companion.ts
+++ b/chrome/browser/resources/side_panel/companion/companion.ts
@@ -2,12 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {assert} from '//resources/js/assert_ts.js';
+import './strings.m.js';
 
+import {assert} from '//resources/js/assert_ts.js';
+import {loadTimeData} from '//resources/js/load_time_data.js';
+
+import {MethodType, PromoAction, PromoType} from './companion.mojom-webui.js';
 import {CompanionProxy, CompanionProxyImpl} from './companion_proxy.js';
 
 const companionProxy: CompanionProxy = CompanionProxyImpl.getInstance();
 
+// Validation check for incoming enums from the iframe postMessage().
+function validatePromoArguments(promoType: any, promoAction: any): boolean {
+  const isValidType = Object.values(PromoType).includes(promoType);
+  const isValidAction = Object.values(PromoAction).includes(promoAction);
+  return isValidType && isValidAction;
+}
 
 function initialize() {
   // When the url is changed, we update our iframe src to pass new parameters.
@@ -20,4 +30,21 @@
   companionProxy.handler.showUI();
 }
 
+// Handler for postMessage() calls from the embedded iframe.
+function onCompanionMessageEvent(event: MessageEvent) {
+  if (event.origin !== loadTimeData.getString('companion_origin')) {
+    return;
+  }
+
+  const data = event.data;
+  if (data.type === MethodType.kOnRegionSearchClicked) {
+    companionProxy.handler.onRegionSearchClicked();
+  } else if (data.type === MethodType.kOnPromoAction) {
+    if (validatePromoArguments(data.promoType, data.promoAction)) {
+      companionProxy.handler.onPromoAction(data.promoType, data.promoAction);
+    }
+  }
+}
+
+window.addEventListener('message', onCompanionMessageEvent, false);
 document.addEventListener('DOMContentLoaded', initialize);
diff --git a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc
index 6a1ba0d..d3166cd 100644
--- a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc
+++ b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service_unittest.cc
@@ -39,11 +39,9 @@
 
 namespace safe_browsing {
 
-#if !BUILDFLAG(IS_ANDROID)
 // Names for Tailored Security status to make the test cases clearer.
 const bool kTailoredSecurityEnabled = true;
 const bool kTailoredSecurityDisabled = false;
-#endif
 
 namespace {
 // Test implementation of ChromeTailoredSecurityService.
@@ -200,7 +198,6 @@
       chrome_tailored_security_service_;
 };
 
-#if !BUILDFLAG(IS_ANDROID)
 // Some of the test names are shorted using "Ts" for Tailored Security, "Ep"
 // for Enhanced Protection and "Sb" for Safe Browsing.
 
@@ -349,6 +346,4 @@
   EXPECT_TRUE(IsEnhancedProtectionEnabled(*prefs()));
 }
 
-#endif
-
 }  // namespace safe_browsing
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 63653ffe..388396e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1695,6 +1695,8 @@
       "webui/side_panel/companion/companion_url_builder.cc",
       "webui/side_panel/companion/companion_url_builder.h",
       "webui/side_panel/companion/constants.h",
+      "webui/side_panel/companion/promo_handler.cc",
+      "webui/side_panel/companion/promo_handler.h",
       "webui/side_panel/customize_chrome/customize_chrome_colors.cc",
       "webui/side_panel/customize_chrome/customize_chrome_colors.h",
       "webui/side_panel/customize_chrome/customize_chrome_page_handler.cc",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index 7a47421..c03bff1 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -328,6 +328,7 @@
     public void onFinishInflate() {
         super.onFinishInflate();
         setPrivateImeOptions(IME_OPTION_RESTRICT_STYLUS_WRITING_AREA);
+        ApiCompatibilityUtils.clearHandwritingBoundsOffsetBottom(this);
     }
 
     /**
diff --git a/chrome/browser/ui/ash/login_screen_client_impl.cc b/chrome/browser/ui/ash/login_screen_client_impl.cc
index 1c3e113..246f250a 100644
--- a/chrome/browser/ui/ash/login_screen_client_impl.cc
+++ b/chrome/browser/ui/ash/login_screen_client_impl.cc
@@ -156,11 +156,6 @@
       .ValidateParentAccessCode(account_id, access_code, validation_time);
 }
 
-void LoginScreenClientImpl::HardlockPod(const AccountId& account_id) {
-  if (delegate_)
-    delegate_->HandleHardlockPod(account_id);
-}
-
 void LoginScreenClientImpl::OnFocusPod(const AccountId& account_id) {
   if (delegate_)
     delegate_->HandleOnFocusPod(account_id);
diff --git a/chrome/browser/ui/ash/login_screen_client_impl.h b/chrome/browser/ui/ash/login_screen_client_impl.h
index 46a06175..be940c2 100644
--- a/chrome/browser/ui/ash/login_screen_client_impl.h
+++ b/chrome/browser/ui/ash/login_screen_client_impl.h
@@ -44,7 +44,6 @@
     virtual void HandleAuthenticateUserWithChallengeResponse(
         const AccountId& account_id,
         base::OnceCallback<void(bool)> callback) = 0;
-    virtual void HandleHardlockPod(const AccountId& account_id) = 0;
     virtual void HandleOnFocusPod(const AccountId& account_id) = 0;
     virtual void HandleOnNoPodFocused() = 0;
     // Handles request to focus a lock screen app window. Returns whether the
@@ -103,7 +102,6 @@
       const AccountId& account_id,
       const std::string& access_code,
       base::Time validation_time) override;
-  void HardlockPod(const AccountId& account_id) override;
   void OnFocusPod(const AccountId& account_id) override;
   void OnNoPodFocused() override;
   void LoadWallpaper(const AccountId& account_id) override;
diff --git a/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.cc b/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.cc
index ff5195dc..7e18d589 100644
--- a/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.cc
+++ b/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.cc
@@ -35,9 +35,24 @@
   }
 
   auto key_code = key_event->key_code();
-  if (key_code == ui::VKEY_ESCAPE) {
-    QuickAnswersController::Get()->DismissQuickAnswers(
-        quick_answers::QuickAnswersExitPoint::kUnspecified);
+  switch (key_code) {
+    case ui::VKEY_ESCAPE: {
+      QuickAnswersController::Get()->DismissQuickAnswers(
+          quick_answers::QuickAnswersExitPoint::kUnspecified);
+      return;
+    }
+    case ui::VKEY_SPACE:
+    case ui::VKEY_UP:
+    case ui::VKEY_DOWN:
+    case ui::VKEY_LEFT:
+    case ui::VKEY_RIGHT: {
+      // TODO(b/275106457): Handle key navigation of focus on the
+      // rich answers card view.
+      key_event->StopPropagation();
+      return;
+    }
+    default:
+      return;
   }
 }
 
@@ -52,6 +67,23 @@
     QuickAnswersController::Get()->DismissQuickAnswers(
         quick_answers::QuickAnswersExitPoint::kUnspecified);
   }
+
+  // While the rich answers view is visible, do not pass on unhandled
+  // mouse events up the hierarchy. The rich answers view should be dismissed
+  // before allowing mouse event handling by other windows and views.
+  if (mouse_event->cancelable()) {
+    mouse_event->StopPropagation();
+  }
+}
+
+void RichAnswersPreTargetHandler::OnScrollEvent(ui::ScrollEvent* scroll_event) {
+  // TODO(b/265255821): handle scrolling of the rich answers view card.
+  // Limit scroll events to the rich answers card while it is visible.
+  // This means other windows and views will not be scrollable until the rich
+  // answers view is dismissed.
+  if (scroll_event->cancelable()) {
+    scroll_event->StopPropagation();
+  }
 }
 
 }  // namespace quick_answers
diff --git a/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.h b/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.h
index 5ec8b68c..30808936 100644
--- a/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.h
+++ b/chrome/browser/ui/quick_answers/ui/rich_answers_pre_target_handler.h
@@ -29,6 +29,7 @@
   // ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* key_event) override;
   void OnMouseEvent(ui::MouseEvent* mouse_event) override;
+  void OnScrollEvent(ui::ScrollEvent* scroll_event) override;
 
  private:
   // Associated view handled by this class.
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index f505dbc9..fac42e3 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -61,6 +61,7 @@
 #include "components/dom_distiller/core/dom_distiller_features.h"
 #include "components/dom_distiller/core/url_utils.h"
 #include "components/feature_engagement/public/event_constants.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/performance_manager/public/features.h"
 #include "components/prefs/pref_service.h"
 #include "components/profile_metrics/browser_profile_type.h"
@@ -114,6 +115,7 @@
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(AppMenuModel, kExtensionsMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(AppMenuModel, kMoreToolsMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(AppMenuModel, kIncognitoMenuItem);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(AppMenuModel, kPasswordManagerMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToolsMenuModel, kPerformanceMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ExtensionsMenuModel,
                                       kManageExtensionsMenuItem);
@@ -955,6 +957,13 @@
     SetElementIdentifierAt(GetIndexOfCommandId(IDC_BOOKMARKS_MENU).value(),
                            kBookmarksMenuItem);
   }
+  if (!browser_->profile()->IsOffTheRecord() &&
+      base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordManagerRedesign)) {
+    AddItemWithStringId(IDC_VIEW_PASSWORDS, IDS_VIEW_PASSWORDS);
+    SetElementIdentifierAt(GetIndexOfCommandId(IDC_VIEW_PASSWORDS).value(),
+                           kPasswordManagerMenuItem);
+  }
 
   if (base::FeatureList::IsEnabled(features::kExtensionsMenuInAppMenu)) {
     // Extensions sub menu.
diff --git a/chrome/browser/ui/toolbar/app_menu_model.h b/chrome/browser/ui/toolbar/app_menu_model.h
index 26545b0..5cd3225 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.h
+++ b/chrome/browser/ui/toolbar/app_menu_model.h
@@ -154,6 +154,7 @@
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kExtensionsMenuItem);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMoreToolsMenuItem);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kIncognitoMenuItem);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordManagerMenuItem);
 
   // First command ID to use for the recent tabs menu. This is one higher than
   // the first command id used for the bookmarks menus, as the command ids for
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index e7b711d..c80aa95f 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -24,6 +24,7 @@
 #include "chrome/test/base/menu_model_test.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/performance_manager/public/features.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -377,3 +378,38 @@
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS)
+
+class AppMenuModelPasswordManagerTest
+    : public AppMenuModelTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  AppMenuModelPasswordManagerTest() {
+    feature_list_.InitWithFeatureState(
+        password_manager::features::kPasswordManagerRedesign, GetParam());
+  }
+
+  AppMenuModelPasswordManagerTest(const AppMenuModelPasswordManagerTest&) =
+      delete;
+  AppMenuModelPasswordManagerTest& operator=(
+      const AppMenuModelPasswordManagerTest&) = delete;
+
+  ~AppMenuModelPasswordManagerTest() override = default;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    AppMenuModelPasswordManagerTest,
+    /* features::kPasswordManagerRedesign enabled */ testing::Bool());
+
+TEST_P(AppMenuModelPasswordManagerTest, NewPasswordManagerHasMenuEntry) {
+  AppMenuModel model(this, browser());
+  model.Init();
+  auto index = model.GetIndexOfCommandId(IDC_VIEW_PASSWORDS);
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordManagerRedesign)) {
+    ASSERT_TRUE(index.has_value());
+    EXPECT_TRUE(model.IsVisibleAt(index.value()));
+  } else {
+    EXPECT_FALSE(index.has_value());
+  }
+}
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_interactive_uitest.cc
index 8bf566b..8faaff9 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_main_page_view_interactive_uitest.cc
@@ -22,22 +22,6 @@
 
 using PermissionsManager = extensions::PermissionsManager;
 
-// Returns whether the extension injected a script by checking the document
-// title.
-bool DidInjectScript(content::WebContents* web_contents) {
-  const std::u16string& title = web_contents->GetTitle();
-  if (title == u"success") {
-    return true;
-  }
-  // The original page title is "OK"; this indicates the script didn't
-  // inject.
-  if (title == u"OK") {
-    return false;
-  }
-  ADD_FAILURE() << "Unexpected page title found: " << title;
-  return false;
-}
-
 }  // namespace
 
 class ExtensionsMenuMainPageViewInteractiveUITest
@@ -55,8 +39,6 @@
 
   void ClickSiteSettingToggle();
 
-  ExtensionsToolbarButton* extensions_button();
-  ExtensionsMenuCoordinator* menu_coordinator();
   ExtensionsMenuMainPageView* main_page();
 
   // ExtensionsToolbarUITest:
@@ -89,17 +71,6 @@
   WaitForAnimation();
 }
 
-ExtensionsToolbarButton*
-ExtensionsMenuMainPageViewInteractiveUITest::extensions_button() {
-  return GetExtensionsToolbarContainer()->GetExtensionsButton();
-}
-
-ExtensionsMenuCoordinator*
-ExtensionsMenuMainPageViewInteractiveUITest::menu_coordinator() {
-  return GetExtensionsToolbarContainer()
-      ->GetExtensionsMenuCoordinatorForTesting();
-}
-
 ExtensionsMenuMainPageView*
 ExtensionsMenuMainPageViewInteractiveUITest::main_page() {
   ExtensionsMenuViewController* menu_controller =
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_interactive_uitest.cc
index a3804c6..53f6721 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_site_permissions_page_view_interactive_uitest.cc
@@ -22,24 +22,6 @@
 
 using PermissionsManager = extensions::PermissionsManager;
 
-// Returns whether the extension injected a script by checking the document
-// title.
-// TODO(crbug.com/1390952): Move repeated code from main page and site
-// permissions page interactive ui tests to ExtensionsToolbarUITest.
-bool DidInjectScript(content::WebContents* web_contents) {
-  const std::u16string& title = web_contents->GetTitle();
-  if (title == u"success") {
-    return true;
-  }
-  // The original page title is "OK"; this indicates the script didn't
-  // inject.
-  if (title == u"OK") {
-    return false;
-  }
-  ADD_FAILURE() << "Unexpected page title found: " << title;
-  return false;
-}
-
 }  // namespace
 
 class ExtensionsMenuSitePermissionsPageViewInteractiveUITest
@@ -62,8 +44,6 @@
   // opened.
   bool IsSitePermissionsPageOpened(extensions::ExtensionId extension_id);
 
-  ExtensionsToolbarButton* extensions_button();
-  ExtensionsMenuCoordinator* menu_coordinator();
   ExtensionsMenuMainPageView* main_page();
   ExtensionsMenuSitePermissionsPageView* site_permissions_page();
 
@@ -100,17 +80,6 @@
   return page && page->extension_id() == extension_id;
 }
 
-ExtensionsToolbarButton*
-ExtensionsMenuSitePermissionsPageViewInteractiveUITest::extensions_button() {
-  return GetExtensionsToolbarContainer()->GetExtensionsButton();
-}
-
-ExtensionsMenuCoordinator*
-ExtensionsMenuSitePermissionsPageViewInteractiveUITest::menu_coordinator() {
-  return GetExtensionsToolbarContainer()
-      ->GetExtensionsMenuCoordinatorForTesting();
-}
-
 ExtensionsMenuMainPageView*
 ExtensionsMenuSitePermissionsPageViewInteractiveUITest::main_page() {
   ExtensionsMenuViewController* menu_controller =
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.cc
index eae19cf..436e65a 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.cc
@@ -173,6 +173,30 @@
   return views;
 }
 
+ExtensionsToolbarButton* ExtensionsToolbarUITest::extensions_button() {
+  return GetExtensionsToolbarContainer()->GetExtensionsButton();
+}
+
+ExtensionsMenuCoordinator* ExtensionsToolbarUITest::menu_coordinator() {
+  return GetExtensionsToolbarContainer()
+      ->GetExtensionsMenuCoordinatorForTesting();
+}
+
+bool ExtensionsToolbarUITest::DidInjectScript(
+    content::WebContents* web_contents) {
+  const std::u16string& title = web_contents->GetTitle();
+  if (title == u"success") {
+    return true;
+  }
+  // The original page title is "OK"; this indicates the script didn't
+  // inject.
+  if (title == u"OK") {
+    return false;
+  }
+  ADD_FAILURE() << "Unexpected page title found: " << title;
+  return false;
+}
+
 void ExtensionsToolbarUITest::ClickButton(views::Button* button) const {
   ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                              base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0);
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.h b/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.h
index 53fa084..8317b88 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.h
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_interactive_uitest.h
@@ -15,6 +15,8 @@
 
 class ExtensionsToolbarContainer;
 class ToolbarActionView;
+class ExtensionsToolbarButton;
+class ExtensionsMenuCoordinator;
 
 namespace extensions {
 class Extension;
@@ -97,9 +99,19 @@
   // GetToolbarActionViews().
   std::vector<ToolbarActionView*> GetVisibleToolbarActionViews() const;
 
+  // Returns the extensions button in the toolbar.
+  ExtensionsToolbarButton* extensions_button();
+
+  // Returns the extensions menu coordinator.
+  ExtensionsMenuCoordinator* menu_coordinator();
+
   // Triggers the press and release event of the given `button`.
   void ClickButton(views::Button* button) const;
 
+  // Returns whether the extension injected a script by checking the document
+  // title. Extension must use 'extensions/blocked_actions/content_scripts'.
+  bool DidInjectScript(content::WebContents* web_contents);
+
   // Waits for the extensions container to animate (on pin, unpin, pop-out,
   // etc.)
   void WaitForAnimation();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 107d7773..89c2e710 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -87,6 +87,7 @@
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/color/color_provider.h"
 #include "ui/display/display.h"
 #include "ui/gfx/animation/throb_animation.h"
@@ -1152,8 +1153,16 @@
 
 bool TabStrip::ShouldDrawStrokes() const {
   // If the controller says we can't draw strokes, don't.
-  if (!controller_->CanDrawStrokes())
+  if (!controller_->CanDrawStrokes()) {
     return false;
+  }
+
+  // The Tabstrip in the refreshed style does not meet the contrast ratio
+  // requirements listed below but does not have strokes for Tabs or the bottom
+  // border.
+  if (features::IsChromeRefresh2023()) {
+    return false;
+  }
 
   // The tabstrip normally avoids strokes and relies on the active tab
   // contrasting sufficiently with the frame background.  When there isn't
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index e222f8f..222cdf9 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -105,6 +105,12 @@
   // Painting helper functions:
   virtual SkColor GetTabBackgroundColor(TabActive active) const;
 
+  // Returns the thickness of the stroke drawn around the top and sides of the
+  // tab. Only active tabs may have a stroke, and not in all cases. If there
+  // is no stroke, returns 0. If |should_paint_as_active| is true, the tab is
+  // treated as an active tab regardless of its true current state.
+  virtual int GetStrokeThickness(bool should_paint_as_active = false) const;
+
  private:
   // Gets the bounds for the leading and trailing separators for a tab.
   SeparatorBounds GetSeparatorBounds(float scale) const;
@@ -142,12 +148,6 @@
   // Gets the throb value. A value of 0 indicates no throbbing.
   float GetThrobValue() const;
 
-  // Returns the thickness of the stroke drawn around the top and sides of the
-  // tab. Only active tabs may have a stroke, and not in all cases. If there
-  // is no stroke, returns 0. If |should_paint_as_active| is true, the tab is
-  // treated as an active tab regardless of its true current state.
-  int GetStrokeThickness(bool should_paint_as_active = false) const;
-
   bool ShouldPaintTabBackgroundColor(TabActive active,
                                      bool has_custom_background) const;
 
@@ -956,6 +956,7 @@
  public:
   explicit GM3TabStyle(Tab* tab);
   SkColor GetTabBackgroundColor(TabActive active) const override;
+  int GetStrokeThickness(bool should_paint_as_active = false) const override;
 };
 
 GM3TabStyle::GM3TabStyle(Tab* tab) : GM2TabStyle(tab) {}
@@ -977,6 +978,14 @@
       tab()->controller()->ShouldPaintAsActiveFrame())]);
 }
 
+int GM3TabStyle::GetStrokeThickness(bool should_paint_as_active) const {
+  if (tab()->group().has_value() && tab()->IsActive()) {
+    return TabGroupUnderline::kStrokeThickness;
+  }
+
+  return 0;
+}
+
 }  // namespace
 
 // static
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc
index 5e5ae3f..31c6e4d2 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.cc
+++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/performance_manager/public/user_tuning/user_tuning_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.h"
@@ -185,9 +186,27 @@
                    mojom::LifecycleUnitDiscardReason reason,
                    DiscardByIdCallback callback) override {
     auto* lifecycle_unit = GetLifecycleUnitById(id);
-    if (lifecycle_unit)
-      lifecycle_unit->Discard(reason);
-    std::move(callback).Run();
+    if (lifecycle_unit) {
+      // Callback to do the discard with the memory estimate.
+      auto discard_callback = base::BindOnce(
+          [](int32_t id, mojom::LifecycleUnitDiscardReason reason,
+             DiscardByIdCallback post_discard_callback,
+             uint64_t memory_estimate) {
+            // Look up lifecycle_unit by id again, in case it's deleted while
+            // waiting.
+            auto* lifecycle_unit = GetLifecycleUnitById(id);
+            if (lifecycle_unit) {
+              lifecycle_unit->Discard(reason, memory_estimate);
+            }
+            std::move(post_discard_callback).Run();
+          },
+          id, reason, std::move(callback));
+
+      performance_manager::user_tuning::
+          GetDiscardedMemoryEstimateForWebContents(
+              lifecycle_unit->AsTabLifecycleUnitExternal()->GetWebContents(),
+              std::move(discard_callback));
+    }
   }
 
   void LoadById(int32_t id) override {
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion.mojom b/chrome/browser/ui/webui/side_panel/companion/companion.mojom
index 7456892..ccd6d40 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion.mojom
+++ b/chrome/browser/ui/webui/side_panel/companion/companion.mojom
@@ -4,6 +4,45 @@
 
 module side_panel.mojom;
 
+// Methods called on the browser from the companion UI.
+// TODO(b/274618365): Link documentation for server side counterpart that must
+// be kept in sync.
+enum MethodType {
+  // Method called in response to a user action in a promo.
+  kOnPromoAction = 1,
+
+  // Method called in response to user clicking on the region search button.
+  kOnRegionSearchClicked = 2,
+};
+
+// Types of promos shown in the companion UI.
+// TODO(b/274618365): Link documentation for server side counterpart that must
+// be kept in sync.
+enum PromoType {
+  // Promo to sign-in to chrome.
+  kSignin = 1,
+
+  // Promo to turn on make searches and browsing better.
+  kMsbb = 2,
+
+  // Promo to opt into labs api.
+  kLabs = 3,
+};
+
+// User actions taken on a promo.
+// TODO(b/274618365): Link documentation for server side counterpart that must
+// be kept in sync.
+enum PromoAction {
+  // Promo was shown in the companion UI.
+  kShown = 1,
+
+  // User accepted the promo.
+  kAccepted = 2,
+
+  // User declined the promo.
+  kRejected = 3,
+};
+
 // Factory method for creating a new WebUI page handler.
 interface CompanionPageHandlerFactory {
   // The WebUI calls this method when the page is first initialized.
@@ -16,6 +55,12 @@
 interface CompanionPageHandler {
   // Notify the backend that the UI is ready to be shown.
   ShowUI();
+
+  // Called to notify the browser about user action on a promo.
+  OnPromoAction(PromoType promo_type, PromoAction promo_action);
+
+  // Called to notify the browser that user has clicked on region search button.
+  OnRegionSearchClicked();
 };
 
 // WebUI page handler for request from Browser side. (C++ -> TypeScript)
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
index 150be00c..60fc3dad 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/webui/side_panel/companion/companion_side_panel_untrusted_ui.h"
 #include "chrome/browser/ui/webui/side_panel/companion/companion_url_builder.h"
+#include "chrome/browser/ui/webui/side_panel/companion/promo_handler.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/unified_consent/pref_names.h"
@@ -29,7 +30,9 @@
       page_(std::move(page)),
       companion_untrusted_ui_(companion_untrusted_ui),
       url_builder_(std::make_unique<CompanionUrlBuilder>(
-          browser->profile()->GetPrefs())) {
+          browser->profile()->GetPrefs())),
+      promo_handler_(
+          std::make_unique<PromoHandler>(browser->profile()->GetPrefs())) {
   DCHECK(browser);
   NotifyURLChanged();
 }
@@ -55,4 +58,14 @@
   page_->OnURLChanged(companion_url.spec());
 }
 
+void CompanionPageHandler::OnPromoAction(
+    side_panel::mojom::PromoType promo_type,
+    side_panel::mojom::PromoAction promo_action) {
+  promo_handler_->OnPromoAction(promo_type, promo_action);
+}
+
+void CompanionPageHandler::OnRegionSearchClicked() {
+  // TODO(b/274618487): Start lens region search.
+}
+
 }  // namespace companion
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
index c357f6d..10396da7 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
+++ b/chrome/browser/ui/webui/side_panel/companion/companion_page_handler.h
@@ -18,6 +18,7 @@
 
 namespace companion {
 class CompanionUrlBuilder;
+class PromoHandler;
 
 class CompanionPageHandler : public side_panel::mojom::CompanionPageHandler,
                              public content::WebContentsObserver {
@@ -33,6 +34,9 @@
 
   // side_panel::mojom::CompanionPageHandler:
   void ShowUI() override;
+  void OnPromoAction(side_panel::mojom::PromoType promo_type,
+                     side_panel::mojom::PromoAction promo_action) override;
+  void OnRegionSearchClicked() override;
 
   // content::WebContentsObserver:
   void PrimaryPageChanged(content::Page& page) override;
@@ -46,6 +50,7 @@
   mojo::Remote<side_panel::mojom::CompanionPage> page_;
   raw_ptr<CompanionSidePanelUntrustedUI> companion_untrusted_ui_ = nullptr;
   std::unique_ptr<CompanionUrlBuilder> url_builder_;
+  std::unique_ptr<PromoHandler> promo_handler_;
 };
 }  // namespace companion
 
diff --git a/chrome/browser/ui/webui/side_panel/companion/companion_side_panel_untrusted_ui.cc b/chrome/browser/ui/webui/side_panel/companion/companion_side_panel_untrusted_ui.cc
index 9c53b47..e8cd5086 100644
--- a/chrome/browser/ui/webui/side_panel/companion/companion_side_panel_untrusted_ui.cc
+++ b/chrome/browser/ui/webui/side_panel/companion/companion_side_panel_untrusted_ui.cc
@@ -24,6 +24,7 @@
           chrome::kChromeUIUntrustedCompanionSidePanelURL);
 
   // Add required resources.
+  html_source->UseStringsJs();
   html_source->AddResourcePaths(base::make_span(
       kSidePanelCompanionResources, kSidePanelCompanionResourcesSize));
   html_source->AddResourcePath("", IDR_SIDE_PANEL_COMPANION_COMPANION_HTML);
@@ -41,6 +42,7 @@
       std::string("frame-src ") + frameSrcString + ";";
   html_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::FrameSrc, frameSrcDirective);
+  html_source->AddString("companion_origin", frameSrcString);
 }
 
 CompanionSidePanelUntrustedUI::~CompanionSidePanelUntrustedUI() = default;
diff --git a/chrome/browser/ui/webui/side_panel/companion/promo_handler.cc b/chrome/browser/ui/webui/side_panel/companion/promo_handler.cc
new file mode 100644
index 0000000..38598c7
--- /dev/null
+++ b/chrome/browser/ui/webui/side_panel/companion/promo_handler.cc
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/side_panel/companion/promo_handler.h"
+
+#include "components/prefs/pref_service.h"
+
+namespace companion {
+
+PromoHandler::PromoHandler(PrefService* pref_service)
+    : pref_service_(pref_service) {}
+
+PromoHandler::~PromoHandler() = default;
+
+void PromoHandler::OnPromoAction(PromoType promo_type,
+                                 PromoAction promo_action) {
+  // TODO(b/273652233): Implement logic to persist promo count, and optionally
+  // open sign-in flow.
+}
+
+}  // namespace companion
diff --git a/chrome/browser/ui/webui/side_panel/companion/promo_handler.h b/chrome/browser/ui/webui/side_panel/companion/promo_handler.h
new file mode 100644
index 0000000..8318c6b
--- /dev/null
+++ b/chrome/browser/ui/webui/side_panel/companion/promo_handler.h
@@ -0,0 +1,38 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SIDE_PANEL_COMPANION_PROMO_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SIDE_PANEL_COMPANION_PROMO_HANDLER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/webui/side_panel/companion/companion.mojom.h"
+
+class PrefService;
+
+namespace companion {
+using side_panel::mojom::PromoAction;
+using side_panel::mojom::PromoType;
+
+// Central class to handle user actions on various promos displayed in the
+// search companion.
+class PromoHandler {
+ public:
+  explicit PromoHandler(PrefService* pref_service);
+  PromoHandler(const PromoHandler&) = delete;
+  PromoHandler& operator=(const PromoHandler&) = delete;
+  ~PromoHandler();
+
+  // Called in response to the mojo call from renderer. Takes necessary action
+  // to handle the user action on the promo.
+  void OnPromoAction(PromoType promo_type, PromoAction promo_action);
+
+ private:
+  // Lifetime of the PrefService is bound to profile which outlives the lifetime
+  // of the companion page.
+  raw_ptr<PrefService> pref_service_;
+};
+
+}  // namespace companion
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SIDE_PANEL_COMPANION_PROMO_HANDLER_H_
diff --git a/chrome/browser/ui/webui/side_panel/companion/promo_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/companion/promo_handler_unittest.cc
new file mode 100644
index 0000000..389951d0
--- /dev/null
+++ b/chrome/browser/ui/webui/side_panel/companion/promo_handler_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/side_panel/companion/promo_handler.h"
+
+#include "chrome/browser/ui/webui/side_panel/companion/companion.mojom.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace companion {
+
+class PromoHandlerTest : public testing::Test {
+ public:
+  PromoHandlerTest() = default;
+  ~PromoHandlerTest() override = default;
+
+  void SetUp() override {
+    promo_handler_ = std::make_unique<PromoHandler>(&pref_service_);
+  }
+
+ protected:
+  TestingPrefServiceSimple pref_service_;
+  std::unique_ptr<PromoHandler> promo_handler_;
+};
+
+TEST_F(PromoHandlerTest, OnPromoActionTest) {
+  promo_handler_->OnPromoAction(PromoType::kMsbb, PromoAction::kAccepted);
+  // TODO(shaktisahu): Verify result.
+}
+
+}  // namespace companion
diff --git a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager.cc b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager.cc
index 06c4807..b996408 100644
--- a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager.cc
+++ b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager.cc
@@ -94,14 +94,20 @@
 void ShortcutMenuHandlingSubManager::StoreShortcutMenuData(
     const AppId& app_id,
     proto::ShortcutMenus* shortcut_menus,
-    WebAppIconManager::ShortcutIconDataVector shortcut_menu_items) {
-  if (shortcut_menu_items.size() == 0) {
-    return;
-  }
+    WebAppIconManager::ShortcutIconDataVector downloaded_shortcut_menu_items) {
   std::vector<WebAppShortcutsMenuItemInfo> shortcut_menu_item_info =
       registrar_->GetAppShortcutsMenuItemInfos(app_id);
-  CHECK_EQ(shortcut_menu_item_info.size(), shortcut_menu_items.size());
-  for (size_t menu_index = 0; menu_index < shortcut_menu_items.size();
+  // Due to the bitmaps possibly being not populated (see
+  // https://crbug.com/1427444), we just have empty bitmap data in that case. We
+  // continue to check to make sure that there aren't MORE bitmaps than
+  // items.
+  CHECK_LE(downloaded_shortcut_menu_items.size(),
+           shortcut_menu_item_info.size());
+  while (downloaded_shortcut_menu_items.size() <
+         shortcut_menu_item_info.size()) {
+    downloaded_shortcut_menu_items.emplace_back();
+  }
+  for (size_t menu_index = 0; menu_index < shortcut_menu_item_info.size();
        menu_index++) {
     proto::ShortcutMenuInfo* new_shortcut_menu_item =
         shortcut_menus->add_shortcut_menu_info();
@@ -111,7 +117,7 @@
         shortcut_menu_item_info[menu_index].url.spec());
 
     for (const auto& [size, time] :
-         shortcut_menu_items[menu_index][IconPurpose::ANY]) {
+         downloaded_shortcut_menu_items[menu_index][IconPurpose::ANY]) {
       proto::ShortcutIconData* icon_data =
           new_shortcut_menu_item->add_icon_data_any();
       icon_data->set_icon_size(size);
@@ -119,7 +125,7 @@
     }
 
     for (const auto& [size, time] :
-         shortcut_menu_items[menu_index][IconPurpose::MASKABLE]) {
+         downloaded_shortcut_menu_items[menu_index][IconPurpose::MASKABLE]) {
       proto::ShortcutIconData* icon_data =
           new_shortcut_menu_item->add_icon_data_maskable();
       icon_data->set_icon_size(size);
@@ -127,7 +133,7 @@
     }
 
     for (const auto& [size, time] :
-         shortcut_menu_items[menu_index][IconPurpose::MONOCHROME]) {
+         downloaded_shortcut_menu_items[menu_index][IconPurpose::MONOCHROME]) {
       proto::ShortcutIconData* icon_data =
           new_shortcut_menu_item->add_icon_data_monochrome();
       icon_data->set_icon_size(size);
diff --git a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc
index bfe5a67..7ecf3ea 100644
--- a/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc
+++ b/chrome/browser/web_applications/os_integration/shortcut_menu_handling_sub_manager_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cstddef>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -26,6 +27,7 @@
 #include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_params.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registry_update.h"
 #include "chrome/common/chrome_features.h"
 #include "components/webapps/browser/install_result_code.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -242,15 +244,18 @@
                   testing::Eq(base::StrCat(
                       {kWebAppUrl.spec(), base::NumberToString(menu_index)})));
 
-      EXPECT_TRUE(os_integration_state.shortcut_menus()
-                      .shortcut_menu_info(menu_index)
-                      .icon_data_any_size() == num_sizes);
-      EXPECT_TRUE(os_integration_state.shortcut_menus()
-                      .shortcut_menu_info(menu_index)
-                      .icon_data_maskable_size() == num_sizes);
-      EXPECT_TRUE(os_integration_state.shortcut_menus()
-                      .shortcut_menu_info(menu_index)
-                      .icon_data_monochrome_size() == num_sizes);
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_any_size(),
+                num_sizes);
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_maskable_size(),
+                num_sizes);
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_monochrome_size(),
+                num_sizes);
 
       for (int size_index = 0; size_index < num_sizes; size_index++) {
         EXPECT_TRUE(os_integration_state.shortcut_menus()
@@ -284,6 +289,70 @@
   }
 }
 
+// This tests our handling of https://crbug.com/1427444.
+TEST_P(ShortcutMenuHandlingSubManagerConfigureTest, NoDownloadedIcons_1427444) {
+  const int num_menu_items = 2;
+
+  const std::vector<int> sizes = {icon_size::k64, icon_size::k128};
+  const std::vector<SkColor> colors = {SK_ColorRED, SK_ColorRED};
+  const AppId& app_id = InstallWebAppWithShortcutMenuIcons(
+      MakeIconBitmaps({{IconPurpose::ANY, sizes, colors},
+                       {IconPurpose::MASKABLE, sizes, colors},
+                       {IconPurpose::MONOCHROME, sizes, colors}},
+                      num_menu_items));
+  // Remove the downloaded icons & resync os integration.
+  {
+    ScopedRegistryUpdate remove_downloaded(&provider().sync_bridge_unsafe());
+    remove_downloaded->UpdateApp(app_id)->SetDownloadedShortcutsMenuIconsSizes(
+        {});
+  }
+  if (AreOsIntegrationSubManagersEnabled()) {
+    base::test::TestFuture<void> future;
+    provider().scheduler().SynchronizeOsIntegration(app_id,
+                                                    future.GetCallback());
+    ASSERT_TRUE(future.Wait());
+  }
+
+  auto state =
+      provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id);
+  ASSERT_TRUE(state.has_value());
+  const proto::WebAppOsIntegrationState& os_integration_state = state.value();
+  if (AreOsIntegrationSubManagersEnabled()) {
+    EXPECT_TRUE(
+        os_integration_state.shortcut_menus().shortcut_menu_info_size() ==
+        num_menu_items);
+
+    for (int menu_index = 0; menu_index < num_menu_items; menu_index++) {
+      EXPECT_THAT(os_integration_state.shortcut_menus()
+                      .shortcut_menu_info(menu_index)
+                      .shortcut_name(),
+                  testing::Eq(base::StrCat(
+                      {"shortcut_name", base::NumberToString(menu_index)})));
+
+      EXPECT_THAT(os_integration_state.shortcut_menus()
+                      .shortcut_menu_info(menu_index)
+                      .shortcut_launch_url(),
+                  testing::Eq(base::StrCat(
+                      {kWebAppUrl.spec(), base::NumberToString(menu_index)})));
+
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_any_size(),
+                0);
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_maskable_size(),
+                0);
+      EXPECT_EQ(os_integration_state.shortcut_menus()
+                    .shortcut_menu_info(menu_index)
+                    .icon_data_monochrome_size(),
+                0);
+    }
+  } else {
+    ASSERT_FALSE(os_integration_state.has_shortcut_menus());
+  }
+}
+
 INSTANTIATE_TEST_SUITE_P(
     All,
     ShortcutMenuHandlingSubManagerConfigureTest,
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc
index 264c765..8cbb0444 100644
--- a/chrome/browser/web_applications/test/web_app_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -261,10 +261,11 @@
 
 std::vector<WebAppShortcutsMenuItemInfo> CreateRandomShortcutsMenuItemInfos(
     const GURL& scope,
+    int num,
     RandomHelper& random) {
   const uint32_t suffix = random.next_uint();
   std::vector<WebAppShortcutsMenuItemInfo> shortcuts_menu_item_infos;
-  for (int i = random.next_uint(4) + 1; i >= 0; --i) {
+  for (int i = num - 1; i >= 0; --i) {
     std::string suffix_str =
         base::NumberToString(suffix) + base::NumberToString(i);
     WebAppShortcutsMenuItemInfo shortcut_info;
@@ -308,14 +309,15 @@
 }
 
 std::vector<IconSizes> CreateRandomDownloadedShortcutsMenuIconsSizes(
+    int num,
     RandomHelper& random) {
   std::vector<IconSizes> results;
-  for (unsigned int i = 0; i < 3; ++i) {
+  for (int i = 0; i < num; ++i) {
     IconSizes result;
     std::vector<SquareSizePx> shortcuts_menu_icon_sizes_any;
     std::vector<SquareSizePx> shortcuts_menu_icon_sizes_maskable;
     std::vector<SquareSizePx> shortcuts_menu_icon_sizes_monochrome;
-    for (unsigned int j = 0; j < i; ++j) {
+    for (int j = 0; j < i; ++j) {
       shortcuts_menu_icon_sizes_any.push_back(random.next_uint(256) + 1);
       shortcuts_menu_icon_sizes_maskable.push_back(random.next_uint(256) + 1);
       shortcuts_menu_icon_sizes_monochrome.push_back(random.next_uint(256) + 1);
@@ -695,10 +697,14 @@
   }
   app->SetAdditionalSearchTerms(std::move(additional_search_terms));
 
+  int num_shortcut_menus = static_cast<int>(random.next_uint(4)) + 1;
   app->SetShortcutsMenuItemInfos(
-      CreateRandomShortcutsMenuItemInfos(scope, random));
+      CreateRandomShortcutsMenuItemInfos(scope, num_shortcut_menus, random));
   app->SetDownloadedShortcutsMenuIconsSizes(
-      CreateRandomDownloadedShortcutsMenuIconsSizes(random));
+      CreateRandomDownloadedShortcutsMenuIconsSizes(num_shortcut_menus,
+                                                    random));
+  CHECK_EQ(app->shortcuts_menu_item_infos().size(),
+           app->downloaded_shortcuts_menu_icons_sizes().size());
   app->SetManifestUrl(base_url.Resolve("/manifest" + seed_str + ".json"));
 
   const int num_allowed_launch_protocols = random.next_uint(8);
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index baf4dd28..7468ce1 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -1102,16 +1102,13 @@
       file_handler.accept.push_back(std::move(accept_entry));
     }
 
-    if (WebAppFileHandlerManager::IconsEnabled()) {
-      absl::optional<std::vector<apps::IconInfo>> file_handler_icon_infos =
-          ParseAppIconInfos("WebApp", file_handler_proto.downloaded_icons());
-      if (!file_handler_icon_infos) {
-        // ParseAppIconInfos() reports any errors.
-        return nullptr;
-      }
-      file_handler.downloaded_icons =
-          std::move(file_handler_icon_infos.value());
+    absl::optional<std::vector<apps::IconInfo>> file_handler_icon_infos =
+        ParseAppIconInfos("WebApp", file_handler_proto.downloaded_icons());
+    if (!file_handler_icon_infos) {
+      // ParseAppIconInfos() reports any errors.
+      return nullptr;
     }
+    file_handler.downloaded_icons = std::move(file_handler_icon_infos.value());
 
     file_handlers.push_back(std::move(file_handler));
   }
@@ -1199,6 +1196,7 @@
     }
     shortcuts_menu_item_infos.emplace_back(std::move(shortcut_info));
   }
+  const size_t shortcut_menu_item_size = shortcuts_menu_item_infos.size();
   web_app->SetShortcutsMenuItemInfos(std::move(shortcuts_menu_item_infos));
 
   std::vector<IconSizes> shortcuts_menu_icons_sizes;
@@ -1222,6 +1220,11 @@
 
     shortcuts_menu_icons_sizes.push_back(std::move(icon_sizes));
   }
+  // Due to the bitmaps possibly being not populated (see
+  // https://crbug.com/1427444), we just have empty bitmap data in that case.
+  while (shortcuts_menu_icons_sizes.size() < shortcut_menu_item_size) {
+    shortcuts_menu_icons_sizes.emplace_back();
+  }
   web_app->SetDownloadedShortcutsMenuIconsSizes(
       std::move(shortcuts_menu_icons_sizes));
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.cc b/chrome/browser/web_applications/web_app_icon_manager.cc
index 6e3dd40..485b080 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager.cc
@@ -462,6 +462,7 @@
     // item.
     results.value.push_back(std::move(result));
   }
+  CHECK_EQ(shortcuts_menu_icons_sizes.size(), results.value.size());
   return results;
 }
 
@@ -565,6 +566,7 @@
     // item.
     results.value.push_back(std::move(data));
   }
+  CHECK_EQ(shortcuts_menu_icons_sizes.size(), results.value.size());
   return results;
 }
 
diff --git a/chrome/browser/web_applications/web_app_install_info.h b/chrome/browser/web_applications/web_app_install_info.h
index 4a7b93c..94cbc63 100644
--- a/chrome/browser/web_applications/web_app_install_info.h
+++ b/chrome/browser/web_applications/web_app_install_info.h
@@ -290,6 +290,8 @@
   // Vector of shortcut icon bitmaps keyed by their square size. The index of a
   // given |IconBitmaps| matches that of the shortcut in
   // |shortcuts_menu_item_infos| whose bitmaps it contains.
+  // Notes: It is not guaranteed that these are populated if the menu items are.
+  // See https://crbug.com/1427444.
   ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps;
 
   // The URL protocols/schemes that the app can handle.
diff --git a/chrome/browser/web_applications/web_app_install_utils.cc b/chrome/browser/web_applications/web_app_install_utils.cc
index 7c7a922..9890be9 100644
--- a/chrome/browser/web_applications/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/web_app_install_utils.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/web_applications/web_app_chromeos_data.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_icon_generator.h"
+#include "chrome/browser/web_applications/web_app_install_info.h"
 #include "chrome/browser/web_applications/web_app_install_params.h"
 #include "chrome/browser/web_applications/web_app_sources.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
@@ -221,19 +222,32 @@
 }
 
 std::vector<IconSizes> GetDownloadedShortcutsMenuIconsSizes(
+    const std::vector<WebAppShortcutsMenuItemInfo>& shortcuts_menu_items,
     const ShortcutsMenuIconBitmaps& shortcuts_menu_icon_bitmaps) {
+  // Due to the bitmaps possibly being not populated (see
+  // https://crbug.com/1427444), we create empty bitmaps in that case. We
+  // continue to check to make sure that there aren't MORE bitmaps than
+  // items.
+  CHECK_LE(shortcuts_menu_icon_bitmaps.size(), shortcuts_menu_items.size());
   std::vector<IconSizes> shortcuts_menu_icons_sizes;
-  shortcuts_menu_icons_sizes.reserve(shortcuts_menu_icon_bitmaps.size());
-  for (const auto& shortcut_icon_bitmaps : shortcuts_menu_icon_bitmaps) {
+  shortcuts_menu_icons_sizes.reserve(shortcuts_menu_items.size());
+  IconBitmaps empty_icon_bitmaps;
+  for (size_t i = 0; i < shortcuts_menu_items.size(); ++i) {
+    const IconBitmaps* shortcut_icon_bitmaps;
+    if (i < shortcuts_menu_icon_bitmaps.size()) {
+      shortcut_icon_bitmaps = &shortcuts_menu_icon_bitmaps[i];
+    } else {
+      shortcut_icon_bitmaps = &empty_icon_bitmaps;
+    }
     IconSizes icon_sizes;
     icon_sizes.SetSizesForPurpose(IconPurpose::ANY,
-                                  GetSquareSizePxs(shortcut_icon_bitmaps.any));
+                                  GetSquareSizePxs(shortcut_icon_bitmaps->any));
     icon_sizes.SetSizesForPurpose(
         IconPurpose::MASKABLE,
-        GetSquareSizePxs(shortcut_icon_bitmaps.maskable));
+        GetSquareSizePxs(shortcut_icon_bitmaps->maskable));
     icon_sizes.SetSizesForPurpose(
         IconPurpose::MONOCHROME,
-        GetSquareSizePxs(shortcut_icon_bitmaps.monochrome));
+        GetSquareSizePxs(shortcut_icon_bitmaps->monochrome));
     shortcuts_menu_icons_sizes.push_back(std::move(icon_sizes));
   }
   return shortcuts_menu_icons_sizes;
@@ -362,6 +376,8 @@
     web_app_info->shortcuts_menu_icon_bitmaps.emplace_back(
         std::move(shortcut_icon_bitmaps));
   }
+  CHECK_EQ(web_app_info->shortcuts_menu_icon_bitmaps.size(),
+           web_app_info->shortcuts_menu_item_infos.size());
 }
 
 // Reconcile the file handling icons that were specified in the manifest with
@@ -1187,6 +1203,7 @@
     web_app.SetShortcutsMenuItemInfos(web_app_info.shortcuts_menu_item_infos);
     web_app.SetDownloadedShortcutsMenuIconsSizes(
         GetDownloadedShortcutsMenuIconsSizes(
+            web_app_info.shortcuts_menu_item_infos,
             web_app_info.shortcuts_menu_icon_bitmaps));
   }
 
diff --git a/chrome/browser/webapps/web_app_offline_browsertest.cc b/chrome/browser/webapps/web_app_offline_browsertest.cc
index 48eb045..75269a7 100644
--- a/chrome/browser/webapps/web_app_offline_browsertest.cc
+++ b/chrome/browser/webapps/web_app_offline_browsertest.cc
@@ -496,14 +496,6 @@
  public:
   WebAppOfflineDarkModeTest() {
     std::vector<base::test::FeatureRef> disabled_features;
-#if BUILDFLAG(IS_CHROMEOS)
-    disabled_features.push_back(chromeos::features::kDarkLightMode);
-#endif
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    disabled_features.push_back(ash::features::kNotificationsRefresh);
-#endif
-
     feature_list_.InitWithFeatures({features::kPWAsDefaultOfflinePage,
                                     blink::features::kWebAppEnableDarkMode},
                                    {disabled_features});
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 665b72b..99ef7a44 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1679680693-d693694c85959104915ecf5cb194386a47140e9b.profdata
+chrome-mac-arm-main-1679709158-c339e2ba66284dfbe68931ac4e60c8c944b5b0ae.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e33029f..5de0e6c1 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1679659147-930aaffb60325f97349600d849ae51c381292414.profdata
+chrome-mac-main-1679680693-afa00bb871e5d51f0ec7e44205aa4419b9ac1325.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index f263121..8befee2b 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1679659147-2168e0c7290c17295fe30c046bb719069031b0d5.profdata
+chrome-win32-main-1679691474-7c856c3b7fb74beb20e566c3cae4e9bfcfd78195.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 26158140..9a767bb 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1679680693-06d47d930b07d390341ca29eb35a7a52ff62ce7e.profdata
+chrome-win64-main-1679702393-2eb9be2ac21f3e88a524a2a8cde402675eedbb83.profdata
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
index 3d34fa6..fcb3dc2 100644
--- a/chrome/services/printing/print_backend_service_impl.cc
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -21,6 +21,7 @@
 #include "base/threading/sequence_bound.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/printing/printing_init.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "components/crash/core/common/crash_keys.h"
@@ -501,6 +502,7 @@
       mojom::DefaultPrinterNameResult::NewDefaultPrinterName(default_printer));
 }
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintBackendServiceImpl::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
@@ -522,6 +524,7 @@
       mojom::PrinterSemanticCapsAndDefaultsResult::NewPrinterCaps(
           std::move(printer_caps)));
 }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void PrintBackendServiceImpl::FetchCapabilities(
     const std::string& printer_name,
diff --git a/chrome/services/printing/print_backend_service_impl.h b/chrome/services/printing/print_backend_service_impl.h
index de21509..f31eba3 100644
--- a/chrome/services/printing/print_backend_service_impl.h
+++ b/chrome/services/printing/print_backend_service_impl.h
@@ -17,6 +17,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -151,10 +152,12 @@
   void GetDefaultPrinterName(
       mojom::PrintBackendService::GetDefaultPrinterNameCallback callback)
       override;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       mojom::PrintBackendService::GetPrinterSemanticCapsAndDefaultsCallback
           callback) override;
+#endif
   void FetchCapabilities(
       const std::string& printer_name,
       mojom::PrintBackendService::FetchCapabilitiesCallback callback) override;
diff --git a/chrome/services/printing/public/mojom/print_backend_service.mojom b/chrome/services/printing/public/mojom/print_backend_service.mojom
index e119ff0..9d79b09 100644
--- a/chrome/services/printing/public/mojom/print_backend_service.mojom
+++ b/chrome/services/printing/public/mojom/print_backend_service.mojom
@@ -102,6 +102,7 @@
     => (DefaultPrinterNameResult printer_name);
 
   // Gets the semantic capabilities and defaults for a specific printer.
+  [EnableIf=is_chromeos_ash]
   GetPrinterSemanticCapsAndDefaults(string printer_name)
     => (PrinterSemanticCapsAndDefaultsResult printer_caps);
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 3b4885b..957e309 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -7163,6 +7163,7 @@
       "../browser/ui/webui/settings/site_settings_permissions_handler_unittest.cc",
       "../browser/ui/webui/side_panel/bookmarks/bookmarks_page_handler_unittest.cc",
       "../browser/ui/webui/side_panel/companion/companion_url_builder_unittest.cc",
+      "../browser/ui/webui/side_panel/companion/promo_handler_unittest.cc",
       "../browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc",
       "../browser/ui/webui/side_panel/reading_list/reading_list_page_handler_unittest.cc",
       "../browser/ui/webui/side_panel/user_notes/user_notes_page_handler_unittest.cc",
@@ -7357,6 +7358,7 @@
       "//chrome/browser/ui/webui/discards:mojo_bindings",
       "//chrome/browser/ui/webui/downloads:mojo_bindings",
       "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
+      "//chrome/browser/ui/webui/side_panel/companion:mojo_bindings",
       "//chrome/browser/ui/webui/side_panel/companion/proto",
       "//chrome/browser/ui/webui/side_panel/customize_chrome:mojo_bindings",
       "//chrome/browser/ui/webui/side_panel/user_notes:mojo_bindings",
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 7304b77..c0b4586 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -796,9 +796,11 @@
                                                bool wait_for_response,
                                                const int client_command_id,
                                                const Timeout* timeout) {
-  DCHECK(IsConnected());
-  if (parent_ == nullptr && !socket_->IsConnected())
+  if (parent_ == nullptr && !socket_->IsConnected()) {
+    // The browser has crashed or closed the connection, e.g. due to
+    // DeveloperToolsAvailability policy change.
     return Status(kDisconnected, "not connected to DevTools");
+  }
 
   // |client_command_id| will be 0 for commands sent by ChromeDriver
   int command_id =
diff --git a/chrome/test/data/web_apps/sample_web_app.json b/chrome/test/data/web_apps/sample_web_app.json
index c9675024..f5b6502f 100644
--- a/chrome/test/data/web_apps/sample_web_app.json
+++ b/chrome/test/data/web_apps/sample_web_app.json
@@ -2,36 +2,47 @@
    "!app_id": "eajjdjobhihlgobdfaehiiheinneagde",
    "!name": "Name1234",
    "additional_search_terms": [ "Foo_1234_0", "Foo_1234_1", "Foo_1234_2", "Foo_1234_3", "Foo_1234_4", "Foo_1234_5", "Foo_1234_6" ],
-   "allowed_launch_protocols": [ "web+test_1234_0" ],
-   "always_show_toolbar_in_fullscreen": false,
+   "allowed_launch_protocols": [ "web+test_1234_0", "web+test_1234_1", "web+test_1234_2", "web+test_1234_3", "web+test_1234_4", "web+test_1234_5", "web+test_1234_6" ],
+   "always_show_toolbar_in_fullscreen": true,
    "app_service_icon_url": "chrome://app-icon/eajjdjobhihlgobdfaehiiheinneagde/32",
-   "app_size_in_bytes": "1505422652",
+   "app_size_in_bytes": "382722586",
    "background_color": "rgba(77,188,194,0.9686274509803922)",
    "capture_links": "kNone",
    "current_os_integration_states": {
       "file_handling": [  ],
       "protocols_handled": {
-         "web+test0": "https://example.com/scope1234/start12340"
       },
-      "run_on_os_login": "not_run",
+      "run_on_os_login": "windowed",
       "shortcut_descriptions": {
          "description": "Description1234",
          "icon_size_to_timestamp_map": {
-            "32": "1970-02-04 17:47:46.335 UTC"
+            "32": "1970-02-18 21:58:05.750 UTC"
          },
          "title": "Name1234"
       },
-      "shortcut_menus": [  ],
+      "shortcut_menus": [ {
+         "icon_data_any": {
+            "48": "1970-02-05 06:19:19.039 UTC"
+         },
+         "icon_data_maskable": {
+            "48": "1970-02-05 06:19:19.039 UTC"
+         },
+         "icon_data_monochrome": {
+            "48": "1970-02-05 06:19:19.039 UTC"
+         },
+         "shortcut_launch_url": "https://example.com/scope1234/0",
+         "shortcut_name": "shortcut_name0"
+      } ],
       "uninstall_registration": {
          "display_name": "Name1234",
-         "registered_with_os": true
+         "registered_with_os": false
       }
    },
    "dark_mode_background_color": "none",
    "dark_mode_theme_color": "rgba(34,214,187,1)",
-   "data_size_in_bytes": "1449447663",
+   "data_size_in_bytes": "1450270097",
    "description": "Description1234",
-   "disallowed_launch_protocols": [ "web+disallowed_1234_0", "web+disallowed_1234_1", "web+disallowed_1234_2", "web+disallowed_1234_3", "web+disallowed_1234_4", "web+disallowed_1234_5" ],
+   "disallowed_launch_protocols": [ "web+disallowed_1234_0", "web+disallowed_1234_1", "web+disallowed_1234_2", "web+disallowed_1234_3", "web+disallowed_1234_4", "web+disallowed_1234_5", "web+disallowed_1234_6" ],
    "display_mode": "fullscreen",
    "display_override": [ "standalone", "fullscreen" ],
    "downloaded_icon_sizes": {
@@ -45,15 +56,10 @@
       "MONOCHROME": [  ],
       "index": 0
    }, {
-      "ANY": [ 36 ],
-      "MASKABLE": [ 184 ],
-      "MONOCHROME": [ 60 ],
+      "ANY": [ 118 ],
+      "MASKABLE": [ 38 ],
+      "MONOCHROME": [ 228 ],
       "index": 1
-   }, {
-      "ANY": [ 136, 6 ],
-      "MASKABLE": [ 98, 254 ],
-      "MONOCHROME": [ 109, 27 ],
-      "index": 2
    } ],
    "file_handler_approval_state": "kRequiresPrompt",
    "file_handler_os_integration_state": "kDisabled",
@@ -172,32 +178,32 @@
    },
    "last_badging_time": "1970-01-15 16:10:56.662 UTC",
    "last_launch_time": "1970-01-21 15:31:39.413 UTC",
-   "latest_install_source": 26,
+   "latest_install_source": 16,
    "launch_handler": {
-      "client_mode": "kNavigateExisting"
+      "client_mode": "kNavigateNew"
    },
    "launch_query_params": "944292860",
    "lock_screen_start_url": "https://example.com/scope1234/lock_screen_start_url3022990271",
    "management_type_to_external_configuration_map": {
       "Default": {
          "additional_policy_ids": [ "policy_id_1_1234", "policy_id_2_1234" ],
-         "install_urls": [ "https://example.com/installer1_1234/" ],
-         "is_placeholder": false
+         "install_urls": [ "https://example.com/installer2_1234/" ],
+         "is_placeholder": true
       },
       "SubApp": {
-         "additional_policy_ids": [  ],
-         "install_urls": [  ],
+         "additional_policy_ids": [ "policy_id_2_1234" ],
+         "install_urls": [ "https://example.com/installer1_1234/", "https://example.com/installer2_1234/" ],
          "is_placeholder": true
       },
       "WebAppStore": {
          "additional_policy_ids": [ "policy_id_1_1234" ],
          "install_urls": [ "https://example.com/installer1_1234/", "https://example.com/installer2_1234/" ],
-         "is_placeholder": false
+         "is_placeholder": true
       }
    },
    "manifest_icons": [  ],
    "manifest_id": null,
-   "manifest_update_time": "1970-02-12 16:20:18.762 UTC",
+   "manifest_update_time": "1970-01-24 05:49:58.819 UTC",
    "manifest_url": "https://example.com/manifest1234.json",
    "note_taking_new_note_url": "https://example.com/scope1234/new_note1289939860",
    "parent_app_id": "",
@@ -235,73 +241,33 @@
       "icons": {
          "ANY": [ {
             "square_size_px": 14,
-            "url": "https://example.com/shortcuts/icon28940158931"
+            "url": "https://example.com/shortcuts/icon24240987411"
          } ],
          "MASKABLE": [ {
             "square_size_px": 29,
-            "url": "https://example.com/shortcuts/icon28940158932"
+            "url": "https://example.com/shortcuts/icon24240987412"
          }, {
             "square_size_px": 7,
-            "url": "https://example.com/shortcuts/icon28940158930"
+            "url": "https://example.com/shortcuts/icon24240987410"
          } ],
          "MONOCHROME": [  ]
       },
-      "name": "shortcut2894015893",
-      "url": "https://example.com/scope1234/shortcut2894015893"
+      "name": "shortcut2424098741",
+      "url": "https://example.com/scope1234/shortcut2424098741"
    }, {
       "icons": {
          "ANY": [ {
             "square_size_px": 0,
-            "url": "https://example.com/shortcuts/icon28940158920"
+            "url": "https://example.com/shortcuts/icon24240987400"
          } ],
          "MASKABLE": [  ],
          "MONOCHROME": [ {
             "square_size_px": 16,
-            "url": "https://example.com/shortcuts/icon28940158921"
+            "url": "https://example.com/shortcuts/icon24240987401"
          } ]
       },
-      "name": "shortcut2894015892",
-      "url": "https://example.com/scope1234/shortcut2894015892"
-   }, {
-      "icons": {
-         "ANY": [ {
-            "square_size_px": 11,
-            "url": "https://example.com/shortcuts/icon28940158911"
-         } ],
-         "MASKABLE": [ {
-            "square_size_px": 21,
-            "url": "https://example.com/shortcuts/icon28940158912"
-         }, {
-            "square_size_px": 7,
-            "url": "https://example.com/shortcuts/icon28940158910"
-         } ],
-         "MONOCHROME": [  ]
-      },
-      "name": "shortcut2894015891",
-      "url": "https://example.com/scope1234/shortcut2894015891"
-   }, {
-      "icons": {
-         "ANY": [ {
-            "square_size_px": 4,
-            "url": "https://example.com/shortcuts/icon28940158900"
-         } ],
-         "MASKABLE": [ {
-            "square_size_px": 34,
-            "url": "https://example.com/shortcuts/icon28940158903"
-         } ],
-         "MONOCHROME": [ {
-            "square_size_px": 44,
-            "url": "https://example.com/shortcuts/icon28940158904"
-         }, {
-            "square_size_px": 25,
-            "url": "https://example.com/shortcuts/icon28940158902"
-         }, {
-            "square_size_px": 10,
-            "url": "https://example.com/shortcuts/icon28940158901"
-         } ]
-      },
-      "name": "shortcut2894015890",
-      "url": "https://example.com/scope1234/shortcut2894015890"
+      "name": "shortcut2424098740",
+      "url": "https://example.com/scope1234/shortcut2424098740"
    } ],
    "sources": [ "SubApp", "WebAppStore", "Sync", "Default" ],
    "start_url": "https://example.com/scope1234/start1234",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.ts
index 9275dd3..d9457ee2 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.ts
@@ -226,6 +226,70 @@
         'element has correct data attribute');
   });
 
+  test(
+      'displays one preview tile for images with the same unitId', async () => {
+        personalizationStore.data.wallpaper.backdrop.images = {
+          'id_0': [
+            {
+              assetId: BigInt(0),
+              attribution: ['Late Afternoon Image 0-0'],
+              type: OnlineImageType.kPreview,
+              unitId: BigInt(1),
+              url: {url: 'https://id_0-0/'},
+            },
+            {
+              assetId: BigInt(1),
+              attribution: ['Light Image 0-1'],
+              type: OnlineImageType.kLight,
+              unitId: BigInt(1),
+              url: {url: 'https://id_0-1/'},
+            },
+            {
+              assetId: BigInt(2),
+              attribution: ['Dark Image 0-2'],
+              type: OnlineImageType.kDark,
+              unitId: BigInt(1),
+              url: {url: 'https://id_0-2/'},
+            },
+            {
+              assetId: BigInt(3),
+              attribution: ['Morning Image 0-3'],
+              type: OnlineImageType.kMorning,
+              unitId: BigInt(1),
+              url: {url: 'https://id_0-3/'},
+            },
+            {
+              assetId: BigInt(4),
+              attribution: ['Late Afternoon Image 0-4'],
+              type: OnlineImageType.kLateAfternoon,
+              unitId: BigInt(1),
+              url: {url: 'https://id_0-4/'},
+            },
+          ],
+        };
+        personalizationStore.data.wallpaper.backdrop.collections =
+            wallpaperProvider.collections;
+        personalizationStore.data.wallpaper.loading.images = {
+          'id_0': false,
+        };
+        personalizationStore.data.wallpaper.loading.collections = false;
+
+        wallpaperImagesElement =
+            initElement(WallpaperImages, {collectionId: 'id_0'});
+        await waitAfterNextRender(wallpaperImagesElement);
+
+        const elements =
+            Array.from(wallpaperImagesElement.shadowRoot!
+                           .querySelectorAll<WallpaperGridItem>(
+                               `${WallpaperGridItem.is}:not([hidden])`));
+
+        assertDeepEquals(
+            [
+              {url: 'https://id_0-0/'},
+            ],
+            elements[0]!.src, 'preview image has only one url');
+      });
+
   test('displays dark light tile for images with same unitId', async () => {
     wallpaperImagesElement = await createWithDefaultData();
 
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index ccffcfd..4923a89d 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -112,6 +112,7 @@
     "settings_subpage_test.ts",
     "settings_toggle_button_tests.ts",
     "settings_ui_tests.ts",
+    "simple_confirmation_dialog_test.ts",
     "site_data_test.ts",
     "site_details_permission_tests.ts",
     "site_details_permission_device_entry_tests.ts",
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 6fd10595..fb3511c 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -934,6 +934,7 @@
  ['SecurityKeysSetPinDialog', 'security_keys_set_pin_dialog_test.js'],
  ['SecurityKeysPhonesSubpage', 'security_keys_phones_subpage_test.js'],
  ['SecureDns', 'secure_dns_test.js'],
+ ['SimpleConfirmationDialog', 'simple_confirmation_dialog_test.js'],
  ['SiteDataTest', 'site_data_test.js'],
  ['SiteDetailsPermission', 'site_details_permission_tests.js'],
  [
diff --git a/chrome/test/data/webui/settings/simple_confirmation_dialog_test.ts b/chrome/test/data/webui/settings/simple_confirmation_dialog_test.ts
new file mode 100644
index 0000000..59f2fa87
--- /dev/null
+++ b/chrome/test/data/webui/settings/simple_confirmation_dialog_test.ts
@@ -0,0 +1,57 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://settings/lazy_load.js';
+
+import {SettingsSimpleConfirmationDialogElement} from 'chrome://settings/lazy_load.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {eventToPromise} from 'chrome://webui-test/test_util.js';
+
+suite('settings-simple-confirmation-dialog', function() {
+  let dialog: SettingsSimpleConfirmationDialogElement;
+
+  setup(function() {
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    dialog = document.createElement('settings-simple-confirmation-dialog');
+    document.body.appendChild(dialog);
+  });
+
+  test('strings', function() {
+    dialog.titleText = 'fooTitle';
+    dialog.bodyText = 'fooBody';
+    dialog.confirmText = 'fooConfirm';
+
+    const title = dialog.shadowRoot!.querySelector('[slot=title]');
+    assertTrue(!!title);
+    assertEquals(dialog.titleText, title.textContent);
+
+    const body = dialog.shadowRoot!.querySelector('[slot=body]');
+    assertTrue(!!body);
+    assertEquals(dialog.bodyText, body.textContent!.trim());
+
+    assertEquals(dialog.confirmText, dialog.$.confirm.textContent!.trim());
+  });
+
+  test('noPrimaryButton', function() {
+    assertFalse(dialog.noPrimaryButton);
+    assertTrue(dialog.$.confirm.classList.contains('action-button'));
+
+    dialog.noPrimaryButton = true;
+    assertFalse(dialog.$.confirm.classList.contains('action-button'));
+  });
+
+  test('wasConfirmed_false', async function() {
+    const whenClosed = eventToPromise('close', dialog);
+    dialog.$.cancel.click();
+    await whenClosed;
+    assertFalse(dialog.wasConfirmed());
+  });
+
+  test('wasConfirmed_true', async function() {
+    const whenClosed = eventToPromise('close', dialog);
+    dialog.$.confirm.click();
+    await whenClosed;
+    assertTrue(dialog.wasConfirmed());
+  });
+});
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 0d1ee727..d5fa1a8 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -884,7 +884,7 @@
 
       data_deps = [
         ":updater_selfupdate_test_crx",
-        "//chrome/updater/mac:ksadmin",
+        "//chrome/updater/mac:ksadmin_test",
         "//chrome/updater/mac:updater_bundle_test",
       ]
 
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn
index 37d5f665..422b277 100644
--- a/chrome/updater/mac/BUILD.gn
+++ b/chrome/updater/mac/BUILD.gn
@@ -52,7 +52,7 @@
     "//chrome/updater:constants_prod",
   ]
   public_deps = [
-    ":ksadmin_copy",
+    ":ksadmin",
     ":ksadmin_link",
   ]
 }
@@ -77,10 +77,7 @@
   if (is_asan) {
     deps += [ ":keystone_agent_bundle_resource_executable_test_asan_dylib" ]
   }
-  public_deps = [
-    ":ksadmin_test_copy",
-    ":ksadmin_test_link",
-  ]
+  public_deps = [ ":ksadmin_test_copy" ]
 }
 
 source_set("privileged_helper_sources") {
@@ -334,7 +331,7 @@
 }
 
 executable("ksadmin") {
-  output_name = "ksadmin"
+  output_dir = "$root_out_dir/${updater_product_full_name}.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Helpers"
   sources = [ "keystone/ksadmin_main.cc" ]
 
   deps = [
@@ -351,14 +348,7 @@
   }
 }
 
-copy("ksadmin_copy") {
-  sources = [ "$root_out_dir/ksadmin" ]
-  outputs = [ "$root_out_dir/${updater_product_full_name}.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Helpers/ksadmin" ]
-  deps = [ ":ksadmin" ]
-}
-
 executable("ksadmin_test") {
-  output_name = "ksadmin_test"
   sources = [ "keystone/ksadmin_main.cc" ]
 
   deps = [
@@ -411,12 +401,6 @@
   deps = [ ":ksadmin" ]
 }
 
-symlink("ksadmin_test_link") {
-  source = "$root_out_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Helpers/ksadmin"
-  output = "$root_out_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/MacOS/ksadmin"
-  deps = [ ":ksadmin_test" ]
-}
-
 mac_app_bundle("keystone_agent_bundle") {
   info_plist = "keystone/Info.plist"
   sources = [ "keystone/agent_main.cc" ]
@@ -601,7 +585,6 @@
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/MacOS/$keystone_app_name",
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Helpers/ksinstall",
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Helpers/ksadmin",
-    "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/MacOS/ksadmin",
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Resources/${keystone_app_name}Agent.app/Contents/MacOS/${keystone_app_name}Agent",
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Resources/${keystone_app_name}Agent.app/Contents/Info.plist",
     "$root_build_dir/${updater_product_full_name}_test.app/Contents/Helpers/$keystone_app_name.bundle/Contents/Info.plist",
diff --git a/chrome/updater/mac/keystone/ksadmin_unittest.cc b/chrome/updater/mac/keystone/ksadmin_unittest.cc
index 0cdd482..95b6d1b 100644
--- a/chrome/updater/mac/keystone/ksadmin_unittest.cc
+++ b/chrome/updater/mac/keystone/ksadmin_unittest.cc
@@ -26,7 +26,7 @@
 int RunKSAdmin(std::string* std_out, const std::vector<std::string>& args) {
   base::FilePath out_dir;
   EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &out_dir));
-  base::CommandLine command(out_dir.Append(FILE_PATH_LITERAL("ksadmin")));
+  base::CommandLine command(out_dir.Append(FILE_PATH_LITERAL("ksadmin_test")));
   for (const auto& arg : args) {
     command.AppendSwitch(arg);
   }
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm
index 42328e6..0c41d99 100644
--- a/chrome/updater/test/integration_tests_mac.mm
+++ b/chrome/updater/test/integration_tests_mac.mm
@@ -200,15 +200,10 @@
 
   absl::optional<base::FilePath> keystone_path = GetKeystoneFolderPath(scope);
   ASSERT_TRUE(keystone_path);
-  absl::optional<base::FilePath> ksadmin_symlink =
-      keystone_path->Append(FILE_PATH_LITERAL(KEYSTONE_NAME ".bundle"))
-          .Append(FILE_PATH_LITERAL("Contents"))
-          .Append(FILE_PATH_LITERAL("MacOS"))
-          .Append(FILE_PATH_LITERAL("ksadmin"));
 
   // Files must exist on the file system.
-  for (const auto& path : {GetInstallDirectory(scope), keystone_path,
-                           GetKSAdminPath(scope), ksadmin_symlink}) {
+  for (const auto& path :
+       {GetInstallDirectory(scope), keystone_path, GetKSAdminPath(scope)}) {
     ASSERT_TRUE(path) << path;
     EXPECT_TRUE(base::PathExists(*path)) << path;
   }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 8571b13..32256199 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-15393.0.0
\ No newline at end of file
+15395.0.0
\ No newline at end of file
diff --git a/chromeos/ui/frame/caption_buttons/frame_size_button.cc b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
index 3b882f2da..f60b4f34 100644
--- a/chromeos/ui/frame/caption_buttons/frame_size_button.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
@@ -244,7 +244,9 @@
     // Owned by the bubble which contains this view. If there is an existing
     // bubble, it will be deactivated and then close and destroy itself.
     auto menu_delegate = std::make_unique<MultitaskMenu>(
-        /*anchor=*/this, GetWidget());
+        /*anchor=*/this, GetWidget(),
+        /*close_on_move_out=*/entry_type ==
+            MultitaskMenuEntryType::kFrameSizeButtonHover);
     auto* menu_delegate_ptr = menu_delegate.get();
     multitask_menu_widget_ =
         base::WrapUnique(views::BubbleDialogDelegateView::CreateBubble(
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.cc b/chromeos/ui/frame/multitask_menu/multitask_menu.cc
index 662e3ac..8f23c4e 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu.cc
@@ -33,7 +33,8 @@
 }  // namespace
 
 MultitaskMenu::MultitaskMenu(views::View* anchor,
-                             views::Widget* parent_widget) {
+                             views::Widget* parent_widget,
+                             bool close_on_move_out) {
   DCHECK(parent_widget);
 
   set_corner_radius(kMultitaskMenuBubbleCornerRadius);
@@ -61,7 +62,7 @@
   multitask_menu_view_ = AddChildView(std::make_unique<MultitaskMenuView>(
       parent_window(),
       base::BindRepeating(&MultitaskMenu::HideBubble, base::Unretained(this)),
-      buttons));
+      buttons, close_on_move_out ? anchor : nullptr));
 
   auto* layout = multitask_menu_view_->SetLayoutManager(
       std::make_unique<views::TableLayout>());
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu.h b/chromeos/ui/frame/multitask_menu/multitask_menu.h
index 1442d554..16c93f8a 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu.h
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu.h
@@ -30,7 +30,9 @@
  public:
   METADATA_HEADER(MultitaskMenu);
 
-  MultitaskMenu(views::View* anchor, views::Widget* parent_widget);
+  MultitaskMenu(views::View* anchor,
+                views::Widget* parent_widget,
+                bool close_on_move_out);
   MultitaskMenu(const MultitaskMenu&) = delete;
   MultitaskMenu& operator=(const MultitaskMenu&) = delete;
   ~MultitaskMenu() override;
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
index b3763ef..d43f19c5 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.cc
@@ -9,6 +9,7 @@
 #include "base/check.h"
 #include "base/functional/callback_forward.h"
 #include "base/metrics/user_metrics.h"
+#include "base/timer/timer.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "chromeos/ui/base/display_util.h"
 #include "chromeos/ui/base/window_properties.h"
@@ -43,6 +44,8 @@
 
 namespace {
 
+bool g_skip_mouse_out_delay_for_testing = false;
+
 constexpr int kCenterPadding = 4;
 constexpr int kLabelFontSize = 13;
 
@@ -54,6 +57,11 @@
 constexpr float kButtonRadDivisor = 2.f;
 constexpr gfx::Insets kButtonInsets = gfx::Insets::TLBR(0, 6, 0, 8);
 
+// If the menu was opened as a result of hovering over the frame size button,
+// moving the mouse outside the menu or size button will result in closing it
+// after 3 seconds have elapsed.
+constexpr base::TimeDelta kMouseExitMenuTimeout = base::Seconds(3);
+
 // Creates multitask button with label.
 std::unique_ptr<views::View> CreateButtonContainer(
     std::unique_ptr<views::View> button_view,
@@ -78,22 +86,41 @@
 
 class MultitaskMenuView::MenuPreTargetHandler : public ui::EventHandler {
  public:
-  MenuPreTargetHandler(aura::Window* menu_window,
-                       base::RepeatingClosure close_callback)
-      : menu_window_(menu_window), close_callback_(std::move(close_callback)) {
+  MenuPreTargetHandler(views::Widget* menu_widget,
+                       base::RepeatingClosure close_callback,
+                       views::View* anchor_view)
+      : menu_widget_(menu_widget),
+        anchor_view_(anchor_view),
+        close_callback_(std::move(close_callback)) {
     aura::Env::GetInstance()->AddPreTargetHandler(
         this, ui::EventTarget::Priority::kSystem);
   }
-
+  MenuPreTargetHandler(const MenuPreTargetHandler&) = delete;
+  MenuPreTargetHandler& operator=(const MenuPreTargetHandler&) = delete;
   ~MenuPreTargetHandler() override {
     aura::Env::GetInstance()->RemovePreTargetHandler(this);
   }
 
   void OnMouseEvent(ui::MouseEvent* event) override {
-    // TODO(b/266441890): Consider closing the menu on ET_MOUSE_MOVED.
     if (event->type() == ui::ET_MOUSE_PRESSED) {
       ProcessPressedEvent(*event);
     }
+
+    if (event->type() == ui::ET_MOUSE_MOVED && anchor_view_) {
+      const gfx::Point screen_location =
+          event->target()->GetScreenLocation(*event);
+      // Stop the existing timer if either the anchor or the menu contain the
+      // event.
+      if (menu_widget_->GetWindowBoundsInScreen().Contains(screen_location) ||
+          anchor_view_->GetBoundsInScreen().Contains(screen_location)) {
+        exit_timer_.Stop();
+      } else if (g_skip_mouse_out_delay_for_testing) {
+        OnExitTimerFinished();
+      } else {
+        exit_timer_.Start(FROM_HERE, kMouseExitMenuTimeout, this,
+                          &MenuPreTargetHandler::OnExitTimerFinished);
+      }
+    }
   }
 
   void OnTouchEvent(ui::TouchEvent* event) override {
@@ -105,15 +132,24 @@
   void ProcessPressedEvent(const ui::LocatedEvent& event) {
     const gfx::Point screen_location = event.target()->GetScreenLocation(event);
     // If the event is out of menu bounds, close the menu.
-    if (!menu_window_->GetBoundsInScreen().Contains(screen_location)) {
+    if (!menu_widget_->GetWindowBoundsInScreen().Contains(screen_location)) {
       close_callback_.Run();
     }
   }
 
  private:
-  // The multitask menu that is currently shown. Guaranteed to outlive `this`,
-  // which will get destroyed when the menu is destructed in `close_callback_`.
-  aura::Window* const menu_window_;
+  void OnExitTimerFinished() { close_callback_.Run(); }
+
+  // The widget of the multitask menu that is currently shown. Guaranteed to
+  // outlive `this`, which will get destroyed when the menu is destructed in
+  // `close_callback_`.
+  views::Widget* const menu_widget_;
+
+  // The anchor of the menu's widget if it exists. Set if there is an anchor and
+  // we want the menu to close if the mouse has exited the menu bounds.
+  views::View* anchor_view_ = nullptr;
+
+  base::OneShotTimer exit_timer_;
 
   base::RepeatingClosure close_callback_;
 };
@@ -123,8 +159,11 @@
 
 MultitaskMenuView::MultitaskMenuView(aura::Window* window,
                                      base::RepeatingClosure close_callback,
-                                     uint8_t buttons)
-    : window_(window), close_callback_(std::move(close_callback)) {
+                                     uint8_t buttons,
+                                     views::View* anchor_view)
+    : window_(window),
+      anchor_view_(anchor_view),
+      close_callback_(std::move(close_callback)) {
   DCHECK(window);
   DCHECK(close_callback_);
   SetUseDefaultFillLayout(true);
@@ -220,8 +259,8 @@
 void MultitaskMenuView::AddedToWidget() {
   // When the menu widget is shown, we install `MenuPreTargetHandler` to close
   // the menu on any events outside.
-  event_handler_ = std::make_unique<MultitaskMenuView::MenuPreTargetHandler>(
-      GetWidget()->GetNativeWindow(), close_callback_);
+  event_handler_ = std::make_unique<MenuPreTargetHandler>(
+      GetWidget(), close_callback_, anchor_view_);
 }
 
 void MultitaskMenuView::OnThemeChanged() {
@@ -241,6 +280,11 @@
               ui::kColorMultitaskFeedbackButtonLabelForeground)));
 }
 
+// static
+void MultitaskMenuView::SetSkipMouseOutDelayFoTesting(bool val) {
+  g_skip_mouse_out_delay_for_testing = val;
+}
+
 void MultitaskMenuView::SplitButtonPressed(SnapDirection direction) {
   SnapController::Get()->CommitSnap(window_, direction, kDefaultSnapRatio);
   close_callback_.Run();
diff --git a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
index 6a332e7..40baad70 100644
--- a/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
+++ b/chromeos/ui/frame/multitask_menu/multitask_menu_view.h
@@ -37,9 +37,13 @@
     kFloat = 1 << 3,
   };
 
+  // `window` is the window that the buttons on this view act on. `anchor_view`
+  // should be passed when we want the functionality of auto-closing the menu
+  // when the mouse moves out of the menu or the anchor.
   MultitaskMenuView(aura::Window* window,
                     base::RepeatingClosure on_any_button_pressed,
-                    uint8_t buttons);
+                    uint8_t buttons,
+                    views::View* anchor_view);
 
   MultitaskMenuView(const MultitaskMenuView&) = delete;
   MultitaskMenuView& operator=(const MultitaskMenuView&) = delete;
@@ -51,6 +55,12 @@
 
   // views::View:
   void AddedToWidget() override;
+  void OnThemeChanged() override;
+
+  // If the menu is opened because of mouse hover, moving the mouse outside the
+  // menu for 3 seconds will result in it auto closing. This function reduces
+  // that 3 second dealy to
+  static void SetSkipMouseOutDelayFoTesting(bool val);
 
   // For testing.
   SplitButtonView* half_button_for_testing() {
@@ -63,9 +73,6 @@
     return float_button_for_testing_.get();
   }
 
-  // views::View:
-  void OnThemeChanged() override;
-
  private:
   class MenuPreTargetHandler;
 
@@ -86,6 +93,11 @@
   // The window which the buttons act on. It is guaranteed to outlive `this`.
   aura::Window* const window_;
 
+  // The view the menu is anchored to if any. This is only passed if we want to
+  // close the menu when the mouse moves out of the multitask menu or its anchor
+  // view.
+  views::View* const anchor_view_;
+
   // Runs after any of the buttons are pressed, or a press out of the menu
   // bounds.
   base::RepeatingClosure close_callback_;
diff --git a/components/autofill/android/java/res/values/dimens.xml b/components/autofill/android/java/res/values/dimens.xml
index 1c76256..46634d4 100644
--- a/components/autofill/android/java/res/values/dimens.xml
+++ b/components/autofill/android/java/res/values/dimens.xml
@@ -13,6 +13,8 @@
 
     <dimen name="autofill_dropdown_icon_width">32dp</dimen>
     <dimen name="autofill_dropdown_icon_height">20dp</dimen>
+    <dimen name="autofill_dropdown_icon_width_new">40dp</dimen>
+    <dimen name="autofill_dropdown_icon_height_new">24dp</dimen>
 
     <!-- Preferences dimensions
       pref_autofill_field_horizontal_padding exists because TextInputLayouts have an internal
@@ -42,4 +44,12 @@
     <dimen name="editable_option_section_logo_width">48dp</dimen>
     <dimen name="editable_option_section_logo_horizontal_padding">5dp</dimen>
     <dimen name="editable_option_section_logo_vertical_padding">13dp</dimen>
+
+    <!-- Settings page -->
+    <dimen name="settings_page_card_icon_width">32dp</dimen>
+    <dimen name="settings_page_card_icon_height">20dp</dimen>
+    <dimen name="settings_page_card_icon_width_new">40dp</dimen>
+    <dimen name="settings_page_card_icon_height_new">24dp</dimen>
+    <dimen name="settings_page_card_icon_end_margin">20dp</dimen>
+    <dimen name="settings_page_margin_between_card_name_and_last_four_digits">4dp</dimen>
 </resources>
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc
index a32a16e..bf6f7949 100644
--- a/components/autofill/core/browser/autofill_data_util.cc
+++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -60,24 +60,25 @@
 
 const PaymentRequestData kPaymentRequestDataForNewNetworkImages[]{
     {autofill::kAmericanExpressCard, "amex", IDR_AUTOFILL_METADATA_CC_AMEX,
-     IDR_AUTOFILL_METADATA_CC_AMEX},
+     IDS_AUTOFILL_CC_AMEX},
     {autofill::kDinersCard, "diners", IDR_AUTOFILL_METADATA_CC_DINERS,
-     IDR_AUTOFILL_METADATA_CC_DINERS},
+     IDS_AUTOFILL_CC_DINERS},
     {autofill::kDiscoverCard, "discover", IDR_AUTOFILL_METADATA_CC_DISCOVER,
-     IDR_AUTOFILL_METADATA_CC_DISCOVER},
-    {autofill::kEloCard, "elo", IDR_AUTOFILL_CC_ELO, IDS_AUTOFILL_CC_ELO},
+     IDS_AUTOFILL_CC_DISCOVER},
+    {autofill::kEloCard, "elo", IDR_AUTOFILL_METADATA_CC_ELO,
+     IDS_AUTOFILL_CC_ELO},
     {autofill::kJCBCard, "jcb", IDR_AUTOFILL_METADATA_CC_JCB,
-     IDR_AUTOFILL_METADATA_CC_JCB},
+     IDS_AUTOFILL_CC_JCB},
     {autofill::kMasterCard, "mastercard", IDR_AUTOFILL_METADATA_CC_MASTERCARD,
-     IDR_AUTOFILL_METADATA_CC_MASTERCARD},
+     IDS_AUTOFILL_CC_MASTERCARD},
     {autofill::kMirCard, "mir", IDR_AUTOFILL_METADATA_CC_MIR,
-     IDR_AUTOFILL_METADATA_CC_MIR},
+     IDS_AUTOFILL_CC_MIR},
     {autofill::kTroyCard, "troy", IDR_AUTOFILL_METADATA_CC_TROY,
-     IDR_AUTOFILL_METADATA_CC_TROY},
+     IDS_AUTOFILL_CC_TROY},
     {autofill::kUnionPay, "unionpay", IDR_AUTOFILL_METADATA_CC_UNIONPAY,
-     IDR_AUTOFILL_METADATA_CC_UNIONPAY},
+     IDS_AUTOFILL_CC_UNION_PAY},
     {autofill::kVisaCard, "visa", IDR_AUTOFILL_METADATA_CC_VISA,
-     IDR_AUTOFILL_METADATA_CC_VISA},
+     IDS_AUTOFILL_CC_VISA},
 };
 
 const PaymentRequestData kGenericPaymentRequestData = {
@@ -86,7 +87,7 @@
 
 const PaymentRequestData kGenericPaymentRequestDataForNewNetworkImages = {
     autofill::kGenericCard, "generic", IDR_AUTOFILL_METADATA_CC_GENERIC,
-    IDR_AUTOFILL_METADATA_CC_GENERIC};
+    IDS_AUTOFILL_CC_GENERIC};
 
 const char* const name_prefixes[] = {
     "1lt",     "1st", "2lt", "2nd",    "3rd",  "admiral", "capt",
diff --git a/components/autofill/core/browser/data_model/credit_card.cc b/components/autofill/core/browser/data_model/credit_card.cc
index dd563ec..7a0f77f 100644
--- a/components/autofill/core/browser/data_model/credit_card.cc
+++ b/components/autofill/core/browser/data_model/credit_card.cc
@@ -227,7 +227,8 @@
                                      : IDR_AUTOFILL_CC_DISCOVER;
   }
   if (network == kEloCard)
-    return IDR_AUTOFILL_CC_ELO;
+    return should_show_metadata_icon ? IDR_AUTOFILL_METADATA_CC_ELO
+                                     : IDR_AUTOFILL_CC_ELO;
   if (network == kJCBCard)
     return should_show_metadata_icon ? IDR_AUTOFILL_METADATA_CC_JCB
                                      : IDR_AUTOFILL_CC_JCB;
diff --git a/components/autofill/ios/form_util/resources/fill.js b/components/autofill/ios/form_util/resources/fill.js
index f0e0ac4..454b215 100644
--- a/components/autofill/ios/form_util/resources/fill.js
+++ b/components/autofill/ios/form_util/resources/fill.js
@@ -38,6 +38,11 @@
 let AutofillFormData;
 
 /**
+ * Maps elements using their unique ID
+ */
+const elementMap = new Map();
+
+/**
  * Namespace for this file. It depends on |__gCrWeb| having already been
  * injected. String 'fill' is used in |__gCrWeb['fill']| as it needs to be
  * accessed in Objective-C code.
@@ -694,7 +699,9 @@
       // Sometimes site authors will incorrectly specify the corresponding
       // field element's name rather than its id, so we compensate here.
       const elementName = label.htmlFor;
-      if (!elementName) continue;
+      if (!elementName) {
+        continue;
+      }
       // Look through the list for elements with this name. There can actually
       // be more than one. In this case, the label may not be particularly
       // useful, so just discard it.
@@ -724,7 +731,9 @@
       }
     }
 
-    if (!fieldData) continue;
+    if (!fieldData) {
+      continue;
+    }
 
     if (!('label' in fieldData)) {
       fieldData['label'] = '';
@@ -820,7 +829,9 @@
        i < controlElements.length && fieldIdx < formFields.length; ++i) {
     // This field didn't meet the requirements, so don't try to find a label
     // for it.
-    if (!fieldsExtracted[i]) continue;
+    if (!fieldsExtracted[i]) {
+      continue;
+    }
 
     const controlElement = controlElements[i];
     const currentField = formFields[fieldIdx];
@@ -833,7 +844,9 @@
           currentField['label'].substr(0, __gCrWeb.fill.MAX_DATA_LENGTH);
     }
 
-    if (controlElement === formControlElement) field = formFields[fieldIdx];
+    if (controlElement === formControlElement) {
+      field = formFields[fieldIdx];
+    }
     ++fieldIdx;
   }
 
@@ -2353,6 +2366,10 @@
     if (typeof document[uniqueID] !== 'undefined' &&
         typeof element[uniqueID] === 'undefined') {
       element[uniqueID] = document[uniqueID]++;
+      // TODO(crbug.com/1350973): WeakRef starts in 14.5, remove checks once 14
+      // is deprecated.
+      elementMap.set(
+          element[uniqueID], window.WeakRef ? new WeakRef(element) : element);
     }
   } catch (e) {
   }
@@ -2374,3 +2391,17 @@
     return __gCrWeb.fill.RENDERER_ID_NOT_SET;
   }
 };
+
+/**
+ * @param {int} Unique ID.
+ * @return {Element} element Form or form input element.
+ */
+__gCrWeb.fill.getElementByUniqueID = function(id) {
+  try {
+    // TODO(crbug.com/1350973): WeakRef starts in 14.5, remove checks once 14 is
+    // deprecated.
+    return window.WeakRef ? elementMap.get(id).deref() : elementMap.get(id);
+  } catch (e) {
+    return null;
+  }
+};
diff --git a/components/browsing_data/content/database_helper_browsertest.cc b/components/browsing_data/content/database_helper_browsertest.cc
index bee2811..8950c7f7 100644
--- a/components/browsing_data/content/database_helper_browsertest.cc
+++ b/components/browsing_data/content/database_helper_browsertest.cc
@@ -77,8 +77,7 @@
   }
 };
 
-// Flaky, see https://crbug.com/1293136
-IN_PROC_BROWSER_TEST_F(DatabaseHelperTest, DISABLED_FetchData) {
+IN_PROC_BROWSER_TEST_F(DatabaseHelperTest, FetchData) {
   CreateDatabases();
   auto database_helper = base::MakeRefCounted<DatabaseHelper>(
       shell()->web_contents()->GetPrimaryMainFrame()->GetStoragePartition());
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc
index dd27293..96f576a 100644
--- a/components/feature_engagement/public/feature_configurations.cc
+++ b/components/feature_engagement/public/feature_configurations.cc
@@ -154,9 +154,9 @@
     absl::optional<FeatureConfig> config = FeatureConfig();
     config->valid = true;
     config->availability = Comparator(ANY, 0);
-    config->session_rate = Comparator(ANY, 0);
+    config->session_rate = Comparator(EQUAL, 0);
     config->trigger = EventConfig("battery_saver_info_triggered",
-                                  Comparator(EQUAL, 0), 360, 360);
+                                  Comparator(LESS_THAN, 3), 360, 360);
     config->used =
         EventConfig("battery_saver_info_shown", Comparator(EQUAL, 0), 7, 360);
     return config;
@@ -166,11 +166,11 @@
     absl::optional<FeatureConfig> config = FeatureConfig();
     config->valid = true;
     config->availability = Comparator(ANY, 0);
-    config->session_rate = Comparator(ANY, 0);
-    // Show the promo once a year if the page action chip was not opened
+    config->session_rate = Comparator(EQUAL, 0);
+    // Show the promo up to 3 times if the page action chip was not opened
     // within the last week
     config->trigger = EventConfig("high_efficiency_info_trigger",
-                                  Comparator(EQUAL, 0), 360, 360);
+                                  Comparator(LESS_THAN, 3), 360, 360);
     config->used =
         EventConfig("high_efficiency_info_shown", Comparator(EQUAL, 0), 7, 360);
     return config;
@@ -180,10 +180,10 @@
     absl::optional<FeatureConfig> config = FeatureConfig();
     config->valid = true;
     config->availability = Comparator(ANY, 0);
-    config->session_rate = Comparator(ANY, 0);
-    // Show the promo max 3 times, once per day.
+    config->session_rate = Comparator(EQUAL, 0);
+    // Show the promo max 3 times, once per week.
     config->trigger = EventConfig("high_efficiency_prompt_in_trigger",
-                                  Comparator(LESS_THAN, 1), 1, 360);
+                                  Comparator(LESS_THAN, 1), 7, 360);
     // This event is never logged but is included for consistency.
     config->used = EventConfig("high_efficiency_prompt_in_used",
                                Comparator(EQUAL, 0), 360, 360);
diff --git a/components/history_clusters/core/context_clusterer_history_service_observer.cc b/components/history_clusters/core/context_clusterer_history_service_observer.cc
index ed735f5..c358ac14 100644
--- a/components/history_clusters/core/context_clusterer_history_service_observer.cc
+++ b/components/history_clusters/core/context_clusterer_history_service_observer.cc
@@ -144,17 +144,19 @@
   // Update the normalized URL if it's a search URL.
   std::string normalized_url = url_row.url().possibly_invalid_spec();
   std::u16string search_terms;
+  bool is_search_normalized_url = false;
   if (template_url_service_) {
     absl::optional<TemplateURLService::SearchMetadata> search_metadata =
         template_url_service_->ExtractSearchMetadata(url_row.url());
     if (search_metadata) {
       normalized_url = search_metadata->normalized_url.possibly_invalid_spec();
       search_terms = search_metadata->search_terms;
+      is_search_normalized_url = true;
     }
   }
 
   history::ClusterVisit cluster_visit =
-      CreateClusterVisit(normalized_url, new_visit);
+      CreateClusterVisit(normalized_url, is_search_normalized_url, new_visit);
 
   if (!new_visit.originator_cache_guid.empty()) {
     // Skip determining the exact cluster id for remote synced visits.
@@ -411,12 +413,15 @@
 history::ClusterVisit
 ContextClustererHistoryServiceObserver::CreateClusterVisit(
     const std::string& normalized_url,
+    bool is_search_normalized_url,
     const history::VisitRow& visit_row) {
   history::ClusterVisit cluster_visit;
   cluster_visit.annotated_visit.visit_row.visit_id = visit_row.visit_id;
   cluster_visit.normalized_url = GURL(normalized_url);
   cluster_visit.url_for_deduping =
-      ComputeURLForDeduping(cluster_visit.normalized_url);
+      is_search_normalized_url
+          ? cluster_visit.normalized_url
+          : ComputeURLForDeduping(cluster_visit.normalized_url);
   cluster_visit.url_for_display =
       ComputeURLForDisplay(cluster_visit.normalized_url);
   if (engagement_score_provider_) {
diff --git a/components/history_clusters/core/context_clusterer_history_service_observer.h b/components/history_clusters/core/context_clusterer_history_service_observer.h
index 02c448c9..86c70c4 100644
--- a/components/history_clusters/core/context_clusterer_history_service_observer.h
+++ b/components/history_clusters/core/context_clusterer_history_service_observer.h
@@ -102,6 +102,7 @@
 
   // Creates a cluster visit from `normalized_url` and `visit_row`.
   history::ClusterVisit CreateClusterVisit(const std::string& normalized_url,
+                                           bool is_search_normalized_url,
                                            const history::VisitRow& visit_row);
 
   // Overrides `clock_` for testing.
diff --git a/components/history_clusters/core/context_clusterer_history_service_observer_unittest.cc b/components/history_clusters/core/context_clusterer_history_service_observer_unittest.cc
index cd4b457f..b3cae8e9 100644
--- a/components/history_clusters/core/context_clusterer_history_service_observer_unittest.cc
+++ b/components/history_clusters/core/context_clusterer_history_service_observer_unittest.cc
@@ -518,6 +518,31 @@
       "History.Clusters.ContextClusterer.DbLatency.UpdateClusterVisit", 1);
 }
 
+TEST_F(ContextClustererHistoryServiceObserverTest,
+       SearchNormalizedUrlIsNotAdjusted) {
+  base::HistogramTester histogram_tester;
+
+  SetPersistenceExpectedConfig();
+
+  history::ClusterVisit updated_cluster_visit;
+  EXPECT_CALL(*history_service_,
+              UpdateClusterVisit(_, base::test::IsNotNullCallback(), _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&updated_cluster_visit),
+                Invoke(history_service_.get(),
+                       &MockHistoryService::RunUpdateClusterVisitCallback)));
+
+  VisitURL(GURL("http://default-engine.com/search?q=foo#abc"), 1,
+           base::Time::FromTimeT(123), history::kInvalidVisitID,
+           history::kInvalidVisitID,
+           /*is_synced_visit=*/true);
+
+  EXPECT_EQ(updated_cluster_visit.normalized_url,
+            GURL("http://default-engine.com/search?q=foo"));
+  EXPECT_EQ(updated_cluster_visit.url_for_deduping,
+            GURL("http://default-engine.com/search?q=foo"));
+}
+
 TEST_F(ContextClustererHistoryServiceObserverTest, SkipsBlocklistedHost) {
   base::HistogramTester histogram_tester;
 
diff --git a/components/history_clusters/core/similar_visit.h b/components/history_clusters/core/similar_visit.h
index c54ea13..0bc087d7 100644
--- a/components/history_clusters/core/similar_visit.h
+++ b/components/history_clusters/core/similar_visit.h
@@ -16,7 +16,14 @@
   SimilarVisit() = default;
   explicit SimilarVisit(const history::ClusterVisit& visit)
       : title(visit.annotated_visit.url_row.title()),
-        url_for_deduping(visit.url_for_deduping.spec()) {}
+        // TODO(sophiechang): Remove this duplication once the underlying
+        // persisted change is rolled out in Stable for at least 90 days
+        // (probably around 07/2023).
+        url_for_deduping(visit.annotated_visit.content_annotations
+                                 .search_normalized_url.is_empty()
+                             ? visit.url_for_deduping.spec()
+                             : visit.annotated_visit.content_annotations
+                                   .search_normalized_url.spec()) {}
   SimilarVisit(const SimilarVisit&) = default;
   ~SimilarVisit() = default;
 
diff --git a/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc b/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
index 21cfa19..b1e70b0 100644
--- a/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
+++ b/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
@@ -33,6 +33,41 @@
   base::test::TaskEnvironment task_environment_;
 };
 
+TEST_F(SimilarVisitDeduperClusterFinalizerTest, DedupeBySearchNormalizedUrl) {
+  // canonical_visit has the same URL as Visit1.
+  history::ClusterVisit visit = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/")));
+  visit.annotated_visit.url_row.set_title(u"sametitle");
+  visit.annotated_visit.context_annotations.total_foreground_duration =
+      base::Seconds(20);
+  visit.annotated_visit.content_annotations.search_normalized_url =
+      GURL("https://google.com/search?q=query");
+  visit.url_for_deduping = GURL("https://google.com/shouldbeignored");
+  visit.url_for_display = u"someurl";
+
+  history::ClusterVisit canonical_visit = testing::CreateClusterVisit(
+      testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/#abc")));
+  canonical_visit.annotated_visit.url_row.set_title(u"sametitle");
+  canonical_visit.annotated_visit.content_annotations.search_normalized_url =
+      GURL("https://google.com/search?q=query");
+  canonical_visit.url_for_deduping =
+      GURL("https://google.com/shouldalsobeignored");
+  canonical_visit.url_for_display = u"someurl";
+
+  history::Cluster cluster;
+  cluster.visits = {visit, canonical_visit};
+  FinalizeCluster(cluster);
+  EXPECT_THAT(testing::ToVisitResults({cluster}),
+              ElementsAre(ElementsAre(testing::VisitResult(
+                  2, 1.0, {history::DuplicateClusterVisit{1}}))));
+  const auto& actual_canonical_visit = cluster.visits.at(0);
+  // Make sure total foreground duration is updated correctly even if some don't
+  // have the field populated.
+  EXPECT_EQ(actual_canonical_visit.annotated_visit.context_annotations
+                .total_foreground_duration,
+            base::Seconds(20));
+}
+
 TEST_F(SimilarVisitDeduperClusterFinalizerTest, DedupeExactSimilarVisit) {
   // canonical_visit has the same URL as Visit1.
   history::ClusterVisit visit = testing::CreateClusterVisit(
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index 92dd38d..62e5389 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -2234,7 +2234,7 @@
 
   // TODO(manukh): Remove this histogram when `kRedoCurrentMatch` &
   //   `kRevertModelBeforeClosingPopup` launch or are abandoned.
-  SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Omnibox.OpenMatchTime");
+  SCOPED_UMA_HISTOGRAM_TIMER_MICROS("Omnibox.OmniboxEditModelOpenMatchTime");
 
   // Switch the window disposition to SWITCH_TO_TAB for open tab matches that
   // originated while in keyword mode.  This is to support the keyword mode
diff --git a/components/page_load_metrics/browser/page_load_metrics_util.h b/components/page_load_metrics/browser/page_load_metrics_util.h
index 5a3c0b8..cc7fc81 100644
--- a/components/page_load_metrics/browser/page_load_metrics_util.h
+++ b/components/page_load_metrics/browser/page_load_metrics_util.h
@@ -16,7 +16,12 @@
 // Up to 10 minutes, with 100 buckets.
 #define PAGE_LOAD_HISTOGRAM(name, sample)                          \
   UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, base::Milliseconds(10), \
-                             base::Minutes(10), 100)
+                             base::Minutes(10), 100)               \
+                                                                   \
+// 1 ms to 1 minute, with 100 buckets.
+#define PAGE_LOAD_SHORT_HISTOGRAM(name, sample)                   \
+  UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, base::Milliseconds(1), \
+                             base::Minutes(1), 100)
 
 // Up to 1 hour, with 100 buckets.
 #define PAGE_LOAD_LONG_HISTOGRAM(name, sample)                     \
diff --git a/components/resources/autofill_scaled_resources.grdp b/components/resources/autofill_scaled_resources.grdp
index af729515..fe7bbcd 100644
--- a/components/resources/autofill_scaled_resources.grdp
+++ b/components/resources/autofill_scaled_resources.grdp
@@ -16,6 +16,7 @@
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_AMEX" file="autofill/metadata/amex.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_DINERS" file="autofill/metadata/diners.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_DISCOVER" file="autofill/metadata/discover.png" />
+  <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_ELO" file="autofill/metadata/elo.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_GENERIC" file="autofill/metadata/cc-generic.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_JCB" file="autofill/metadata/jcb.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_METADATA_CC_MASTERCARD" file="autofill/metadata/mastercard.png" />
diff --git a/components/resources/default_100_percent/autofill/metadata/elo.png b/components/resources/default_100_percent/autofill/metadata/elo.png
new file mode 100644
index 0000000..fcd10382
--- /dev/null
+++ b/components/resources/default_100_percent/autofill/metadata/elo.png
Binary files differ
diff --git a/components/resources/default_200_percent/autofill/metadata/elo.png b/components/resources/default_200_percent/autofill/metadata/elo.png
new file mode 100644
index 0000000..6c91137
--- /dev/null
+++ b/components/resources/default_200_percent/autofill/metadata/elo.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/metadata/elo.png b/components/resources/default_300_percent/autofill/metadata/elo.png
new file mode 100644
index 0000000..55f1ad1bf
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/metadata/elo.png
Binary files differ
diff --git a/components/update_client/request_sender.cc b/components/update_client/request_sender.cc
index 90a0475a..ff91d4a 100644
--- a/components/update_client/request_sender.cc
+++ b/components/update_client/request_sender.cc
@@ -125,6 +125,7 @@
     const std::string& response_cup_server_proof,
     int retry_after_sec) {
   VLOG(2) << "Omaha response received: " << response_body;
+  VLOG_IF(2, error) << "Omaha send error: " << error;
 
   if (!error) {
     if (!use_signing_) {
@@ -159,7 +160,6 @@
     return;
   }
 
-  VLOG(2) << "Omaha send error: " << response_body;
   HandleSendError(error, retry_after_sec);
 }
 
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index 8a6112d..1a55ab38 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -79,7 +79,8 @@
     bool has_overlay_support,
     int allowed_yuv_overlay_count,
     int processed_yuv_overlay_count,
-    DisplayResourceProvider* resource_provider) {
+    DisplayResourceProvider* resource_provider,
+    bool is_page_fullscreen_mode) {
   // Note: Do not override this value based on base::Feature values. It is the
   // result after the GPU blocklist has been consulted.
   if (!has_overlay_support)
@@ -104,6 +105,14 @@
     return DC_LAYER_FAILED_COMPLEX_TRANSFORM;
   }
 
+  // TODO(crbug.com/1425907): Remove this restriction after fixing overlay 180
+  // deg rotation in full screen mode in DirectComposition.
+  if (is_page_fullscreen_mode &&
+      !quad->shared_quad_state->quad_to_target_transform
+           .IsPositiveScaleOrTranslation()) {
+    return DC_LAYER_FAILED_COMPLEX_TRANSFORM;
+  }
+
   if (processed_yuv_overlay_count >= allowed_yuv_overlay_count)
     return DC_LAYER_FAILED_TOO_MANY_OVERLAYS;
 
@@ -715,10 +724,11 @@
     DCLayerResult result;
     switch (it->material) {
       case DrawQuad::Material::kYuvVideoContent:
-        result = ValidateYUVQuad(
-            YUVVideoDrawQuad::MaterialCast(*it), backdrop_filter_rects,
-            has_overlay_support_, allowed_yuv_overlay_count_,
-            processed_yuv_overlay_count_, resource_provider);
+        result = ValidateYUVQuad(YUVVideoDrawQuad::MaterialCast(*it),
+                                 backdrop_filter_rects, has_overlay_support_,
+                                 allowed_yuv_overlay_count_,
+                                 processed_yuv_overlay_count_,
+                                 resource_provider, is_page_fullscreen_mode);
         yuv_quads_in_quad_list++;
 
         if (no_undamaged_overlay_promotion_) {
diff --git a/components/viz/service/display/resolved_frame_data.cc b/components/viz/service/display/resolved_frame_data.cc
index e27f4cbe..641c102 100644
--- a/components/viz/service/display/resolved_frame_data.cc
+++ b/components/viz/service/display/resolved_frame_data.cc
@@ -269,6 +269,16 @@
 gfx::Rect ResolvedFrameData::GetSurfaceDamage() const {
   DCHECK(valid_);
 
+  // The |damage_rect| set in |SurfaceAnimationManager| is the |output_rect|.
+  // However, we dont use |damage_rect| because when we transition from
+  // interpolated frame we would end up using the |damage_rect| from the
+  // original non interpolated frame.
+  // TODO(vmpstr): This damage may be too large, but I think it's hard to figure
+  // out a small bounds on the damage given an animation that happens in
+  // SurfaceAnimationManager.
+  if (surface_->HasSurfaceAnimationDamage())
+    return GetOutputRect();
+
   if (IsSameFrameAsLastAggregation()) {
     return gfx::Rect();
   } else if (IsNextFrameSinceLastAggregation()) {
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 1af9f7b5..b69175c 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -407,6 +407,12 @@
     const gfx::Transform& parent_target_transform,
     const Surface* surface,
     size_t* overlay_damage_index) {
+  // If we have damage from a surface animation, then we shouldn't have an
+  // overlay candidate from the root render pass, since that's an interpolated
+  // pass with "artificial" damage.
+  if (surface->HasSurfaceAnimationDamage())
+    return nullptr;
+
   // Only process the damage rect at the root render pass, once per surface.
   const CompositorFrame& frame = surface->GetActiveFrame();
   bool is_last_pass_on_src_surface =
@@ -546,7 +552,8 @@
     // If there is a new CompositorFrame for `surface` compute resolved frame
     // data for the new resolved CompositorFrame.
     if (resolved_frame.previous_frame_index() !=
-        surface->GetActiveFrameIndex()) {
+            surface->GetActiveFrameIndex() ||
+        surface->HasSurfaceAnimationDamage()) {
       base::ElapsedTimer timer;
       ProcessResolvedFrame(resolved_frame);
       stats_->declare_resources_time += timer.Elapsed();
@@ -905,6 +912,7 @@
   }
 
   referenced_surfaces_.erase(surface_id);
+  surface->DidAggregate();
 }
 
 void SurfaceAggregator::EmitDefaultBackgroundColorQuad(
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 134611e..d7f1771 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -615,9 +615,6 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ddl);
 
-  DLOG_IF(WARNING, update_rect.IsEmpty())
-      << "FinishPaintRenderPass called with empty update_rect.";
-
   if (context_is_lost_)
     return;
 
@@ -675,6 +672,10 @@
     overlay_pass_accesses_.emplace(mailbox, std::move(local_scoped_access));
   }
 
+  DLOG_IF(WARNING, update_rect.IsEmpty() && !skia_representation->IsCleared())
+      << "FinishPaintRenderPass called with empty update_rect on an "
+         "uninitialized backing.";
+
   SkSurface* surface = scoped_access->surface();
   DCHECK(surface);
 
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index 54ac755..1e477e96 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -732,10 +732,23 @@
   return active_frame_data_->frame.metadata;
 }
 
+void Surface::ResetInterpolatedFrame() {
+  interpolated_frame_.reset();
+  has_damage_from_interpolated_frame_ = true;
+}
+
 void Surface::SetInterpolatedFrame(CompositorFrame frame) {
   interpolated_frame_.emplace(std::move(frame));
 }
 
+bool Surface::HasSurfaceAnimationDamage() const {
+  return interpolated_frame_.has_value() || has_damage_from_interpolated_frame_;
+}
+
+void Surface::DidAggregate() {
+  has_damage_from_interpolated_frame_ = false;
+}
+
 const CompositorFrame& Surface::GetPendingFrame() {
   DCHECK(pending_frame_data_);
   return pending_frame_data_->frame;
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index d7630fa8..16ed8468 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -202,6 +202,7 @@
   const CompositorFrame& GetActiveFrame() const;
   const CompositorFrameMetadata& GetActiveFrameMetadata() const;
 
+  void ResetInterpolatedFrame();
   void SetInterpolatedFrame(CompositorFrame frame);
   const CompositorFrame& GetActiveOrInterpolatedFrame() const;
   bool HasInterpolatedFrame() const;
@@ -310,6 +311,8 @@
       std::unique_ptr<CopyOutputRequest> copy_request,
       CompositorRenderPassId render_pass_id);
 
+  void DidAggregate();
+
   // Returns frame id of the oldest uncommitted frame if any,
   absl::optional<BeginFrameId> GetFirstUncommitedFrameId();
 
@@ -437,6 +440,8 @@
 
   const raw_ptr<SurfaceAllocationGroup> allocation_group_;
 
+  bool has_damage_from_interpolated_frame_ = false;
+
   const size_t max_uncommitted_frames_;
 
   base::WeakPtrFactory<Surface> weak_factory_{this};
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index a6458f1..4e3ff63c 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -733,7 +733,22 @@
     base::HangWatcher::CreateHangWatcherInstance();
     unregister_thread_closure = base::HangWatcher::RegisterThread(
         base::HangWatcher::ThreadType::kMainThread);
-    base::HangWatcher::GetInstance()->Start();
+    bool start_hang_watcher_now;
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+    // On Linux/ChromeOS, the HangWatcher can't start until after the sandbox is
+    // initialized, because the sandbox can't be started with multiple threads.
+    // TODO(mpdenton): start the HangWatcher after the sandbox is initialized.
+    // Currently there are no sandboxed processes that aren't launched from the
+    // zygote so this doesn't disable the HangWatcher anywhere.
+    start_hang_watcher_now = sandbox::policy::IsUnsandboxedSandboxType(
+        sandbox::policy::SandboxTypeFromCommandLine(
+            *main_function_params.command_line));
+#else
+    start_hang_watcher_now = true;
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+    if (start_hang_watcher_now) {
+      base::HangWatcher::GetInstance()->Start();
+    }
   }
 
   for (size_t i = 0; i < std::size(kMainFunctions); ++i) {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 47a42b7..ee49f7e 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1598,7 +1598,12 @@
     // CHECK() but caused too many crashes, with unknown cause.
     return nil;
   }
-  CHECK(root_manager->GetParentView());
+  if (!root_manager->GetParentView()) {
+    // TODO(crbug.com/1425682) Find out why this happens, there should always be
+    // a parent view. This used to be a CHECK() but caused too many crashes.
+    // Repro steps are available in the bug.
+    return nil;
+  }
   return root_manager->GetWindow();  // Can be null for inactive tabs.
 }
 
diff --git a/content/browser/renderer_host/ipc_utils.cc b/content/browser/renderer_host/ipc_utils.cc
index bc5b3e4..0ce0ea7 100644
--- a/content/browser/renderer_host/ipc_utils.cc
+++ b/content/browser/renderer_host/ipc_utils.cc
@@ -17,7 +17,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/site_instance.h"
 #include "content/public/common/url_constants.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -98,11 +97,10 @@
 
 }  // namespace
 
-bool VerifyDownloadUrlParams(SiteInstance* site_instance,
+bool VerifyDownloadUrlParams(RenderProcessHost* process,
                              const blink::mojom::DownloadURLParams& params) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(site_instance);
-  RenderProcessHost* process = site_instance->GetProcess();
+  CHECK(process);
   int process_id = process->GetID();
 
   // Verifies |params.blob_url_token| is appropriately set.
@@ -184,13 +182,11 @@
 
 bool VerifyBeginNavigationCommonParams(
     const RenderFrameHostImpl& current_rfh,
-    SiteInstance* site_instance,
     blink::LocalFrameToken* initiator_frame_token,
     blink::mojom::CommonNavigationParams* common_params) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(site_instance);
   DCHECK(common_params);
-  RenderProcessHost* process = site_instance->GetProcess();
+  RenderProcessHost* process = current_rfh.GetProcess();
   int process_id = process->GetID();
 
   // Verify (and possibly rewrite) |url|.
diff --git a/content/browser/renderer_host/ipc_utils.h b/content/browser/renderer_host/ipc_utils.h
index 3e742edd3..73b546e 100644
--- a/content/browser/renderer_host/ipc_utils.h
+++ b/content/browser/renderer_host/ipc_utils.h
@@ -14,19 +14,16 @@
 
 namespace content {
 
-class SiteInstance;
 class RenderFrameHostImpl;
 
-// Verifies that |params| are valid and can be accessed by the renderer process
-// associated with |site_instance|.
+// Verifies that |params| are valid and can be accessed by |process|.
 //
 // If the |params| are valid, returns true.
 //
-// Otherwise, terminates the renderer associated with |site_instance| and
-// returns false.
+// Otherwise, terminates |process| and returns false.
 //
 // This function has to be called on the UI thread.
-bool VerifyDownloadUrlParams(SiteInstance* site_instance,
+bool VerifyDownloadUrlParams(RenderProcessHost* process,
                              const blink::mojom::DownloadURLParams& params);
 
 // Verifies that |params| are valid and can be accessed by |process|.
@@ -45,20 +42,19 @@
                          scoped_refptr<network::SharedURLLoaderFactory>*
                              out_blob_url_loader_factory);
 
-// Verifies that CommonNavigationParams are valid and can be accessed by the
-// renderer process associated with |site_instance|.
+// Verifies that CommonNavigationParams are valid and can be accessed by
+// |current_rfh|'s process.
 //
 // Returns true if the CommonNavigationParams are valid.  As a side-effect of
 // the verification parts of |common_params| will be rewritten (e.g. some
 // URLs will be filtered).
 //
-// Terminates the renderer the process associated with |site_instance| and
-// returns false if the CommonNavigationParams are invalid.
+// Terminates |current_rfh|'s process and returns false if the
+// CommonNavigationParams are invalid.
 //
 // This function has to be called on the UI thread.
 bool VerifyBeginNavigationCommonParams(
     const RenderFrameHostImpl& current_rfh,
-    SiteInstance* site_instance,
     blink::LocalFrameToken* initiator_frame_token,
     blink::mojom::CommonNavigationParams* common_params);
 
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index d045964..89bcbe4a 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -39,7 +39,9 @@
 const int kIdScreenReaderHoneyPot = 1;
 
 // static
-LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create(HWND parent) {
+LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create(
+    HWND parent,
+    RenderWidgetHostViewAura* host) {
   // content_unittests passes in the desktop window as the parent. We allow
   // the LegacyRenderWidgetHostHWND instance to be created in this case for
   // these tests to pass.
@@ -49,7 +51,7 @@
     return nullptr;
 
   LegacyRenderWidgetHostHWND* legacy_window_instance =
-      new LegacyRenderWidgetHostHWND();
+      new LegacyRenderWidgetHostHWND(host);
   if (!legacy_window_instance->InitOrDeleteSelf(parent))
     return nullptr;
 
@@ -65,12 +67,7 @@
     ::DestroyWindow(hwnd());
 }
 
-void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
-  if (GetWindowEventTarget(GetParent()))
-    GetWindowEventTarget(GetParent())->HandleParentChanged();
-
-  ::SetParent(hwnd(), parent);
-
+void LegacyRenderWidgetHostHWND::CreateDirectManipulationHelper() {
   // Direct Manipulation is enabled on Windows 10+. The CreateInstance function
   // returns NULL if Direct Manipulation is not available. Recreate
   // |direct_manipulation_helper_| when parent changed (compositor and window
@@ -78,10 +75,38 @@
   direct_manipulation_helper_ = DirectManipulationHelper::CreateInstance(
       hwnd(), host_->GetNativeView()->GetHost()->compositor(),
       GetWindowEventTarget(GetParent()));
+}
 
-  // Reset tooltips when parent changed; otherwise tooltips could stay open as
-  // the former parent wouldn't be forwarded any mouse leave messages.
-  host_->UpdateTooltip(std::u16string());
+void LegacyRenderWidgetHostHWND::UpdateParent(HWND new_parent) {
+  // Performance profiles for resizing show that roughly 1/3 of the
+  // browser main thread CPU samples are inside of the ::SetParent call, even
+  // though the parent is never changed during this operation. The CPU samples
+  // disappear if we ask the OS for the current parent and avoid the SetParent
+  // call altogether.
+  const HWND current_parent = GetParent();
+  if (current_parent != new_parent) {
+    if (GetWindowEventTarget(GetParent())) {
+      GetWindowEventTarget(GetParent())->HandleParentChanged();
+    }
+
+    ::SetParent(hwnd(), new_parent);
+
+    CreateDirectManipulationHelper();
+
+    // Reset tooltips when parent changed; otherwise tooltips could stay open as
+    // the former parent wouldn't be forwarded any mouse leave messages.
+    host_->UpdateTooltip(std::u16string());
+  } else {
+    // The first call to UpdateParent may have the parent correctly set on
+    // account of InitOrDeleteSelf having just created the correctly parented
+    // Window. We will need to create the DirectManipulationHelper in this case
+    // if we haven't already done so. After initial creation, the
+    // DirectManipulationHelper only needs to be re-created if the parent
+    // subsequently changes.
+    if (!direct_manipulation_helper_) {
+      CreateDirectManipulationHelper();
+    }
+  }
 }
 
 HWND LegacyRenderWidgetHostHWND::GetParent() {
@@ -118,9 +143,10 @@
   delete this;
 }
 
-LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND()
+LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(
+    RenderWidgetHostViewAura* host)
     : mouse_tracking_enabled_(false),
-      host_(nullptr),
+      host_(host),
       did_return_uia_object_(false) {}
 
 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
@@ -187,6 +213,8 @@
   // Disable pen flicks (http://crbug.com/506977)
   base::win::DisableFlicks(hwnd());
 
+  host_->UpdateTooltip(std::u16string());
+
   return true;
 }
 
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h
index 11ae0ec6..ede2965c 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.h
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -75,7 +75,8 @@
   // Creates and returns an instance of the LegacyRenderWidgetHostHWND class on
   // successful creation of a child window parented to the parent window passed
   // in.
-  static LegacyRenderWidgetHostHWND* Create(HWND parent);
+  static LegacyRenderWidgetHostHWND* Create(HWND parent,
+                                            RenderWidgetHostViewAura* host);
 
   LegacyRenderWidgetHostHWND(const LegacyRenderWidgetHostHWND&) = delete;
   LegacyRenderWidgetHostHWND& operator=(const LegacyRenderWidgetHostHWND&) =
@@ -128,12 +129,6 @@
   // Resizes the window to the bounds passed in.
   void SetBounds(const gfx::Rect& bounds);
 
-  // The pointer to the containing RenderWidgetHostViewAura instance is passed
-  // here.
-  void set_host(RenderWidgetHostViewAura* host) {
-    host_ = host;
-  }
-
   // Return the root accessible object for either MSAA or UI Automation.
   gfx::NativeViewAccessible GetOrCreateWindowRootAccessible(
       bool is_uia_request);
@@ -145,7 +140,7 @@
   friend class AccessibilityObjectLifetimeWinBrowserTest;
   friend class DirectManipulationBrowserTestBase;
 
-  LegacyRenderWidgetHostHWND();
+  LegacyRenderWidgetHostHWND(RenderWidgetHostViewAura* host);
   ~LegacyRenderWidgetHostHWND() override;
 
   // If initialization fails, deletes `this` and returns false.
@@ -183,6 +178,7 @@
   bool IsAXFragmentRootAControlElement() override;
 
   gfx::NativeViewAccessible GetOrCreateBrowserAccessibilityRoot();
+  void CreateDirectManipulationHelper();
 
   Microsoft::WRL::ComPtr<IAccessible> window_accessible_;
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index e8d27c6..146799a8 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -5684,8 +5684,9 @@
     return;
   }
 
-  if (!VerifyDownloadUrlParams(GetSiteInstance(), *blink_parameters))
+  if (!VerifyDownloadUrlParams(GetProcess(), *blink_parameters)) {
     return;
+  }
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("renderer_initiated_download", R"(
@@ -8351,8 +8352,7 @@
   blink::mojom::CommonNavigationParamsPtr validated_common_params =
       unvalidated_common_params.Clone();
   if (!VerifyBeginNavigationCommonParams(
-          *this, GetSiteInstance(),
-          base::OptionalToPtr(begin_params->initiator_frame_token),
+          *this, base::OptionalToPtr(begin_params->initiator_frame_token),
           &*validated_common_params)) {
     return;
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 7098e7e..bc017ad 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2507,11 +2507,10 @@
 
   if (!legacy_render_widget_host_HWND_) {
     legacy_render_widget_host_HWND_ =
-        LegacyRenderWidgetHostHWND::Create(GetHostWindowHWND());
+        LegacyRenderWidgetHostHWND::Create(GetHostWindowHWND(), this);
   }
 
   if (legacy_render_widget_host_HWND_) {
-    legacy_render_widget_host_HWND_->set_host(this);
     legacy_render_widget_host_HWND_->UpdateParent(GetHostWindowHWND());
     legacy_render_widget_host_HWND_->SetBounds(
         window_->GetBoundsInRootWindow());
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 881a680..619ce49 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -260,8 +260,6 @@
     {wf::EnableMediaCastOverlayButton, raw_ref(media::kMediaCastOverlayButton)},
     {wf::EnableMediaEngagementBypassAutoplayPolicies,
      raw_ref(media::kMediaEngagementBypassAutoplayPolicies)},
-    {wf::EnableMouseSubframeNoImplicitCapture,
-     raw_ref(features::kMouseSubframeNoImplicitCapture)},
     {wf::EnableNotificationContentImage,
      raw_ref(features::kNotificationContentImage), kSetOnlyIfOverridden},
     {wf::EnablePaymentApp, raw_ref(features::kServiceWorkerPaymentApps)},
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 88bfd54..fd151db 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -743,11 +743,6 @@
              "MojoVideoCaptureSecondary",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// When enable, iframe does not implicit capture mouse event.
-BASE_FEATURE(kMouseSubframeNoImplicitCapture,
-             "MouseSubframeNoImplicitCapture",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // When NavigationNetworkResponseQueue is enabled, the browser will schedule
 // some tasks related to navigation network responses in a kHighest priority
 // queue.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 6e29c43..1464625 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -166,7 +166,6 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kMojoDedicatedThread);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kMojoVideoCapture);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kMojoVideoCaptureSecondary);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kMouseSubframeNoImplicitCapture);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kNavigationNetworkResponseQueue);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kNavigationRequestPreconnect);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kNetworkQualityEstimatorWebHoldback);
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java
index e2a7853..63c0151 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/ContentJUnit4ClassRunner.java
@@ -10,6 +10,7 @@
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.SkipCheck;
+import org.chromium.ui.test.util.DeviceRestrictionSkipCheck;
 import org.chromium.ui.test.util.UiDisableIfSkipCheck;
 import org.chromium.ui.test.util.UiRestrictionSkipCheck;
 
@@ -32,6 +33,7 @@
     protected List<SkipCheck> getSkipChecks() {
         return addToList(super.getSkipChecks(),
                 new UiRestrictionSkipCheck(InstrumentationRegistry.getTargetContext()),
+                new DeviceRestrictionSkipCheck(InstrumentationRegistry.getTargetContext()),
                 new UiDisableIfSkipCheck(InstrumentationRegistry.getTargetContext()));
     }
 
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 173041c4..50a4050 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -511,7 +511,6 @@
     "//ios/chrome/browser/ui/tab_switcher/tab_grid:tab_grid_ui",
     "//ios/chrome/browser/ui/tabs",
     "//ios/chrome/browser/ui/toolbar:toolbar_ui",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/webui:webui_internal",
     "//ios/chrome/browser/upgrade",
     "//ios/chrome/browser/url_loading",
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index f1d5d96..99bb3bf 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1677,6 +1677,9 @@
       <message name="IDS_IOS_NTP_FEED_SIGNIN_PROMO_CONTINUE" desc="In Title Case: Button on the new tab page Feed Signin Promo which allow users to signin. [iOS only]">
         Continue
       </message>
+      <message name="IDS_IOS_NTP_FEED_SIGNIN_PROMO_DISABLE_SNACKBAR_MESSAGE" desc="The test shown in the snackbar message when sign-in promo is trigger when sign-in is disabled. [iOS only]">
+        Not available on your device
+      </message>
       <message name="IDS_IOS_NTP_FEED_SIGNIN_PROMO_TITLE" desc="In Title Case: Title   of the new tab page Feed Signin Promo. [iOS only]">
         See Content for You
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_NTP_FEED_SIGNIN_PROMO_DISABLE_SNACKBAR_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_NTP_FEED_SIGNIN_PROMO_DISABLE_SNACKBAR_MESSAGE.png.sha1
new file mode 100644
index 0000000..4283dff
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_NTP_FEED_SIGNIN_PROMO_DISABLE_SNACKBAR_MESSAGE.png.sha1
@@ -0,0 +1 @@
+1fb047469195087ea33fbf7be40ed0738aa22429
\ No newline at end of file
diff --git a/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
new file mode 100644
index 0000000..2156629
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/BUILD.gn
@@ -0,0 +1,35 @@
+# 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.
+
+import("//ios/web/public/js_messaging/optimize_ts.gni")
+
+source_set("bottom_sheet") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "bottom_sheet_java_script_feature.h",
+    "bottom_sheet_java_script_feature.mm",
+    "bottom_sheet_tab_helper.h",
+    "bottom_sheet_tab_helper.mm",
+  ]
+  deps = [
+    ":bottom_sheet_ts",
+    "//base",
+    "//components/autofill/core/common",
+    "//components/autofill/ios/form_util",
+    "//ios/chrome/browser/shared/public/commands",
+    "//ios/web/public",
+    "//ios/web/public:web_state_observer",
+    "//ios/web/public/js_messaging",
+  ]
+}
+
+optimize_ts("bottom_sheet_ts") {
+  visibility = [ ":bottom_sheet" ]
+
+  sources = [ "resources/bottom_sheet.ts" ]
+  deps = [
+    "//ios/web/public/js_messaging:gcrweb",
+    "//ios/web/public/js_messaging:util_scripts",
+  ]
+}
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h
new file mode 100644
index 0000000..92ce0b1
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h
@@ -0,0 +1,41 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_JAVA_SCRIPT_FEATURE_H_
+#define IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_JAVA_SCRIPT_FEATURE_H_
+
+#import "base/no_destructor.h"
+#import "components/autofill/core/common/unique_ids.h"
+#import "ios/web/public/js_messaging/java_script_feature.h"
+
+class BottomSheetJavaScriptFeature : public web::JavaScriptFeature {
+ public:
+  static BottomSheetJavaScriptFeature* GetInstance();
+
+  // This function sends the relevant renderer IDs to the bottom_sheet.ts
+  // script, which will result in attaching listeners for the focus events
+  // on these fields.
+  void AttachListeners(
+      const std::vector<autofill::FieldRendererId>& renderer_ids,
+      web::WebFrame* frame);
+
+  // This function will result in detaching listeners from the username
+  // and password fields, which will prevent the bottom sheet from showing
+  // up until the form reloads. It will also re-trigger a focus event on
+  // the field that had originally triggered the bottom sheet.
+  void DetachListenersAndRefocus(web::WebFrame* frame);
+
+ private:
+  friend class base::NoDestructor<BottomSheetJavaScriptFeature>;
+
+  // web::JavaScriptFeature
+  absl::optional<std::string> GetScriptMessageHandlerName() const override;
+  void ScriptMessageReceived(web::WebState* web_state,
+                             const web::ScriptMessage& message) override;
+
+  BottomSheetJavaScriptFeature();
+  ~BottomSheetJavaScriptFeature() override;
+};
+
+#endif  // IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_JAVA_SCRIPT_FEATURE_H_
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
new file mode 100644
index 0000000..ae021cf9
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.mm
@@ -0,0 +1,70 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h"
+
+#import "base/values.h"
+#import "components/autofill/core/common/password_form_fill_data.h"
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+constexpr char kScriptName[] = "bottom_sheet";
+constexpr char kScriptMessageName[] = "BottomSheetMessage";
+}  // namespace
+
+absl::optional<std::string>
+BottomSheetJavaScriptFeature::GetScriptMessageHandlerName() const {
+  return kScriptMessageName;
+}
+
+void BottomSheetJavaScriptFeature::ScriptMessageReceived(
+    web::WebState* web_state,
+    const web::ScriptMessage& message) {
+  BottomSheetTabHelper* helper = BottomSheetTabHelper::FromWebState(web_state);
+  if (helper) {
+    helper->OnFormMessageReceived(message);
+  }
+}
+
+// static
+BottomSheetJavaScriptFeature* BottomSheetJavaScriptFeature::GetInstance() {
+  static base::NoDestructor<BottomSheetJavaScriptFeature> instance;
+  return instance.get();
+}
+
+BottomSheetJavaScriptFeature::BottomSheetJavaScriptFeature()
+    : web::JavaScriptFeature(
+          // TODO(crbug.com/1175793): Move autofill code to kIsolatedWorld
+          // once all scripts are converted to JavaScriptFeatures.
+          web::ContentWorld::kPageContentWorld,
+          {FeatureScript::CreateWithFilename(
+              kScriptName,
+              FeatureScript::InjectionTime::kDocumentEnd,
+              FeatureScript::TargetFrames::kAllFrames,
+              FeatureScript::ReinjectionBehavior::
+                  kReinjectOnDocumentRecreation)}) {}
+
+BottomSheetJavaScriptFeature::~BottomSheetJavaScriptFeature() = default;
+
+void BottomSheetJavaScriptFeature::AttachListeners(
+    const std::vector<autofill::FieldRendererId>& renderer_ids,
+    web::WebFrame* frame) {
+  base::Value::List renderer_id_list =
+      base::Value::List::with_capacity(renderer_ids.size());
+  for (auto renderer_id : renderer_ids) {
+    renderer_id_list.Append(static_cast<int>(renderer_id.value()));
+  }
+  std::vector<base::Value> parameters;
+  parameters.push_back(base::Value(std::move(renderer_id_list)));
+  CallJavaScriptFunction(frame, "bottomSheet.attachListeners", parameters);
+}
+
+void BottomSheetJavaScriptFeature::DetachListenersAndRefocus(
+    web::WebFrame* frame) {
+  CallJavaScriptFunction(frame, "bottomSheet.detachListenersAndRefocus", {});
+}
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
new file mode 100644
index 0000000..62b462f4
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h
@@ -0,0 +1,55 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
+
+#import "components/autofill/core/common/unique_ids.h"
+#import "ios/web/public/web_state_observer.h"
+#import "ios/web/public/web_state_user_data.h"
+
+namespace web {
+class ScriptMessage;
+}  // namespace web
+
+@class CommandDispatcher;
+@protocol PasswordBottomSheetCommands;
+
+class BottomSheetTabHelper
+    : public web::WebStateObserver,
+      public web::WebStateUserData<BottomSheetTabHelper> {
+ public:
+  BottomSheetTabHelper(const BottomSheetTabHelper&) = delete;
+  BottomSheetTabHelper& operator=(const BottomSheetTabHelper&) = delete;
+
+  ~BottomSheetTabHelper() override;
+
+  // Handler for JavaScript messages. Dispatch to more specific handler.
+  void OnFormMessageReceived(const web::ScriptMessage& message);
+
+  // Sets the CommandDispatcher.
+  void SetPasswordBottomSheetHandler(id<PasswordBottomSheetCommands> handler);
+
+  // Prepare bottom sheet using data from the password form prediction.
+  void AttachListeners(
+      const std::vector<autofill::FieldRendererId>& renderer_ids,
+      web::WebFrame* frame);
+
+  // Detach the listeners, which will deactivate the bottom sheet.
+  void DetachListenersAndRefocus(web::WebFrame* frame);
+
+ private:
+  friend class web::WebStateUserData<BottomSheetTabHelper>;
+
+  explicit BottomSheetTabHelper(web::WebState* web_state);
+
+  // web::WebStateObserver implementation.
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+  id<PasswordBottomSheetCommands> handler_;
+
+  WEB_STATE_USER_DATA_KEY_DECL();
+};
+
+#endif  // IOS_CHROME_BROWSER_AUTOFILL_BOTTOM_SHEET_BOTTOM_SHEET_TAB_HELPER_H_
diff --git a/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
new file mode 100644
index 0000000..65f0ad94
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.mm
@@ -0,0 +1,56 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
+
+#import "components/autofill/ios/form_util/form_activity_params.h"
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h"
+#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
+#import "ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h"
+#import "ios/web/public/js_messaging/script_message.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+BottomSheetTabHelper::~BottomSheetTabHelper() = default;
+
+BottomSheetTabHelper::BottomSheetTabHelper(web::WebState* web_state) {
+  web_state->AddObserver(this);
+}
+
+// Public methods
+
+void BottomSheetTabHelper::SetPasswordBottomSheetHandler(
+    id<PasswordBottomSheetCommands> handler) {
+  handler_ = handler;
+}
+
+void BottomSheetTabHelper::OnFormMessageReceived(
+    const web::ScriptMessage& message) {
+  autofill::FormActivityParams params;
+  if (handler_ && autofill::FormActivityParams::FromMessage(message, &params)) {
+    [handler_ showPasswordBottomSheet:params];
+  }
+}
+
+void BottomSheetTabHelper::AttachListeners(
+    const std::vector<autofill::FieldRendererId>& renderer_ids,
+    web::WebFrame* frame) {
+  BottomSheetJavaScriptFeature::GetInstance()->AttachListeners(renderer_ids,
+                                                               frame);
+}
+
+void BottomSheetTabHelper::DetachListenersAndRefocus(web::WebFrame* frame) {
+  BottomSheetJavaScriptFeature::GetInstance()->DetachListenersAndRefocus(frame);
+}
+
+// WebStateObserver
+
+void BottomSheetTabHelper::WebStateDestroyed(web::WebState* web_state) {
+  web_state->RemoveObserver(this);
+  handler_ = nil;
+}
+
+WEB_STATE_USER_DATA_KEY_IMPL(BottomSheetTabHelper)
diff --git a/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts b/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts
new file mode 100644
index 0000000..64adf61
--- /dev/null
+++ b/ios/chrome/browser/autofill/bottom_sheet/resources/bottom_sheet.ts
@@ -0,0 +1,129 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js';
+import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js';
+
+/**
+ * @fileoverview Adds listeners on the focus event, specifically for elements
+ * provided through a list of renderer IDs, in order for to allow showing a
+ * bottom sheet in that context.
+ */
+
+/**
+ * The last HTML element that was blurred.
+ */
+let lastBlurredElement_: HTMLElement|null;
+
+/**
+ * The list of observed elements.
+ */
+let observedElements_: Element[] = [];
+
+/**
+ * Focus events for observed input elements are messaged to the main
+ * application for broadcast to WebStateObservers.
+ * @private
+ */
+function focusEventHandler_(event: Event): void {
+  if (!event.target || !(event.target instanceof HTMLElement) ||
+      (event.target !== document.activeElement)) {
+    return;
+  }
+
+  // Prevent the keyboard from showing up
+  event.target.blur();
+  lastBlurredElement_ = event.target;
+
+  let field = null;
+  let fieldType = '';
+  let fieldValue = '';
+  let form = null;
+
+  if (event.target instanceof HTMLInputElement) {
+    field = event.target;
+    fieldType = event.target.type;
+    fieldValue = event.target.value;
+    form = event.target.form;
+  } else if (event.target instanceof HTMLFormElement) {
+    form = event.target;
+  }
+
+  // TODO(crbug.com/1427221): convert these "gCrWeb.fill" and "gCrWeb.form"
+  // calls to import and call the functions directly once the conversion to
+  // TypeScript is done.
+  gCrWeb.fill.setUniqueIDIfNeeded(field);
+  gCrWeb.fill.setUniqueIDIfNeeded(form);
+
+  const msg = {
+    'frameID': gCrWeb.message.getFrameId(),
+    'formName': gCrWeb.form.getFormIdentifier(form),
+    'uniqueFormID': gCrWeb.fill.getUniqueID(form),
+    'fieldIdentifier': gCrWeb.form.getFieldIdentifier(field),
+    'uniqueFieldID': gCrWeb.fill.getUniqueID(field),
+    'fieldType': fieldType,
+    'type': event.type,
+    'value': fieldValue,
+    'hasUserGesture': event.isTrusted,
+  };
+  sendWebKitMessage('BottomSheetMessage', msg);
+}
+
+/**
+ * Attach event listeners for relevant elements on the focus event.
+ * @private
+ */
+function attachListeners_(): void {
+  for (const element of observedElements_) {
+    element.addEventListener('focus', focusEventHandler_, true);
+  }
+}
+
+/**
+ * Removes all listeners and clears the list of observed elements
+ * @private
+ */
+function detachListeners_(): void {
+  for (const element of observedElements_) {
+    element.removeEventListener('focus', focusEventHandler_, true);
+  }
+  observedElements_ = [];
+}
+
+/**
+ * Finds the element associated with each provided renderer ID and
+ * attaches a listener to each of these elements for the focus event.
+ */
+function attachListeners(renderer_ids: number[]): void {
+  // Build list of elements
+  for (const renderer_id of renderer_ids) {
+    const element = gCrWeb.fill.getElementByUniqueID(renderer_id);
+    if (element) {
+      observedElements_.push(element);
+    }
+  }
+
+  // Attach the listeners once the IDs are set.
+  attachListeners_();
+}
+
+/**
+ * Removes all previously attached listeners before re-triggering
+ * a focus event on the previously blurred element.
+ */
+function detachListenersAndRefocus(): void {
+  // If the form was dismissed, we don't need to show it anymore on this page,
+  // so remove the event listeners.
+  detachListeners_();
+
+  // Re-focus the previously blurred element
+  if (lastBlurredElement_) {
+    lastBlurredElement_.focus();
+  }
+}
+
+gCrWeb.bottomSheet = {
+  attachListeners,
+  detachListenersAndRefocus
+};
diff --git a/ios/chrome/browser/shared/public/commands/BUILD.gn b/ios/chrome/browser/shared/public/commands/BUILD.gn
index 6f109f0..06277e4f 100644
--- a/ios/chrome/browser/shared/public/commands/BUILD.gn
+++ b/ios/chrome/browser/shared/public/commands/BUILD.gn
@@ -30,6 +30,7 @@
     "open_new_tab_command.h",
     "open_new_tab_command.mm",
     "page_info_commands.h",
+    "password_bottom_sheet_commands.h",
     "password_breach_commands.h",
     "password_protection_commands.h",
     "password_suggestion_commands.h",
diff --git a/ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h b/ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h
new file mode 100644
index 0000000..2782caa3
--- /dev/null
+++ b/ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_PASSWORD_BOTTOM_SHEET_COMMANDS_H_
+#define IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_PASSWORD_BOTTOM_SHEET_COMMANDS_H_
+
+namespace autofill {
+struct FormActivityParams;
+}  // namespace autofill
+
+// Commands related to the passwords bottom sheet.
+@protocol PasswordBottomSheetCommands
+
+// Shows the password suggestion view controller.
+- (void)showPasswordBottomSheet:(const autofill::FormActivityParams&)params;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SHARED_PUBLIC_COMMANDS_PASSWORD_BOTTOM_SHEET_COMMANDS_H_
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 5777a81..afa9a7f 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -59,6 +59,7 @@
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/autofill/bottom_sheet",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/commerce",
     "//ios/chrome/browser/commerce:shopping_service",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index a0bfe903..a0106e6 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -26,6 +26,7 @@
 #import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h"
 #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
 #import "ios/chrome/browser/autofill/autofill_tab_helper.h"
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/commerce/price_alert_util.h"
@@ -149,6 +150,7 @@
       web_state);
   password_manager::WellKnownChangePasswordTabHelper::CreateForWebState(
       web_state);
+  BottomSheetTabHelper::CreateForWebState(web_state);
 
   InvalidUrlTabHelper::CreateForWebState(web_state);
 
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index 03ea511..1673d59 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -49,6 +49,7 @@
     "//ios/chrome/browser/app_launcher",
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/autofill:autofill_internal",
+    "//ios/chrome/browser/autofill/bottom_sheet",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state_metrics",
@@ -196,6 +197,7 @@
     "//ios/chrome/browser/ui/toolbar/fullscreen",
     "//ios/chrome/browser/ui/toolbar/fullscreen:fullscreen_broadcasting_util",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/ui/toolbar_container",
     "//ios/chrome/browser/ui/toolbar_container:feature_flags",
     "//ios/chrome/browser/ui/voice",
@@ -318,7 +320,6 @@
     "//ios/chrome/browser/ui/tabs:coordinator",
     "//ios/chrome/browser/ui/tabs:tabs",
     "//ios/chrome/browser/ui/toolbar",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/test",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/url_loading:new_tab_animation_tab_helper",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 85a5883..474d6c80 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -53,6 +53,7 @@
 #import "ios/chrome/browser/shared/public/commands/load_query_commands.h"
 #import "ios/chrome/browser/shared/public/commands/new_tab_page_commands.h"
 #import "ios/chrome/browser/shared/public/commands/page_info_commands.h"
+#import "ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h"
 #import "ios/chrome/browser/shared/public/commands/password_breach_commands.h"
 #import "ios/chrome/browser/shared/public/commands/password_protection_commands.h"
 #import "ios/chrome/browser/shared/public/commands/password_suggestion_commands.h"
@@ -667,6 +668,7 @@
     @protocol(FindInPageCommands),
     @protocol(NewTabPageCommands),
     @protocol(PageInfoCommands),
+    @protocol(PasswordBottomSheetCommands),
     @protocol(PasswordBreachCommands),
     @protocol(PasswordProtectionCommands),
     @protocol(PasswordSuggestionCommands),
@@ -1378,6 +1380,13 @@
   [self.sharingCoordinator start];
 }
 
+#pragma mark - PasswordBottomSheetCommands
+
+- (void)showPasswordBottomSheet:(const autofill::FormActivityParams&)params {
+  // TODO(crbug.com/1422362): This will be implemented as soon as the
+  // Password Bottom Sheet's coordinator class lands.
+}
+
 #pragma mark - BrowserCoordinatorCommands
 
 - (void)printTabWithBaseViewController:(UIViewController*)baseViewController {
diff --git a/ios/chrome/browser/ui/browser_view/tab_lifecycle_mediator.mm b/ios/chrome/browser/ui/browser_view/tab_lifecycle_mediator.mm
index 800e663e..1ce649d 100644
--- a/ios/chrome/browser/ui/browser_view/tab_lifecycle_mediator.mm
+++ b/ios/chrome/browser/ui/browser_view/tab_lifecycle_mediator.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/browser_view/tab_lifecycle_mediator.h"
 
 #import "ios/chrome/browser/autofill/autofill_tab_helper.h"
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_tab_helper.h"
 #import "ios/chrome/browser/commerce/price_notifications/price_notifications_iph_presenter.h"
 #import "ios/chrome/browser/commerce/price_notifications/price_notifications_tab_helper.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
@@ -17,6 +18,7 @@
 #import "ios/chrome/browser/passwords/password_tab_helper.h"
 #import "ios/chrome/browser/prerender/prerender_service.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
+#import "ios/chrome/browser/shared/public/commands/password_bottom_sheet_commands.h"
 #import "ios/chrome/browser/shared/public/commands/web_content_commands.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_tab_helper.h"
@@ -85,6 +87,11 @@
   passwordTabHelper->SetPasswordControllerDelegate(_delegate);
   passwordTabHelper->SetDispatcher(_commandDispatcher);
 
+  BottomSheetTabHelper* bottomSheetTabHelper =
+      BottomSheetTabHelper::FromWebState(webState);
+  bottomSheetTabHelper->SetPasswordBottomSheetHandler(
+      HandlerForProtocol(_commandDispatcher, PasswordBottomSheetCommands));
+
   DCHECK(_delegate);
   OverscrollActionsTabHelper::FromWebState(webState)->SetDelegate(_delegate);
 
@@ -158,6 +165,10 @@
   passwordTabHelper->SetPasswordControllerDelegate(nil);
   passwordTabHelper->SetDispatcher(nil);
 
+  BottomSheetTabHelper* bottomSheetTabHelper =
+      BottomSheetTabHelper::FromWebState(webState);
+  bottomSheetTabHelper->SetPasswordBottomSheetHandler(nil);
+
   OverscrollActionsTabHelper::FromWebState(webState)->SetDelegate(nil);
 
   webState->SetSwipeRecognizerProvider(nil);
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index 679923f..d85aac8 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -106,7 +106,6 @@
     "//ios/chrome/browser/ui/sharing",
     "//ios/chrome/browser/ui/start_surface",
     "//ios/chrome/browser/ui/start_surface:feature_flags",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/whats_new:util",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/url_loading",
@@ -202,6 +201,7 @@
     "//ios/chrome/browser/ui/start_surface:feature_flags",
     "//ios/chrome/browser/ui/toolbar/buttons",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/url_loading:url_loading_params_header",
     "//ios/chrome/common:button_config",
diff --git a/ios/chrome/browser/ui/find_bar/BUILD.gn b/ios/chrome/browser/ui/find_bar/BUILD.gn
index 4bf4252..fa93ff40 100644
--- a/ios/chrome/browser/ui/find_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/find_bar/BUILD.gn
@@ -37,7 +37,6 @@
     "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/resources:menu_shadow",
     "//ios/chrome/browser/ui/toolbar/accessory",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
index d05c7c1..7c9eca1 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
+++ b/ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/ui/find_bar/find_bar_view.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_view_controller.h"
 #import "ios/chrome/browser/ui/image_util/image_util.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ui/base/l10n/l10n_util_mac.h"
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_view.mm b/ios/chrome/browser/ui/find_bar/find_bar_view.mm
index c633478..3e1be2c 100644
--- a/ios/chrome/browser/ui/find_bar/find_bar_view.mm
+++ b/ios/chrome/browser/ui/find_bar/find_bar_view.mm
@@ -7,7 +7,6 @@
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_constants.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/common/ui/util/dynamic_type_util.h"
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 4e210267..7029665 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -74,7 +74,6 @@
     "//ios/chrome/browser/ui/omnibox/popup",
     "//ios/chrome/browser/ui/orchestrator:orchestrator",
     "//ios/chrome/browser/ui/toolbar/buttons",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
index d60e328..8e2f720 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
@@ -12,7 +12,6 @@
 #import "ios/chrome/browser/ui/elements/extended_touch_target_button.h"
 #import "ios/chrome/browser/ui/icons/symbols.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_constants.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index 97d4607..fa3245f6 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -220,7 +220,6 @@
     "//ios/chrome/browser/ui/start_surface:feature_flags",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid",
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/whats_new:util",
     "//ios/chrome/browser/ui/whats_new/promo",
     "//ios/chrome/browser/url",
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 51797cc..f62046f 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -88,6 +88,7 @@
     ":ntp",
     ":ntp_internal",
     "//components/feed/core/v2/public/ios:feed_ios_public",
+    "//components/policy:policy_code_generate",
     "//components/pref_registry",
     "//components/prefs",
     "//components/prefs/ios",
diff --git a/ios/chrome/browser/ui/ntp/feed_promos/BUILD.gn b/ios/chrome/browser/ui/ntp/feed_promos/BUILD.gn
index 7ae714d2..5ccd8134 100644
--- a/ios/chrome/browser/ui/ntp/feed_promos/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/feed_promos/BUILD.gn
@@ -17,7 +17,6 @@
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/shared/public/features",
-    "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/ntp/metrics",
     "//ios/chrome/common/ui/confirmation_alert",
   ]
diff --git a/ios/chrome/browser/ui/ntp/feed_promos/feed_sign_in_promo_coordinator.mm b/ios/chrome/browser/ui/ntp/feed_promos/feed_sign_in_promo_coordinator.mm
index c46b184e..aba4e61b 100644
--- a/ios/chrome/browser/ui/ntp/feed_promos/feed_sign_in_promo_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/feed_promos/feed_sign_in_promo_coordinator.mm
@@ -13,8 +13,6 @@
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/show_signin_command.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
-#import "ios/chrome/browser/signin/chrome_account_manager_service.h"
-#import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/ui/ntp/feed_promos/feed_sign_in_promo_view_controller.h"
 #import "ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.h"
 #import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h"
@@ -48,61 +46,40 @@
 - (void)start {
   DCHECK(IsFeedCardMenuSignInPromoEnabled());
 
-  self.feedMetricsRecorder = DiscoverFeedServiceFactory::GetForBrowserState(
-                                 self.browser->GetBrowserState())
-                                 ->GetFeedMetricsRecorder();
+  FeedSignInPromoViewController* signInPromoViewController =
+      [[FeedSignInPromoViewController alloc] init];
 
-  ChromeAccountManagerService* accountManagerService =
-      ChromeAccountManagerServiceFactory::GetForBrowserState(
-          self.browser->GetBrowserState());
+  signInPromoViewController.actionHandler = self;
 
-  BOOL hasUserIdentities = accountManagerService->HasIdentities();
-
-  // Launch the Sign-In only flow, since Sync is not needed for this feature.
-  // TODO(crbug.com/1382615): Currently we show sign-in only UI when it's
-  // enabled, or when the user has one or more device-level user identities.
-  // Remove else block and the user identity check when sign-in only UI is fully
-  // launched.
-  if (IsConsistencyNewAccountInterfaceEnabled() || hasUserIdentities) {
-    [self showSignInFlowWithSignInOnly:YES];
-    [self.feedMetricsRecorder
-        recordShowSignInOnlyUIWithUserId:hasUserIdentities];
+  if (@available(iOS 15, *)) {
+    signInPromoViewController.modalPresentationStyle =
+        UIModalPresentationPageSheet;
+    UISheetPresentationController* presentationController =
+        signInPromoViewController.sheetPresentationController;
+    presentationController.prefersEdgeAttachedInCompactHeight = YES;
+    presentationController.widthFollowsPreferredContentSizeWhenEdgeAttached =
+        YES;
+    presentationController.detents = @[
+      UISheetPresentationControllerDetent.mediumDetent,
+      UISheetPresentationControllerDetent.largeDetent
+    ];
+    presentationController.preferredCornerRadius = kHalfSheetCornerRadius;
   } else {
-    FeedSignInPromoViewController* signInPromoViewController =
-        [[FeedSignInPromoViewController alloc] init];
-
-    signInPromoViewController.actionHandler = self;
-
-    if (@available(iOS 15, *)) {
-      signInPromoViewController.modalPresentationStyle =
-          UIModalPresentationPageSheet;
-      UISheetPresentationController* presentationController =
-          signInPromoViewController.sheetPresentationController;
-      presentationController.prefersEdgeAttachedInCompactHeight = YES;
-      presentationController.widthFollowsPreferredContentSizeWhenEdgeAttached =
-          YES;
-      presentationController.detents = @[
-        UISheetPresentationControllerDetent.mediumDetent,
-        UISheetPresentationControllerDetent.largeDetent
-      ];
-      presentationController.preferredCornerRadius = kHalfSheetCornerRadius;
-    } else {
-      signInPromoViewController.modalPresentationStyle =
-          UIModalPresentationFormSheet;
-    }
-
-    [self.baseViewController
-        presentViewController:signInPromoViewController
-                     animated:YES
-                   completion:^() {
-                     const signin_metrics::AccessPoint access_point =
-                         signin_metrics::AccessPoint::
-                             ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO;
-                     signin_metrics::
-                         RecordSigninImpressionUserActionForAccessPoint(
-                             access_point);
-                   }];
+    signInPromoViewController.modalPresentationStyle =
+        UIModalPresentationFormSheet;
   }
+
+  [self.baseViewController
+      presentViewController:signInPromoViewController
+                   animated:YES
+                 completion:^() {
+                   const signin_metrics::AccessPoint access_point =
+                       signin_metrics::AccessPoint::
+                           ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO;
+                   signin_metrics::
+                       RecordSigninImpressionUserActionForAccessPoint(
+                           access_point);
+                 }];
 }
 
 - (void)stop {
@@ -117,11 +94,10 @@
   [self.feedMetricsRecorder recordSignInPromoUIContinueTapped];
   if (self.baseViewController.presentedViewController) {
     __weak __typeof(self) weakSelf = self;
-    [self.baseViewController
-        dismissViewControllerAnimated:YES
-                           completion:^{
-                             [weakSelf showSignInFlowWithSignInOnly:NO];
-                           }];
+    [self.baseViewController dismissViewControllerAnimated:YES
+                                                completion:^{
+                                                  [weakSelf showSyncFlow];
+                                                }];
   }
 }
 
@@ -132,14 +108,13 @@
 
 #pragma mark - Helpers
 
-- (void)showSignInFlowWithSignInOnly:(BOOL)signInOnly {
+- (void)showSyncFlow {
   const signin_metrics::AccessPoint access_point =
       signin_metrics::AccessPoint::ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO;
   id<ApplicationCommands> handler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), ApplicationCommands);
   ShowSigninCommand* command = [[ShowSigninCommand alloc]
-      initWithOperation:signInOnly ? AuthenticationOperationSigninOnly
-                                   : AuthenticationOperationSigninAndSync
+      initWithOperation:AuthenticationOperationSigninAndSync
             accessPoint:access_point];
   signin_metrics::RecordSigninUserActionForAccessPoint(access_point);
   [handler showSignin:command baseViewController:self.baseViewController];
diff --git a/ios/chrome/browser/ui/ntp/feed_sign_in_promo_delegate.h b/ios/chrome/browser/ui/ntp/feed_sign_in_promo_delegate.h
index 611a350..5bd9eb3 100644
--- a/ios/chrome/browser/ui/ntp/feed_sign_in_promo_delegate.h
+++ b/ios/chrome/browser/ui/ntp/feed_sign_in_promo_delegate.h
@@ -8,10 +8,15 @@
 // Protocol for actions relating to the feed sign-in promo.
 @protocol FeedSignInPromoDelegate
 
-// Shows a sign in promote UI.
+// Shows a sign in promote UI for feed back of card sign-in promo.
+// TODO(crbug.com/1382615): rename it as "showHalfSheetForFeedBoCSignInPromo"
+// since it's not a promo UI but a message to let the user to continue to sign
+// in.
 - (void)showSignInPromoUI;
 
-// Shows a sign in flow.
+// Shows a sign in UI for feed bottom sign-in promo.
+// TODO(crbug.com/1382615): rename it as "showSyncPromoUI" since it shows a sync
+// flow.
 - (void)showSignInUI;
 
 @end
diff --git a/ios/chrome/browser/ui/ntp/incognito/BUILD.gn b/ios/chrome/browser/ui/ntp/incognito/BUILD.gn
index 0dbfb5b..553f7575 100644
--- a/ios/chrome/browser/ui/ntp/incognito/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/incognito/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/ui/ntp:constants",
     "//ios/chrome/browser/ui/ntp:ntp_internal",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/common:string_util",
     "//ios/chrome/common/ui/colors",
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
index 54e0c5ef..b81010d2 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -87,9 +87,6 @@
 // YES if the NTP is visible.
 @property(nonatomic, assign) BOOL isNTPVisible;
 
-// YES if the feed is toggled on in the feed header menu.
-@property(nonatomic, assign) BOOL isFeedVisible;
-
 @end
 
 @implementation FeedMetricsRecorder
@@ -304,7 +301,6 @@
 }
 
 - (void)recordDiscoverFeedVisibilityChanged:(BOOL)visible {
-  self.isFeedVisible = visible;
   if (visible) {
     [self
         recordDiscoverFeedUserActionHistogram:FeedUserActionType::kTappedTurnOn
@@ -647,7 +643,8 @@
 #pragma mark - FeedRefreshStateTracker
 
 - (BOOL)isNTPAndFeedVisible {
-  return self.isNTPVisible && self.isFeedVisible;
+  // This method is deprecated and usage is replaced with `isNTPVisible`.
+  return self.isNTPVisible;
 }
 
 #pragma mark - Follow
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_refresh_state_tracker.h b/ios/chrome/browser/ui/ntp/metrics/feed_refresh_state_tracker.h
index 17ae98b..e03016b 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_refresh_state_tracker.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_refresh_state_tracker.h
@@ -16,8 +16,12 @@
 
 // Returns YES if the NTP and feed is visible to the user. Returns NO if the NTP
 // is not visible or if the feed is toggled off in the feed header menu.
+// Deprecated.
 - (BOOL)isNTPAndFeedVisible;
 
+// Returns YES if the NTP is visible to the user.
+- (BOOL)isNTPVisible;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_METRICS_FEED_REFRESH_STATE_TRACKER_H_
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 694ea4c..2572ccd6 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h"
 
+#import <MaterialComponents/MaterialSnackbar.h>
+
 #import "base/feature_list.h"
 #import "base/metrics/field_trial_params.h"
 #import "base/metrics/histogram_functions.h"
@@ -12,6 +14,7 @@
 #import "base/metrics/user_metrics_action.h"
 #import "base/time/time.h"
 #import "components/feed/core/v2/public/ios/pref_names.h"
+#import "components/policy/policy_constants.h"
 #import "components/pref_registry/pref_registry_syncable.h"
 #import "components/prefs/ios/pref_observer_bridge.h"
 #import "components/prefs/pref_change_registrar.h"
@@ -1023,15 +1026,60 @@
 #pragma mark - FeedSignInPromoDelegate
 
 - (void)showSignInPromoUI {
-  // Show a sign-in promo half sheet.
-  self.feedSignInPromoCoordinator = [[FeedSignInPromoCoordinator alloc]
-      initWithBaseViewController:self.NTPViewController
-                         browser:self.browser];
-  [self.feedSignInPromoCoordinator start];
+  ChromeAccountManagerService* accountManagerService =
+      ChromeAccountManagerServiceFactory::GetForBrowserState(
+          self.browser->GetBrowserState());
+
+  BOOL hasUserIdentities = accountManagerService->HasIdentities();
+
+  if ([self isSignInAllowed] &&
+      (IsConsistencyNewAccountInterfaceEnabled() || hasUserIdentities)) {
+    // Show Sign-In only flow, since Sync is not needed for this feature.
+    // TODO(crbug.com/1382615): Currently we show sign-in only UI when it's
+    // enabled, or when the user has one or more device-level user identities,
+    // and when sign-in is allowed. Remove the user identity check when sign-in
+    // only flow is fully launched.
+    const signin_metrics::AccessPoint access_point =
+        signin_metrics::AccessPoint::ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO;
+    id<ApplicationCommands> handler = HandlerForProtocol(
+        self.browser->GetCommandDispatcher(), ApplicationCommands);
+    ShowSigninCommand* command = [[ShowSigninCommand alloc]
+        initWithOperation:AuthenticationOperationSigninOnly
+              accessPoint:access_point];
+    signin_metrics::RecordSigninUserActionForAccessPoint(access_point);
+    [handler showSignin:command baseViewController:self.NTPViewController];
+    [self.feedMetricsRecorder
+        recordShowSignInOnlyUIWithUserId:hasUserIdentities];
+  } else if ([self isSignInAllowed] && [self isSyncAllowed]) {
+    // Show a sign-in promo half sheet for feed BoC sign-in promo when the
+    // condition of showing sign-in only flow is not fulfilled. This UI will
+    // lead to sync flow,
+    // TODO(crbug.com/1382615): remove this else if block and
+    // FeedSignInPromoCoordinator class when sign-in only flow is fully
+    // launched.
+    self.feedSignInPromoCoordinator = [[FeedSignInPromoCoordinator alloc]
+        initWithBaseViewController:self.NTPViewController
+                           browser:self.browser];
+    [self.feedSignInPromoCoordinator start];
+  } else {
+    // Show a snackbar message if sign-in or sync is disabled and the above UI
+    // shouldn't be shown.
+    // TODO(crbug.com/1382615): remove when able to hide the personalization
+    // control when sign-in or sync is disabled.
+    [self showSignInDisableMessage];
+  }
 }
 
 - (void)showSignInUI {
-  // Show sign-in and sync page.
+  // Show a snackbar message if sign-in or sync is disabled.
+  // TODO(crbug.com/1382615): remove when able to hide the  personalization
+  // control when sign-in or sync is disabled.
+  if (![self isSignInAllowed] || ![self isSyncAllowed]) {
+    [self showSignInDisableMessage];
+    return;
+  }
+
+  // Show sign-in and sync page for feed bottom sync promo.
   const signin_metrics::AccessPoint access_point =
       signin_metrics::AccessPoint::ACCESS_POINT_NTP_FEED_BOTTOM_PROMO;
   id<ApplicationCommands> handler = HandlerForProtocol(
@@ -1663,6 +1711,43 @@
   [self updateVisible];
 }
 
+- (BOOL)isSignInAllowed {
+  AuthenticationService::ServiceStatus statusService =
+      self.authService->GetServiceStatus();
+  switch (statusService) {
+    case AuthenticationService::ServiceStatus::SigninDisabledByPolicy:
+    case AuthenticationService::ServiceStatus::SigninDisabledByInternal:
+    case AuthenticationService::ServiceStatus::SigninDisabledByUser: {
+      return NO;
+    }
+    case AuthenticationService::ServiceStatus::SigninForcedByPolicy:
+    case AuthenticationService::ServiceStatus::SigninAllowed: {
+      break;
+    }
+  }
+  return YES;
+}
+
+- (BOOL)isSyncAllowed {
+  if (self.prefService->FindPreference(policy::key::kSyncDisabled) &&
+      self.prefService->GetBoolean(policy::key::kSyncDisabled)) {
+    return NO;
+  }
+
+  return YES;
+}
+
+- (void)showSignInDisableMessage {
+  id<SnackbarCommands> handler =
+      static_cast<id<SnackbarCommands>>(self.browser->GetCommandDispatcher());
+  MDCSnackbarMessage* message = [MDCSnackbarMessage
+      messageWithText:
+          l10n_util::GetNSString(
+              IDS_IOS_NTP_FEED_SIGNIN_PROMO_DISABLE_SNACKBAR_MESSAGE)];
+
+  [handler showSnackbarMessage:message];
+}
+
 #pragma mark - Getters
 
 - (FeedHeaderViewController*)feedHeaderViewController {
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index 0a6a16b..728f71df 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -181,7 +181,7 @@
     "//ios/chrome/browser/ui/omnibox/popup",
     "//ios/chrome/browser/ui/omnibox/popup:popup_ui_protocols",
     "//ios/chrome/browser/ui/orchestrator:orchestrator",
-    "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/common",
diff --git a/ios/chrome/browser/ui/omnibox/keyboard_assist/BUILD.gn b/ios/chrome/browser/ui/omnibox/keyboard_assist/BUILD.gn
index 0338c8c2..d27c736ee 100644
--- a/ios/chrome/browser/ui/omnibox/keyboard_assist/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/keyboard_assist/BUILD.gn
@@ -38,7 +38,6 @@
     "//ios/chrome/browser/ui/location_bar:constants",
     "//ios/chrome/browser/ui/omnibox:features",
     "//ios/chrome/browser/ui/omnibox:omnibox_internal",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/voice",
     "//ios/chrome/common:button_config",
     "//ios/chrome/common/ui/colors",
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
index e2ac1a0..419aead 100644
--- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -103,7 +103,7 @@
     "//ios/chrome/browser/ui/omnibox/resources:pedal_settings",
     "//ios/chrome/browser/ui/sharing",
     "//ios/chrome/browser/ui/toolbar/buttons",
-    "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/common/ui/colors",
@@ -180,7 +180,6 @@
     "//ios/chrome/browser/ui/omnibox:omnibox_suggestion_icon_util",
     "//ios/chrome/browser/ui/omnibox:omnibox_util",
     "//ios/chrome/browser/ui/toolbar/buttons",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/elements:elements",
     "//ios/chrome/common/ui/favicon",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
index 18729c3..02612b0 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
@@ -19,7 +19,6 @@
 #import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.h"
 #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_suggestion.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_icon_view.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/elements/gradient_view.h"
 #import "ios/chrome/common/ui/util/pointer_interaction_util.h"
diff --git a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
index b3b4aa6..c9995650 100644
--- a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
+++ b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
@@ -24,7 +24,6 @@
     "//ios/chrome/browser/ui/ntp:logo",
     "//ios/chrome/browser/ui/page_info:constants",
     "//ios/chrome/browser/ui/side_swipe",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/common/ui/colors",
     "//ios/public/provider/chrome/browser/fullscreen:fullscreen_api",
diff --git a/ios/chrome/browser/ui/qr_scanner/BUILD.gn b/ios/chrome/browser/ui/qr_scanner/BUILD.gn
index 8c24cc66..ce1fd8e 100644
--- a/ios/chrome/browser/ui/qr_scanner/BUILD.gn
+++ b/ios/chrome/browser/ui/qr_scanner/BUILD.gn
@@ -46,7 +46,6 @@
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/ui/scanner",
-    "//ios/chrome/browser/ui/toolbar/public",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/side_swipe/BUILD.gn b/ios/chrome/browser/ui/side_swipe/BUILD.gn
index 2ebfbe2..a339d96 100644
--- a/ios/chrome/browser/ui/side_swipe/BUILD.gn
+++ b/ios/chrome/browser/ui/side_swipe/BUILD.gn
@@ -36,6 +36,7 @@
     "//ios/chrome/browser/ui/tab_switcher/tab_grid/grid:grid_ui_constants",
     "//ios/chrome/browser/ui/tabs/requirements",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/url",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/ui/text_zoom/BUILD.gn b/ios/chrome/browser/ui/text_zoom/BUILD.gn
index 566446f0..c810c74f 100644
--- a/ios/chrome/browser/ui/text_zoom/BUILD.gn
+++ b/ios/chrome/browser/ui/text_zoom/BUILD.gn
@@ -17,7 +17,6 @@
     "//ios/chrome/browser/shared/public/commands",
     "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/toolbar/accessory",
-    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web/font_size",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/ui/text_zoom/text_zoom_coordinator.mm b/ios/chrome/browser/ui/text_zoom/text_zoom_coordinator.mm
index 06375e179..ad995df 100644
--- a/ios/chrome/browser/ui/text_zoom/text_zoom_coordinator.mm
+++ b/ios/chrome/browser/ui/text_zoom/text_zoom_coordinator.mm
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/ui/text_zoom/text_zoom_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/accessory/toolbar_accessory_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/accessory/toolbar_accessory_presenter.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
 #import "ios/chrome/browser/web/font_size/font_size_tab_helper.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index b108472..4e81cb22 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -123,6 +123,7 @@
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
     "//ios/chrome/browser/ui/toolbar/buttons",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/ui/toolbar_container:toolbar_collapsing",
     "//ios/chrome/common:timing",
     "//ios/chrome/common/ui/colors",
@@ -164,7 +165,6 @@
     "//ios/chrome/browser/ui/menu",
     "//ios/chrome/browser/ui/popup_menu/public",
     "//ios/chrome/browser/ui/toolbar/buttons",
-    "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/test",
     "//ios/chrome/browser/url:constants",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/ui/toolbar/buttons/BUILD.gn b/ios/chrome/browser/ui/toolbar/buttons/BUILD.gn
index 734d1eb..a6ac25f 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/buttons/BUILD.gn
@@ -35,7 +35,7 @@
     "//ios/chrome/browser/shared/ui/util:util_swift",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant",
     "//ios/chrome/browser/ui/icons:symbols",
-    "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common:button_config",
diff --git a/ios/chrome/browser/ui/toolbar/public/BUILD.gn b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
index 395d78a..2b4b9e8b 100644
--- a/ios/chrome/browser/ui/toolbar/public/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
@@ -13,6 +13,7 @@
     "toolbar_utils.mm",
   ]
   deps = [
+    ":constants",
     "//base",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/ui/bubble",
@@ -21,7 +22,6 @@
     "//ios/chrome/common/ui/util",
     "//ios/components/ui_util",
   ]
-  public_deps = [ ":constants" ]
 }
 
 source_set("constants") {
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index 12e2f17..4648a6f 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -253,6 +253,7 @@
     "//ios/chrome/app/resources:ios_resources",
     "//ios/chrome/browser/application_context",
     "//ios/chrome/browser/application_context:application_context_impl",
+    "//ios/chrome/browser/autofill/bottom_sheet",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:browser_state_impl",
     "//ios/chrome/browser/content_settings",
diff --git a/ios/chrome/browser/web/chrome_main_parts.mm b/ios/chrome/browser/web/chrome_main_parts.mm
index b3aecc6..f1f901a 100644
--- a/ios/chrome/browser/web/chrome_main_parts.mm
+++ b/ios/chrome/browser/web/chrome_main_parts.mm
@@ -19,6 +19,7 @@
 #import "base/task/single_thread_task_runner.h"
 #import "base/task/thread_pool.h"
 #import "base/time/default_tick_clock.h"
+#import "build/blink_buildflags.h"
 #import "components/content_settings/core/browser/cookie_settings.h"
 #import "components/content_settings/core/common/content_settings_pattern.h"
 #import "components/crash/core/common/crash_key.h"
@@ -384,8 +385,11 @@
   base::SetRecordActionTaskRunner(web::GetUIThreadTaskRunner({}));
 
   // FeatureList requires VariationsIdsProvider to be created.
+#if !BUILDFLAG(USE_BLINK)
+  // TODO(crbug.com/1427308) Move variations to PostEarlyInitialization.
   variations::VariationsIdsProvider::Create(
       variations::VariationsIdsProvider::Mode::kUseSignedInState);
+#endif
 
   // Initialize FieldTrialList to support FieldTrials that use one-time
   // randomization.
@@ -400,10 +404,13 @@
   std::vector<std::string> variation_ids =
       RegisterAllFeatureVariationParameters(&flags_storage, feature_list.get());
 
+#if !BUILDFLAG(USE_BLINK)
+  // TODO(crbug.com/1427308) Move variations to PostEarlyInitialization.
   application_context_->GetVariationsService()->SetUpFieldTrials(
       variation_ids, command_line_variation_ids,
       std::vector<base::FeatureList::FeatureOverrideInfo>(),
       std::move(feature_list), &ios_field_trials_);
+#endif
 }
 
 void IOSChromeMainParts::SetupMetrics() {
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index be84efd..15d8bcc7 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -26,6 +26,7 @@
 #import "components/translate/ios/browser/translate_java_script_feature.h"
 #import "components/version_info/version_info.h"
 #import "ios/chrome/browser/application_context/application_context.h"
+#import "ios/chrome/browser/autofill/bottom_sheet/bottom_sheet_java_script_feature.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/flags/chrome_switches.h"
 #import "ios/chrome/browser/follow/follow_java_script_feature.h"
@@ -302,6 +303,7 @@
   features.push_back(autofill::FormHandlersJavaScriptFeature::GetInstance());
   features.push_back(
       autofill::SuggestionControllerJavaScriptFeature::GetInstance());
+  features.push_back(BottomSheetJavaScriptFeature::GetInstance());
   features.push_back(FontSizeJavaScriptFeature::GetInstance());
   features.push_back(ImageFetchJavaScriptFeature::GetInstance());
   features.push_back(
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 5681954..2bb4ad4 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -178,7 +178,7 @@
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
     "//ios/chrome/browser/ui/toolbar:eg_app_support+eg2",
     "//ios/chrome/browser/ui/toolbar:toolbar_ui",
-    "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:constants",
     "//ios/chrome/browser/unified_consent",
     "//ios/chrome/browser/variations:eg_app_support+eg2",
     "//ios/chrome/browser/web",
diff --git a/ios/web/content/BUILD.gn b/ios/web/content/BUILD.gn
index f4d5424..7509021 100644
--- a/ios/web/content/BUILD.gn
+++ b/ios/web/content/BUILD.gn
@@ -11,6 +11,8 @@
   sources = [
     "content_browser_context.h",
     "content_browser_context.mm",
+    "content_thread_impl.cc",
+    "content_thread_impl.h",
     "js_messaging/content_web_frame.h",
     "js_messaging/content_web_frame.mm",
     "js_messaging/content_web_frames_manager.h",
diff --git a/ios/web/content/content_thread_impl.cc b/ios/web/content/content_thread_impl.cc
new file mode 100644
index 0000000..fb23eeb
--- /dev/null
+++ b/ios/web/content/content_thread_impl.cc
@@ -0,0 +1,91 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/content/content_thread_impl.h"
+
+// DCHECK_CURRENTLY_ON will be redefined in the content/ browser_thread.h
+#undef DCHECK_CURRENTLY_ON
+
+#include <string>
+#include <utility>
+
+#include "base/atomicops.h"
+#include "base/compiler_specific.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/lazy_instance.h"
+#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/task_executor.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "ios/web/public/thread/web_task_traits.h"
+#include "ios/web/public/thread/web_thread_delegate.h"
+
+namespace web {
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ContentThreadImpl::GetUIThreadTaskRunner(const WebTaskTraits& traits) {
+  // Map WebTraits to browser traits. iOS doesn't use TaskPriorities in
+  // WebThread so take a best guess.
+  content::BrowserTaskTraits browser_traits{base::TaskPriority::BEST_EFFORT};
+  return content::GetUIThreadTaskRunner(browser_traits);
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ContentThreadImpl::GetIOThreadTaskRunner(const WebTaskTraits& traits) {
+  // Map WebTraits to browser traits. iOS doesn't use TaskPriorities in
+  // WebThread so take a best guess.
+  content::BrowserTaskTraits browser_traits{base::TaskPriority::BEST_EFFORT};
+  return content::GetIOThreadTaskRunner(browser_traits);
+}
+
+content::BrowserThread::ID MapWebToBrowserID(WebThread::ID identifier) {
+  if (identifier == WebThread::UI) {
+    return content::BrowserThread::UI;
+  }
+  if (identifier == WebThread::IO) {
+    return content::BrowserThread::IO;
+  }
+  NOTREACHED();
+  return content::BrowserThread::UI;  // default?
+}
+
+WebThread::ID MapBrowserToWebID(content::BrowserThread::ID identifier) {
+  if (identifier == content::BrowserThread::UI) {
+    return WebThread::UI;
+  }
+  if (identifier == content::BrowserThread::IO) {
+    return WebThread::IO;
+  }
+  return WebThread::UI;
+}
+
+// static
+bool ContentThreadImpl::IsThreadInitialized(ID identifier) {
+  return content::BrowserThread::IsThreadInitialized(
+      MapWebToBrowserID(identifier));
+}
+
+// static
+bool ContentThreadImpl::CurrentlyOn(ID identifier) {
+  return content::BrowserThread::CurrentlyOn(MapWebToBrowserID(identifier));
+}
+
+// static
+std::string ContentThreadImpl::GetDCheckCurrentlyOnErrorMessage(ID expected) {
+  return content::BrowserThread::GetDCheckCurrentlyOnErrorMessage(
+      MapWebToBrowserID(expected));
+}
+
+// static
+bool ContentThreadImpl::GetCurrentThreadIdentifier(ID* identifier) {
+  content::BrowserThread::ID browser_id = content::BrowserThread::UI;
+  bool result = content::BrowserThread::GetCurrentThreadIdentifier(&browser_id);
+  *identifier = MapBrowserToWebID(browser_id);
+  return result;
+}
+
+}  // namespace web
diff --git a/ios/web/content/content_thread_impl.h b/ios/web/content/content_thread_impl.h
new file mode 100644
index 0000000..27c9abd7a
--- /dev/null
+++ b/ios/web/content/content_thread_impl.h
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_CONTENT_CONTENT_THREAD_IMPL_H_
+#define IOS_WEB_CONTENT_CONTENT_THREAD_IMPL_H_
+
+#include "ios/web/public/thread/web_thread.h"
+
+namespace web {
+
+// ContentThreadImpl is an alternate backend for WebThread that uses a
+// BrowserThreadImpl as its base.
+class ContentThreadImpl : public WebThread {
+ public:
+  // WebThread static implementation:
+  static scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
+      const WebTaskTraits& traits);
+  static scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
+      const WebTaskTraits& traits);
+  static bool IsThreadInitialized(ID identifier);
+  static bool CurrentlyOn(ID identifier);
+  static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
+  static bool GetCurrentThreadIdentifier(ID* identifier);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_CONTENT_CONTENT_THREAD_IMPL_H_
diff --git a/ios/web/content/web_state/content_web_state.mm b/ios/web/content/web_state/content_web_state.mm
index 25001f9..0c3f131 100644
--- a/ios/web/content/web_state/content_web_state.mm
+++ b/ios/web/content/web_state/content_web_state.mm
@@ -7,12 +7,14 @@
 #import "base/strings/utf_string_conversions.h"
 #import "content/public/browser/navigation_entry.h"
 #import "content/public/browser/web_contents.h"
+#import "ios/web/content/content_browser_context.h"
 #import "ios/web/content/navigation/content_navigation_context.h"
 #import "ios/web/content/web_state/crc_web_view_proxy_impl.h"
 #import "ios/web/find_in_page/java_script_find_in_page_manager_impl.h"
 #import "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/web_state_policy_decider.h"
+#import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/web_state_observer.h"
 #import "ios/web/text_fragments/text_fragments_manager_impl.h"
 #import "net/cert/x509_util.h"
@@ -64,8 +66,12 @@
 }  // namespace
 
 ContentWebState::ContentWebState(const CreateParams& params) {
-  // TODO(crbug.com/1419001): initialize web_contents_ with
-  // WebContents::Create(...) when a BrowserContext is available.
+  content::BrowserContext* browser_context =
+      ContentBrowserContext::FromBrowserState(params.browser_state);
+  scoped_refptr<content::SiteInstance> site_instance;
+  content::WebContents::CreateParams createParams(browser_context,
+                                                  site_instance);
+  web_contents_ = content::WebContents::Create(createParams);
   WebContentsObserver::Observe(web_contents_.get());
   content::NavigationController* controller = nullptr;
   if (web_contents_) {
@@ -78,6 +84,10 @@
       this, params.browser_state, controller);
   web_frames_manager_ = std::make_unique<ContentWebFramesManager>(this);
 
+  UIView* web_contents_view = web_contents_->GetNativeView();
+  web_contents_view.translatesAutoresizingMaskIntoConstraints = NO;
+  web_contents_view.layer.backgroundColor = UIColor.grayColor.CGColor;
+
   web_view_ = [[UIScrollView alloc] init];
   web_view_.translatesAutoresizingMaskIntoConstraints = NO;
   web_view_.backgroundColor = UIColor.redColor;
@@ -127,7 +137,7 @@
 void ContentWebState::SetWebUsageEnabled(bool enabled) {}
 
 UIView* ContentWebState::GetView() {
-  return web_view_;
+  return web_contents_->GetNativeView();
 }
 
 void ContentWebState::DidCoverWebContent() {}
@@ -190,7 +200,7 @@
 }
 
 CRWSessionStorage* ContentWebState::BuildSessionStorage() {
-  return nil;
+  return [[CRWSessionStorage alloc] init];
 }
 
 void ContentWebState::LoadData(NSData* data,
diff --git a/ios/web/public/thread/web_thread.h b/ios/web/public/thread/web_thread.h
index 9962a09..4f6bd3f 100644
--- a/ios/web/public/thread/web_thread.h
+++ b/ios/web/public/thread/web_thread.h
@@ -10,15 +10,8 @@
 #include <utility>
 
 #include "base/check_op.h"
-#include "base/functional/callback.h"
-#include "base/location.h"
-#include "base/memory/ref_counted.h"
 #include "base/task/single_thread_task_runner.h"
 
-namespace base {
-class Location;
-}
-
 namespace web {
 
 // TODO(crbug.com/1026641): Include web_task_traits.h directly when the
@@ -83,20 +76,6 @@
   WebThread(const WebThread&) = delete;
   WebThread& operator=(const WebThread&) = delete;
 
-  // Delete/ReleaseSoon() helpers allow future deletion of an owned object on
-  // its associated thread. If you already have a task runner bound to a
-  // WebThread you should use its SequencedTaskRunner::DeleteSoon() member
-  // method.
-  // TODO(crbug.com/1026641): Get rid of the last few callers to these in favor
-  // of an explicit call to web::GetUIThreadTaskRunner({})->DeleteSoon(...).
-
-  template <class T>
-  static bool DeleteSoon(ID identifier,
-                         const base::Location& from_here,
-                         const T* object) {
-    return GetTaskRunnerForThread(identifier)->DeleteSoon(from_here, object);
-  }
-
   // Callable on any thread.  Returns whether the given well-known thread is
   // initialized.
   [[nodiscard]] static bool IsThreadInitialized(ID identifier);
@@ -124,57 +103,9 @@
   // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
   static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
 
-  // Use these templates in conjunction with RefCountedThreadSafe or
-  // std::unique_ptr when you want to ensure that an object is deleted on a
-  // specific thread. This is needed when an object can hop between threads
-  // (i.e. IO -> UI -> IO), and thread switching delays can mean that the final
-  // IO tasks executes before the UI task's stack unwinds. This would lead to
-  // the object destructing on the UI thread, which often is not what you want
-  // (i.e. to unregister from NotificationService, to notify other objects on
-  // the creating thread etc).
-  template <ID thread>
-  struct DeleteOnThread {
-    template <typename T>
-    static void Destruct(const T* x) {
-      if (CurrentlyOn(thread)) {
-        delete x;
-      } else {
-        if (!DeleteSoon(thread, FROM_HERE, x)) {
-          // Leaks at shutdown are acceptable under normal circumstances,
-          // do not report.
-        }
-      }
-    }
-    template <typename T>
-    inline void operator()(T* ptr) const {
-      enum { type_must_be_complete = sizeof(T) };
-      Destruct(ptr);
-    }
-  };
-
-  // Sample usage with RefCountedThreadSafe:
-  // class Foo
-  //     : public base::RefCountedThreadSafe<
-  //           Foo, web::WebThread::DeleteOnIOThread> {
-  //
-  // ...
-  //  private:
-  //   friend struct web::WebThread::DeleteOnThread<web::WebThread::IO>;
-  //   friend class base::DeleteHelper<Foo>;
-  //
-  //   ~Foo();
-  //
-  // Sample usage with std::unique_ptr:
-  // std::unique_ptr<Foo, web::WebThread::DeleteOnIOThread> ptr;
-  struct DeleteOnUIThread : public DeleteOnThread<UI> {};
-  struct DeleteOnIOThread : public DeleteOnThread<IO> {};
-
  private:
   friend class WebThreadImpl;
-
-  // For DeleteSoon() only.
-  static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
-      ID identifier);
+  friend class ContentThreadImpl;
 
   WebThread() = default;
 };
diff --git a/ios/web/thread/BUILD.gn b/ios/web/thread/BUILD.gn
index 51bd801..e63f738 100644
--- a/ios/web/thread/BUILD.gn
+++ b/ios/web/thread/BUILD.gn
@@ -6,7 +6,18 @@
 
 source_set("thread") {
   configs += [ "//build/config/compiler:enable_arc" ]
-  deps = [ "//ios/web/public" ]
+  deps = [
+    "//build:blink_buildflags",
+    "//ios/web:threads",
+    "//ios/web/public",
+  ]
 
-  sources = [ "web_task_traits.cc" ]
+  if (use_blink) {
+    deps += [ "//ios/web/content" ]
+  }
+
+  sources = [
+    "web_task_traits.cc",
+    "web_thread.cc",
+  ]
 }
diff --git a/ios/web/thread/web_thread.cc b/ios/web/thread/web_thread.cc
new file mode 100644
index 0000000..1e8fde1
--- /dev/null
+++ b/ios/web/thread/web_thread.cc
@@ -0,0 +1,63 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/public/thread/web_thread.h"
+
+#import "build/blink_buildflags.h"
+#include "ios/web/content/content_thread_impl.h"
+#include "ios/web/web_thread_impl.h"
+
+namespace web {
+
+scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
+    const WebTaskTraits& traits) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::GetUIThreadTaskRunner(traits);
+#else
+  return WebThreadImpl::GetUIThreadTaskRunner(traits);
+#endif
+}
+
+scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
+    const WebTaskTraits& traits) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::GetIOThreadTaskRunner(traits);
+#else
+  return WebThreadImpl::GetIOThreadTaskRunner(traits);
+#endif
+}
+
+bool WebThread::IsThreadInitialized(ID identifier) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::IsThreadInitialized(identifier);
+#else
+  return WebThreadImpl::IsThreadInitialized(identifier);
+#endif
+}
+
+bool WebThread::CurrentlyOn(ID identifier) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::CurrentlyOn(identifier);
+#else
+  return WebThreadImpl::CurrentlyOn(identifier);
+#endif
+}
+
+std::string WebThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::GetDCheckCurrentlyOnErrorMessage(expected);
+#else
+  return WebThreadImpl::GetDCheckCurrentlyOnErrorMessage(expected);
+#endif
+}
+
+bool WebThread::GetCurrentThreadIdentifier(ID* identifier) {
+#if BUILDFLAG(USE_BLINK)
+  return ContentThreadImpl::GetCurrentThreadIdentifier(identifier);
+#else
+  return WebThreadImpl::GetCurrentThreadIdentifier(identifier);
+#endif
+}
+
+}  // namespace web
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index cf5c3a59..dfc2f54 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -242,14 +242,14 @@
 
 }  // namespace
 
-scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
-    const WebTaskTraits& traits) {
+scoped_refptr<base::SingleThreadTaskRunner>
+WebThreadImpl::GetUIThreadTaskRunner(const WebTaskTraits& traits) {
   return WebThreadTaskExecutor::GetInstance()->GetTaskRunner(WebThread::UI,
                                                              traits);
 }
 
-scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
-    const WebTaskTraits& traits) {
+scoped_refptr<base::SingleThreadTaskRunner>
+WebThreadImpl::GetIOThreadTaskRunner(const WebTaskTraits& traits) {
   return WebThreadTaskExecutor::GetInstance()->GetTaskRunner(WebThread::IO,
                                                              traits);
 }
@@ -290,7 +290,6 @@
   globals.states[identifier] = WebThreadState::UNINITIALIZED;
   globals.task_runners[identifier] = nullptr;
 }
-
 // Friendly names for the well-known threads.
 
 // static
@@ -306,7 +305,7 @@
 }
 
 // static
-bool WebThread::IsThreadInitialized(ID identifier) {
+bool WebThreadImpl::IsThreadInitialized(ID identifier) {
   if (!g_globals.IsCreated())
     return false;
 
@@ -318,7 +317,7 @@
 }
 
 // static
-bool WebThread::CurrentlyOn(ID identifier) {
+bool WebThreadImpl::CurrentlyOn(ID identifier) {
   WebThreadGlobals& globals = g_globals.Get();
   base::AutoLock lock(globals.lock);
   DCHECK_GE(identifier, 0);
@@ -328,7 +327,7 @@
 }
 
 // static
-std::string WebThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
+std::string WebThreadImpl::GetDCheckCurrentlyOnErrorMessage(ID expected) {
   std::string actual_name = base::PlatformThread::GetName();
   if (actual_name.empty())
     actual_name = "Unknown Thread";
@@ -342,7 +341,7 @@
 }
 
 // static
-bool WebThread::GetCurrentThreadIdentifier(ID* identifier) {
+bool WebThreadImpl::GetCurrentThreadIdentifier(ID* identifier) {
   if (!g_globals.IsCreated())
     return false;
 
@@ -360,22 +359,6 @@
 }
 
 // static
-scoped_refptr<base::SingleThreadTaskRunner> WebThread::GetTaskRunnerForThread(
-    ID identifier) {
-  DCHECK_GE(identifier, 0);
-  DCHECK_LT(identifier, ID_COUNT);
-  switch (identifier) {
-    case UI:
-      return GetUIThreadTaskRunner({});
-    case IO:
-      return GetIOThreadTaskRunner({});
-    case ID_COUNT:
-      NOTREACHED();
-      return nullptr;
-  }
-}
-
-// static
 void WebThreadImpl::CreateTaskExecutor() {
   WebThreadTaskExecutor::CreateInstance();
 }
diff --git a/ios/web/web_thread_impl.h b/ios/web/web_thread_impl.h
index 873802aa..f63fef5 100644
--- a/ios/web/web_thread_impl.h
+++ b/ios/web/web_thread_impl.h
@@ -29,6 +29,16 @@
  public:
   ~WebThreadImpl();
 
+  // WebThread static implementation:
+  static scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
+      const WebTaskTraits& traits);
+  static scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
+      const WebTaskTraits& traits);
+  static bool IsThreadInitialized(ID identifier);
+  static bool CurrentlyOn(ID identifier);
+  static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
+  static bool GetCurrentThreadIdentifier(ID* identifier);
+
   // Returns the thread name for `identifier`.
   static const char* GetThreadName(WebThread::ID identifier);
 
diff --git a/media/gpu/chromeos/oop_video_decoder.cc b/media/gpu/chromeos/oop_video_decoder.cc
index 22684b39..21b3f96 100644
--- a/media/gpu/chromeos/oop_video_decoder.cc
+++ b/media/gpu/chromeos/oop_video_decoder.cc
@@ -518,7 +518,10 @@
   CHECK(!reset_cb_);
 
   if (has_error_ || remote_decoder_type_ == VideoDecoderType::kUnknown) {
-    std::move(reset_cb).Run();
+    // Post a task instead of calling |reset_cb| immediately in order to keep
+    // the relative order between decode callbacks (posted as tasks in Decode())
+    // and the reset callback.
+    decoder_task_runner_->PostTask(FROM_HERE, std::move(reset_cb));
     return;
   }
 
@@ -537,6 +540,16 @@
     Stop();
     return;
   }
+
+  // After a reset is completed, we shouldn't receive decoded frames
+  // corresponding to Decode() calls that came in prior to the reset (similar to
+  // a flush). That's because according to the media::VideoDecoder and
+  // media::stable::mojom::StableVideoDecoder interfaces, all ongoing Decode()
+  // requests must be completed or aborted prior to executing the reset
+  // callback. The clearing of the cache together with the validation in
+  // OnVideoFrameDecoded() should guarantee this.
+  fake_timestamp_to_real_timestamp_cache_.Clear();
+
   std::move(reset_cb_).Run();
 }
 
@@ -587,8 +600,12 @@
   pending_decodes_.clear();
   is_flushing_ = false;
 
-  if (reset_cb_)
-    std::move(reset_cb_).Run();
+  if (reset_cb_) {
+    // We post the |reset_cb_| as a task instead of calling it immediately so
+    // that we keep the order of pending decode callbacks (posted as tasks
+    // above) with respect to the reset callback.
+    decoder_task_runner_->PostTask(FROM_HERE, std::move(reset_cb_));
+  }
 }
 
 void OOPVideoDecoder::ReleaseVideoFrame(
@@ -626,6 +643,7 @@
 VideoDecoderType OOPVideoDecoder::GetDecoderType() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(!init_cb_);
+  CHECK(!reset_cb_);
   return VideoDecoderType::kOutOfProcess;
 }
 
diff --git a/media/gpu/chromeos/oop_video_decoder.h b/media/gpu/chromeos/oop_video_decoder.h
index 675f830f..6e316da 100644
--- a/media/gpu/chromeos/oop_video_decoder.h
+++ b/media/gpu/chromeos/oop_video_decoder.h
@@ -143,6 +143,10 @@
   //    pending in the queue and |decode_cb| must be called after that." We can
   //    do this by clearing the cache when a flush has been reported to be
   //    completed by the remote decoder.
+  //
+  // 3) Guarantee the following requirement mandated by the
+  //    VideoDecoder::Reset() API: "All pending Decode() requests will be
+  //    finished or aborted before |closure| is called."
   base::TimeDelta current_fake_timestamp_
       GUARDED_BY_CONTEXT(sequence_checker_) = base::Microseconds(0u);
   base::LRUCache<base::TimeDelta, base::TimeDelta>
diff --git a/media/remoting/receiver_unittest.cc b/media/remoting/receiver_unittest.cc
index ce26f95..b7338f3 100644
--- a/media/remoting/receiver_unittest.cc
+++ b/media/remoting/receiver_unittest.cc
@@ -301,13 +301,12 @@
   int receiver_renderer_handle_ = RpcMessenger::kInvalidHandle;
 
   MockMediaResource mock_media_resource_;
-  raw_ptr<MockRenderer> mock_renderer_ = nullptr;
   std::unique_ptr<MockSender> mock_sender_;
-
   raw_ptr<RpcMessenger> rpc_messenger_ = nullptr;
   raw_ptr<MockRemotee> mock_remotee_;
   raw_ptr<MockReceiverController> mock_controller_ = nullptr;
   std::unique_ptr<Receiver> receiver_;
+  raw_ptr<MockRenderer> mock_renderer_ = nullptr;
 
   base::WeakPtrFactory<ReceiverTest> weak_factory_{this};
 };
diff --git a/mojo/public/js/interface_support.js b/mojo/public/js/interface_support.js
index acd94ac8..a33f743 100644
--- a/mojo/public/js/interface_support.js
+++ b/mojo/public/js/interface_support.js
@@ -345,7 +345,9 @@
  */
 mojo.internal.interfaceSupport.createEndpoint = function(
     pipeOrEndpoint, setNamespaceBit = false) {
-  if (pipeOrEndpoint.constructor.name != 'MojoHandle') {
+  // `watch` is defined on MojoHandle but not Endpoint, so if it is not defined
+  // we know this is an Endpoint.
+  if (pipeOrEndpoint.watch === undefined) {
     return /** @type {!mojo.internal.interfaceSupport.Endpoint} */(
         pipeOrEndpoint);
   }
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index eab0cf8..52682432 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -316,11 +316,11 @@
   friend class MockHttpCache;
   friend class HttpCacheIOCallbackTest;
 
-  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeature,
+  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeatureEnabled,
                            SplitCacheWithNetworkIsolationKey);
   FRIEND_TEST_ALL_PREFIXES(HttpCacheTest, NonSplitCache);
-  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeature, SplitCache);
-  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeature,
+  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeatureEnabled, SplitCache);
+  FRIEND_TEST_ALL_PREFIXES(HttpCacheTest_SplitCacheFeatureEnabled,
                            SplitCacheUsesRegistrableDomain);
 
   using TransactionList = std::list<Transaction*>;
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 3c0ee0d..690601d 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -80,16 +80,6 @@
     UPDATE          = READ_META | WRITE,  // READ_WRITE & ~READ_DATA
   };
 
-  // This enum backs a histogram. Please keep enums.xml up to date with any
-  // changes, and new entries should be appended at the end. Never re-arrange /
-  // re-use values.
-  enum class NetworkIsolationKeyPresent {
-    kNotPresentCacheableRequest = 0,
-    kNotPresentNonCacheableRequest = 1,
-    kPresent = 2,
-    kMaxValue = kPresent,
-  };
-
   Transaction(RequestPriority priority,
               HttpCache* cache);
 
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 7722bd5..46ccb07 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -1300,6 +1300,31 @@
       }
     });
 
+class HttpCacheTest_SplitCacheFeatureEnabled
+    : public HttpCacheTest_SplitCacheFeature {
+ public:
+  HttpCacheTest_SplitCacheFeatureEnabled() {
+    CHECK(base::FeatureList::IsEnabled(
+        net::features::kSplitCacheByNetworkIsolationKey));
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    HttpCacheTest_SplitCacheFeatureEnabled,
+    testing::ValuesIn({SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled,
+                       SplitCacheTestCase::kSplitCacheNikCrossSiteFlagEnabled}),
+    [](const testing::TestParamInfo<SplitCacheTestCase>& info) {
+      switch (info.param) {
+        case (SplitCacheTestCase::kSplitCacheDisabled):
+          return "NotUsedForThisTestSuite";
+        case (SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled):
+          return "SplitCacheNikFrameSiteEnabled";
+        case (SplitCacheTestCase::kSplitCacheNikCrossSiteFlagEnabled):
+          return "SplitCacheNikCrossSiteFlagEnabled";
+      }
+    });
+
 TEST_F(HttpCacheTest, SimpleGETNoDiskCache) {
   MockHttpCache cache;
 
@@ -7178,10 +7203,8 @@
 
 // Tests that a successful POST invalidates a previously cached GET,
 // with cache split by top-frame origin.
-TEST_P(HttpCacheTest_SplitCacheFeature, SimplePOST_Invalidate_205_SplitCache) {
-  if (!IsSplitCacheEnabled()) {
-    return;
-  }
+TEST_P(HttpCacheTest_SplitCacheFeatureEnabled,
+       SimplePOST_Invalidate_205_SplitCache) {
   SchemefulSite site_a(GURL("http://a.com"));
   SchemefulSite site_b(GURL("http://b.com"));
 
@@ -11195,10 +11218,8 @@
   RemoveMockTransaction(&mock_network_response);
 }
 
-TEST_P(HttpCacheTest_SplitCacheFeature, SplitCacheWithNetworkIsolationKey) {
-  if (!IsSplitCacheEnabled()) {
-    return;
-  }
+TEST_P(HttpCacheTest_SplitCacheFeatureEnabled,
+       SplitCacheWithNetworkIsolationKey) {
   MockHttpCache cache;
   HttpResponseInfo response;
 
@@ -11207,8 +11228,8 @@
   SchemefulSite site_data(GURL("data:text/html,<body>Hello World</body>"));
 
   MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction);
-  // Request with a.com as the top frame and subframe origins. It shouldn't be
-  // cached.
+  // Request with a.com as the top frame and subframe origins. This should
+  // result in a cache miss.
   trans_info.network_isolation_key = NetworkIsolationKey(site_a, site_a);
   trans_info.network_anonymization_key =
       net::NetworkAnonymizationKey::CreateSameSite(site_a);
@@ -11216,12 +11237,13 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // The second request should be cached.
+  // The second request should result in a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // Now request with b.com as the subframe origin. It shouldn't be cached.
+  // Now request with b.com as the subframe origin. It should result in a cache
+  // miss.
   trans_info.network_isolation_key = NetworkIsolationKey(site_a, site_b);
   trans_info.network_anonymization_key =
       net::NetworkAnonymizationKey::CreateCrossSite(site_a);
@@ -11229,12 +11251,13 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // The second request should be cached.
+  // The second request should result in a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // a.com should still be cached.
+  // Another request with a.com as the top frame and subframe origin should
+  // still result in a cache hit.
   trans_info.network_isolation_key = NetworkIsolationKey(site_a, site_a);
   trans_info.network_anonymization_key =
       net::NetworkAnonymizationKey::CreateSameSite(site_a);
@@ -11242,10 +11265,10 @@
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // Now make a request with an opaque subframe site.  It shouldn't be
-  // cached when the NIK makes use of the frame site. Note that we will use
-  // `site_b` as the top-level site so that this resource won't be in the cache
-  // at first regardless of the NIK partitioning scheme.
+  // Now make a request with an opaque subframe site. It shouldn't cause
+  // anything to be added to the cache when the NIK makes use of the frame site.
+  // Note that we will use `site_b` as the top-level site so that this resource
+  // won't be in the cache at first regardless of the NIK partitioning scheme.
   trans_info.network_isolation_key = NetworkIsolationKey(site_b, site_data);
   trans_info.network_anonymization_key =
       net::NetworkAnonymizationKey::CreateCrossSite(site_b);
@@ -11260,8 +11283,7 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // On the second request, it still shouldn't be cached if
-  // the NIK uses the frame site.
+  // On the second request, expect a cache miss if the NIK uses the frame site.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   if (IsNikFrameSiteEnabled()) {
@@ -11419,10 +11441,7 @@
   histograms.ExpectTotalCount("HttpCache.Pattern.FontThirdParty", 1);
 }
 
-TEST_P(HttpCacheTest_SplitCacheFeature, SplitCache) {
-  if (!IsSplitCacheEnabled()) {
-    return;
-  }
+TEST_P(HttpCacheTest_SplitCacheFeatureEnabled, SplitCache) {
   MockHttpCache cache;
   HttpResponseInfo response;
 
@@ -11430,7 +11449,8 @@
   SchemefulSite site_b(GURL("http://b.com"));
   SchemefulSite site_data(GURL("data:text/html,<body>Hello World</body>"));
 
-  // A request without a top frame origin is not cached at all.
+  // A request without a top frame origin shouldn't result in anything being
+  // added to the cache.
   MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction);
   trans_info.network_isolation_key = net::NetworkIsolationKey();
   trans_info.network_anonymization_key = net::NetworkAnonymizationKey();
@@ -11442,8 +11462,9 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // Now request with a.com as the top frame origin. It shouldn't be cached
-  // since the cached resource has a different top frame origin.
+  // Now request with a.com as the top frame origin. This should initially
+  // result in a cache miss since the cached resource has a different top frame
+  // origin.
   net::NetworkIsolationKey key_a(site_a, site_a);
   auto nak_a = net::NetworkAnonymizationKey::CreateSameSite(site_a);
   trans_info.network_isolation_key = key_a;
@@ -11452,7 +11473,7 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // The second request should be cached.
+  // The second request should result in a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
@@ -11470,7 +11491,7 @@
                                 subframe_document_trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // Now request with b.com as the top frame origin. It shouldn't be cached.
+  // Now request with b.com as the top frame origin. It should be a cache miss.
   trans_info.network_isolation_key = NetworkIsolationKey(site_b, site_b);
   trans_info.network_anonymization_key =
       NetworkAnonymizationKey::CreateSameSite(site_b);
@@ -11478,20 +11499,20 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // The second request should be cached.
+  // The second request should be a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // a.com should still be cached.
+  // Another request for a.com should still result in a cache hit.
   trans_info.network_isolation_key = key_a;
   trans_info.network_anonymization_key = nak_a;
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // Now make a request with an opaque top frame origin.  It shouldn't be
-  // cached.
+  // Now make a request with an opaque top frame origin. It shouldn't result in
+  // a cache hit.
   trans_info.network_isolation_key = NetworkIsolationKey(site_data, site_data);
   trans_info.network_anonymization_key =
       NetworkAnonymizationKey::CreateSameSite(site_data);
@@ -11500,7 +11521,7 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // On the second request, it still shouldn't be cached.
+  // On the second request, it still shouldn't result in a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
@@ -11570,10 +11591,8 @@
   EXPECT_FALSE(HttpCache::IsSplitCacheEnabled());
 }
 
-TEST_P(HttpCacheTest_SplitCacheFeature, SplitCacheUsesRegistrableDomain) {
-  if (!IsSplitCacheEnabled()) {
-    return;
-  }
+TEST_P(HttpCacheTest_SplitCacheFeatureEnabled,
+       SplitCacheUsesRegistrableDomain) {
   MockHttpCache cache;
   HttpResponseInfo response;
   MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction);
@@ -11618,7 +11637,7 @@
   MockHttpCache cache;
   HttpResponseInfo response;
 
-  // A request without a top frame is cached normally.
+  // A request without a top frame is added to the cache normally.
   MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction);
   trans_info.network_isolation_key = NetworkIsolationKey();
   trans_info.network_anonymization_key = NetworkAnonymizationKey();
@@ -11626,13 +11645,13 @@
                                 trans_info, &response);
   EXPECT_FALSE(response.was_cached);
 
-  // The second request comes from cache.
+  // The second request should result in a cache hit.
   RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction,
                                 trans_info, &response);
   EXPECT_TRUE(response.was_cached);
 
-  // Now request with a.com as the top frame origin. It should use the same
-  // cached object.
+  // Now request with a.com as the top frame origin. The same cached object
+  // should be used.
   const SchemefulSite kSiteA(GURL("http://a.com/"));
   trans_info.network_isolation_key = NetworkIsolationKey(kSiteA, kSiteA);
   trans_info.network_anonymization_key =
@@ -13799,7 +13818,7 @@
   EXPECT_FALSE(response.was_cached);
   EXPECT_THAT(response.dns_aliases, testing::ElementsAre("alias1", "alias2"));
 
-  // The second request should be cached, and the response used without
+  // The second request result in a cache hit and the response used without
   // revalidation. Set the transaction alias list to empty to verify that the
   // cached aliases are being used.
   transaction.dns_aliases = {};
@@ -13820,9 +13839,9 @@
   EXPECT_FALSE(response.was_cached);
   EXPECT_TRUE(response.dns_aliases.empty());
 
-  // The second request should be cached, and the response used without
-  // revalidation. Set the transaction alias list to nonempty to verify that the
-  // cached aliases are being used.
+  // The second request should result in a cache hit and the response used
+  // without revalidation. Set the transaction alias list to nonempty to verify
+  // that the cached aliases are being used.
   transaction.dns_aliases = {"alias"};
   RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
                                      &response);
@@ -13967,13 +13986,10 @@
   EXPECT_EQ(304, response.headers->response_code());
   EXPECT_EQ("cross-origin", response_corp_header);
 }
-class HttpCacheSingleKeyedCacheTest
-    : public HttpCacheTest,
-      public ::testing::WithParamInterface<SplitCacheTestCase> {
+class CacheTransparencyHttpCacheTest
+    : public HttpCacheTest_SplitCacheFeatureEnabled {
  public:
-  HttpCacheSingleKeyedCacheTest() {
-    InitializeSplitCacheScopedFeatureList(feature_list_, GetParam());
-
+  CacheTransparencyHttpCacheTest() {
     // The single-keyed cache feature is meaningless when the split cache is not
     // enabled. The //net layer doesn't care whether or not the
     // "CacheTransparency" feature is enabled.
@@ -13981,10 +13997,6 @@
         net::features::kSplitCacheByNetworkIsolationKey));
   }
 
-  bool IsNikFrameSiteEnabled() const {
-    return GetParam() == SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled;
-  }
-
   void RunTransactionTestForSingleKeyedCache(
       HttpCache* cache,
       const MockTransaction& trans_info,
@@ -14010,14 +14022,11 @@
     RunTransactionTestForSingleKeyedCache(cache, kSimpleGET_Transaction,
                                           network_isolation_key, checksum);
   }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 INSTANTIATE_TEST_SUITE_P(
     All,
-    HttpCacheSingleKeyedCacheTest,
+    CacheTransparencyHttpCacheTest,
     testing::ValuesIn({SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled,
                        SplitCacheTestCase::kSplitCacheNikCrossSiteFlagEnabled}),
     [](const testing::TestParamInfo<SplitCacheTestCase>& info) {
@@ -14034,7 +14043,7 @@
 constexpr char kChecksumForSimpleGET[] =
     "80B4C37CEF5CFE69B4A90830282AA2BB772DC4CBC00491A219CE5F2AD75C7B58";
 
-TEST_P(HttpCacheSingleKeyedCacheTest, SuccessfulGET) {
+TEST_P(CacheTransparencyHttpCacheTest, SuccessfulGET) {
   MockHttpCache cache;
   // The first request adds the item to the cache.
   {
@@ -14062,7 +14071,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, GETWithChecksumMismatch) {
+TEST_P(CacheTransparencyHttpCacheTest, GETWithChecksumMismatch) {
   MockHttpCache cache;
   const auto site_a = SchemefulSite(GURL("https://a.com/"));
   // The first request adds the item to the cache.
@@ -14102,7 +14111,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, GETWithBadResponseCode) {
+TEST_P(CacheTransparencyHttpCacheTest, GETWithBadResponseCode) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   transaction.status = "HTTP/1.1 404 Not Found";
@@ -14134,7 +14143,7 @@
 // This is identical to GETWithBadResponseCode but with a different response
 // code. It's not very realistic as it doesn't call DoneReading(), but it covers
 // the relevant code path.
-TEST_P(HttpCacheSingleKeyedCacheTest, RedirectUnusable) {
+TEST_P(CacheTransparencyHttpCacheTest, RedirectUnusable) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   transaction.status = "HTTP/1.1 301 Moved Permanently";
@@ -14163,7 +14172,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, GETWith206ResponseCode) {
+TEST_P(CacheTransparencyHttpCacheTest, GETWith206ResponseCode) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   // We should never get a partial response since we never send a range request,
@@ -14193,7 +14202,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, SuccessfulRevalidation) {
+TEST_P(CacheTransparencyHttpCacheTest, SuccessfulRevalidation) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   // Add a cache control header to permit the entry to be cached, with max-age 0
@@ -14243,7 +14252,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, RevalidationChangingUncheckedHeader) {
+TEST_P(CacheTransparencyHttpCacheTest, RevalidationChangingUncheckedHeader) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   // Add a cache control header to permit the entry to be cached, with max-age 0
@@ -14295,7 +14304,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, RevalidationChangingCheckedHeader) {
+TEST_P(CacheTransparencyHttpCacheTest, RevalidationChangingCheckedHeader) {
   MockHttpCache cache;
   MockTransaction transaction = kSimpleGET_Transaction;
   // Add a cache control header to permit the entry to be cached, with max-age 0
@@ -14347,7 +14356,7 @@
   }
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, SuccessfulGETManyWriters) {
+TEST_P(CacheTransparencyHttpCacheTest, SuccessfulGETManyWriters) {
   MockHttpCache cache;
 
   MockHttpRequest request(kSimpleGET_Transaction);
@@ -14389,7 +14398,7 @@
   EXPECT_EQ(1, cache.disk_cache()->create_count());
 }
 
-TEST_P(HttpCacheSingleKeyedCacheTest, BadChecksumManyWriters) {
+TEST_P(CacheTransparencyHttpCacheTest, BadChecksumManyWriters) {
   MockHttpCache cache;
 
   MockHttpRequest request(kSimpleGET_Transaction);
diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h
index 888771d..80922d5 100644
--- a/printing/backend/print_backend.h
+++ b/printing/backend/print_backend.h
@@ -277,10 +277,13 @@
       const std::string& printer_name,
       PrinterSemanticCapsAndDefaults* printer_info) = 0;
 
+#if BUILDFLAG(IS_WIN)
   // Gets the capabilities and defaults for a specific printer.
+  // TODO(crbug.com/1008222): Evaluate if this code is useful and delete if not.
   virtual mojom::ResultCode GetPrinterCapsAndDefaults(
       const std::string& printer_name,
       PrinterCapsAndDefaults* printer_info) = 0;
+#endif
 
   // Gets the information about driver for a specific printer.
   virtual std::string GetPrinterDriverInfo(const std::string& printer_name) = 0;
diff --git a/printing/backend/print_backend_chromeos.cc b/printing/backend/print_backend_chromeos.cc
index c14eba5..906cd97 100644
--- a/printing/backend/print_backend_chromeos.cc
+++ b/printing/backend/print_backend_chromeos.cc
@@ -30,9 +30,6 @@
   mojom::ResultCode GetPrinterBasicInfo(
       const std::string& printer_name,
       PrinterBasicInfo* printer_info) override;
-  mojom::ResultCode GetPrinterCapsAndDefaults(
-      const std::string& printer_name,
-      PrinterCapsAndDefaults* printer_info) override;
   mojom::ResultCode GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       PrinterSemanticCapsAndDefaults* printer_info) override;
@@ -54,13 +51,6 @@
   return mojom::ResultCode::kFailed;
 }
 
-mojom::ResultCode PrintBackendChromeOS::GetPrinterCapsAndDefaults(
-    const std::string& printer_name,
-    PrinterCapsAndDefaults* printer_info) {
-  NOTREACHED();
-  return mojom::ResultCode::kFailed;
-}
-
 mojom::ResultCode PrintBackendChromeOS::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     PrinterSemanticCapsAndDefaults* printer_info) {
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc
index f9493691..63d46fe 100644
--- a/printing/backend/print_backend_cups.cc
+++ b/printing/backend/print_backend_cups.cc
@@ -240,51 +240,39 @@
 mojom::ResultCode PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     PrinterSemanticCapsAndDefaults* printer_info) {
-  PrinterCapsAndDefaults info;
   if (!IsValidPrinter(printer_name))
     return mojom::ResultCode::kFailed;
 
-  mojom::ResultCode result_code =
-      GetPrinterCapsAndDefaults(printer_name, &info);
-  if (result_code != mojom::ResultCode::kSuccess)
-    return result_code;
+  std::string printer_capabilities = GetPrinterCapabilities(printer_name);
+  if (printer_capabilities.empty()) {
+    return mojom::ResultCode::kFailed;
+  }
 
   ScopedDestination dest = GetNamedDest(printer_name);
-  return ParsePpdCapabilities(dest.get(), locale_, info.printer_capabilities,
+  return ParsePpdCapabilities(dest.get(), locale_, printer_capabilities,
                               printer_info)
              ? mojom::ResultCode::kSuccess
              : mojom::ResultCode::kFailed;
 }
 
-mojom::ResultCode PrintBackendCUPS::GetPrinterCapsAndDefaults(
-    const std::string& printer_name,
-    PrinterCapsAndDefaults* printer_info) {
-  DCHECK(printer_info);
-
+std::string PrintBackendCUPS::GetPrinterCapabilities(
+    const std::string& printer_name) {
   VLOG(1) << "CUPS: Getting caps and defaults, printer name: " << printer_name;
 
   base::FilePath ppd_path(GetPPD(printer_name.c_str()));
   // In some cases CUPS failed to get ppd file.
   if (ppd_path.empty()) {
     LOG(ERROR) << "CUPS: Failed to get PPD, printer name: " << printer_name;
-    return mojom::ResultCode::kFailed;
+    return std::string();
   }
 
   std::string content;
-  bool res = base::ReadFileToString(ppd_path, &content);
+  if (!base::ReadFileToString(ppd_path, &content)) {
+    content.clear();
+  }
 
   base::DeleteFile(ppd_path);
-
-  if (!res)
-    return mojom::ResultCode::kFailed;
-
-  printer_info->printer_capabilities.swap(content);
-  printer_info->caps_mime_type = "application/pagemaker";
-  // In CUPS, printer defaults is a part of PPD file. Nothing to upload here.
-  printer_info->printer_defaults.clear();
-  printer_info->defaults_mime_type.clear();
-
-  return mojom::ResultCode::kSuccess;
+  return content;
 }
 
 std::string PrintBackendCUPS::GetPrinterDriverInfo(
diff --git a/printing/backend/print_backend_cups.h b/printing/backend/print_backend_cups.h
index a3b1e04..ce13b6e87 100644
--- a/printing/backend/print_backend_cups.h
+++ b/printing/backend/print_backend_cups.h
@@ -51,12 +51,11 @@
   mojom::ResultCode GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       PrinterSemanticCapsAndDefaults* printer_info) override;
-  mojom::ResultCode GetPrinterCapsAndDefaults(
-      const std::string& printer_name,
-      PrinterCapsAndDefaults* printer_info) override;
   std::string GetPrinterDriverInfo(const std::string& printer_name) override;
   bool IsValidPrinter(const std::string& printer_name) override;
 
+  std::string GetPrinterCapabilities(const std::string& printer_name);
+
   // The following functions are wrappers around corresponding CUPS functions.
   // <functions>2() are called when print server is specified, and plain version
   // in another case. There is an issue specifying CUPS_HTTP_DEFAULT in the
diff --git a/printing/backend/print_backend_cups_ipp.cc b/printing/backend/print_backend_cups_ipp.cc
index d23323de..52d960f7 100644
--- a/printing/backend/print_backend_cups_ipp.cc
+++ b/printing/backend/print_backend_cups_ipp.cc
@@ -87,13 +87,6 @@
                                               : mojom::ResultCode::kFailed;
 }
 
-mojom::ResultCode PrintBackendCupsIpp::GetPrinterCapsAndDefaults(
-    const std::string& printer_name,
-    PrinterCapsAndDefaults* printer_info) {
-  NOTREACHED();
-  return mojom::ResultCode::kFailed;
-}
-
 mojom::ResultCode PrintBackendCupsIpp::GetPrinterSemanticCapsAndDefaults(
     const std::string& printer_name,
     PrinterSemanticCapsAndDefaults* printer_info) {
diff --git a/printing/backend/print_backend_cups_ipp.h b/printing/backend/print_backend_cups_ipp.h
index 7b39baa..cf50213 100644
--- a/printing/backend/print_backend_cups_ipp.h
+++ b/printing/backend/print_backend_cups_ipp.h
@@ -28,9 +28,6 @@
   mojom::ResultCode GetPrinterBasicInfo(
       const std::string& printer_name,
       PrinterBasicInfo* printer_info) override;
-  mojom::ResultCode GetPrinterCapsAndDefaults(
-      const std::string& printer_name,
-      PrinterCapsAndDefaults* printer_info) override;
   mojom::ResultCode GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       PrinterSemanticCapsAndDefaults* printer_info) override;
diff --git a/printing/backend/print_backend_dummy.cc b/printing/backend/print_backend_dummy.cc
index ff1cdd6..6e411ae 100644
--- a/printing/backend/print_backend_dummy.cc
+++ b/printing/backend/print_backend_dummy.cc
@@ -41,12 +41,6 @@
     return mojom::ResultCode::kFailed;
   }
 
-  mojom::ResultCode GetPrinterCapsAndDefaults(
-      const std::string& printer_name,
-      PrinterCapsAndDefaults* printer_info) override {
-    return mojom::ResultCode::kFailed;
-  }
-
   std::string GetPrinterDriverInfo(const std::string& printer_name) override {
     return std::string();
   }
diff --git a/printing/backend/test_print_backend.cc b/printing/backend/test_print_backend.cc
index 0a30332..ee60a91f 100644
--- a/printing/backend/test_print_backend.cc
+++ b/printing/backend/test_print_backend.cc
@@ -51,10 +51,12 @@
   return mojom::ResultCode::kFailed;
 }
 
+#if BUILDFLAG(IS_WIN)
 mojom::ResultCode ReportErrorNotImplemented(const base::Location& from_here) {
   DLOG(ERROR) << from_here.ToString() << " failed, method not implemented";
   return mojom::ResultCode::kFailed;
 }
+#endif  // BUILDFLAG(IS_WIN)
 
 }  // namespace
 
@@ -124,11 +126,13 @@
   return mojom::ResultCode::kSuccess;
 }
 
+#if BUILDFLAG(IS_WIN)
 mojom::ResultCode TestPrintBackend::GetPrinterCapsAndDefaults(
     const std::string& printer_name,
     PrinterCapsAndDefaults* printer_caps) {
   return ReportErrorNotImplemented(FROM_HERE);
 }
+#endif  // BUILDFLAG(IS_WIN)
 
 std::string TestPrintBackend::GetPrinterDriverInfo(
     const std::string& printer_name) {
diff --git a/printing/backend/test_print_backend.h b/printing/backend/test_print_backend.h
index 26334bdc7..b80eb73e 100644
--- a/printing/backend/test_print_backend.h
+++ b/printing/backend/test_print_backend.h
@@ -35,9 +35,11 @@
   mojom::ResultCode GetPrinterSemanticCapsAndDefaults(
       const std::string& printer_name,
       PrinterSemanticCapsAndDefaults* printer_info) override;
+#if BUILDFLAG(IS_WIN)
   mojom::ResultCode GetPrinterCapsAndDefaults(
       const std::string& printer_name,
       PrinterCapsAndDefaults* printer_info) override;
+#endif
   std::string GetPrinterDriverInfo(const std::string& printer_name) override;
   bool IsValidPrinter(const std::string& printer_name) override;
 #if BUILDFLAG(IS_WIN)
diff --git a/sandbox/linux/syscall_broker/broker_file_permission.cc b/sandbox/linux/syscall_broker/broker_file_permission.cc
index c29017e9..3fcb2c5 100644
--- a/sandbox/linux/syscall_broker/broker_file_permission.cc
+++ b/sandbox/linux/syscall_broker/broker_file_permission.cc
@@ -246,7 +246,10 @@
     return nullptr;
   }
 
-  if (!CheckIntermediates(requested_filename,
+  // If this permission is recursive and a prefix of `requested_filename`
+  // matches this permission, allow. Otherwise check intermediates.
+  if (!(recursive() && MatchPath(requested_filename)) &&
+      !CheckIntermediates(requested_filename,
                           /*can_match_full_path=*/true)) {
     return nullptr;
   }
diff --git a/sandbox/linux/syscall_broker/broker_file_permission.h b/sandbox/linux/syscall_broker/broker_file_permission.h
index f4f3aa0..3538da5 100644
--- a/sandbox/linux/syscall_broker/broker_file_permission.h
+++ b/sandbox/linux/syscall_broker/broker_file_permission.h
@@ -107,6 +107,16 @@
             kBlockInotifyAddWatchWithIntermediates);
   }
 
+  static BrokerFilePermission AllPermissions(const std::string& path) {
+    return BrokerFilePermission(
+        path, RecursionOption::kNonRecursive, PersistenceOption::kPermanent,
+        ReadPermission::kAllowRead, WritePermission::kAllowWrite,
+        CreatePermission::kAllowCreate,
+        StatWithIntermediatesPermission::kAllowStatWithIntermediates,
+        InotifyAddWatchWithIntermediatesPermission::
+            kAllowInotifyAddWatchWithIntermediates);
+  }
+
   static BrokerFilePermission AllPermissionsRecursive(const std::string& path) {
     return BrokerFilePermission(
         path, RecursionOption::kRecursive, PersistenceOption::kPermanent,
diff --git a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
index 8c58e24..978167a 100644
--- a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
@@ -321,6 +321,161 @@
   ASSERT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kPath, kBadMask));
 }
 
+TEST(BrokerFilePermission, AllPermissions) {
+  // `kPath` and `kPathDir` get allowlisted with AllPermissions and
+  // AllPermissionsRecursive, respectively.
+  static constexpr char kPath[] = "/tmp/good";
+  static constexpr char kPathDir[] = "/tmp/good/";
+  static constexpr char kPathFile[] = "/tmp/good/file";
+  static constexpr char kPathFileExtraStuff[] = "/tmp/good/file/extrastuff";
+  static constexpr char kLeading1[] = "/";
+  static constexpr char kLeading2[] = "/tmp";
+  static constexpr char kBadPrefix[] = "/tmp/go";
+  static constexpr char kExtraStuff[] = "/tmp/good_extra_stuff";
+  static constexpr char kExtraStuffFile[] = "/tmp/good_extra_stuff/file";
+  static constexpr char kDoubleSlash[] = "/tmp//good/file";
+  static constexpr char kParentRef[] = "/tmp/good/../file";
+
+  constexpr uint32_t kBadInotifyMask =
+      IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_ONLYDIR;
+  constexpr uint32_t kGoodInotifyMask = kBadInotifyMask | IN_ATTRIB;
+
+  BrokerFilePermission perm =
+      BrokerFilePermission::AllPermissionsRecursive(kPathDir);
+  // Opening and accessing the nested files `kPathFile` and
+  // `kPathFileExtraStuff` should work.
+  EXPECT_TRUE(perm.CheckOpen(kPathFile, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_TRUE(perm.CheckOpen(kPathFile, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_TRUE(perm.CheckAccess(kPathFile, R_OK));
+  EXPECT_TRUE(perm.CheckAccess(kPathFile, W_OK));
+  EXPECT_TRUE(
+      perm.CheckOpen(kPathFileExtraStuff, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_TRUE(
+      perm.CheckOpen(kPathFileExtraStuff, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_TRUE(perm.CheckAccess(kPathFileExtraStuff, R_OK));
+  EXPECT_TRUE(perm.CheckAccess(kPathFileExtraStuff, W_OK));
+  // Opening and accessing anything above the path shouldn't work.
+  EXPECT_FALSE(perm.CheckOpen(kBadPrefix, R_OK).first);
+  EXPECT_FALSE(perm.CheckAccess(kBadPrefix, R_OK));
+  EXPECT_FALSE(perm.CheckOpen(kLeading1, R_OK).first);
+  EXPECT_FALSE(perm.CheckAccess(kLeading1, R_OK));
+  EXPECT_FALSE(perm.CheckOpen(kLeading2, R_OK).first);
+  EXPECT_FALSE(perm.CheckAccess(kLeading2, R_OK));
+  // Stat should work recursively and on intermediates but not on all files.
+  EXPECT_TRUE(perm.CheckStatWithIntermediates(kPathFile));
+  EXPECT_TRUE(perm.CheckStatWithIntermediates(kLeading1));
+  EXPECT_TRUE(perm.CheckStatWithIntermediates(kLeading2));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kBadPrefix));
+  // InotifyAddWatch should work recursively and on intermediates but not on all
+  // files.
+  EXPECT_TRUE(
+      perm.CheckInotifyAddWatchWithIntermediates(kPathFile, kGoodInotifyMask));
+  EXPECT_TRUE(
+      perm.CheckInotifyAddWatchWithIntermediates(kLeading1, kGoodInotifyMask));
+  EXPECT_TRUE(
+      perm.CheckInotifyAddWatchWithIntermediates(kLeading2, kGoodInotifyMask));
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates(kBadPrefix, kGoodInotifyMask));
+  // InotifyAddWatch should still fail without the correct mask.
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates(kPathFile, kBadInotifyMask));
+
+  EXPECT_TRUE(perm.CheckStatWithIntermediates(kPath));
+  EXPECT_TRUE(
+      perm.CheckInotifyAddWatchWithIntermediates(kPath, kGoodInotifyMask));
+  // Empty string should always fail
+  EXPECT_FALSE(perm.CheckOpen("", O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen("", O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess("", R_OK));
+  EXPECT_FALSE(perm.CheckAccess("", W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(""));
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates("", kGoodInotifyMask));
+  // Extra characters on the allowlisted path shouldn't pass:
+  EXPECT_FALSE(perm.CheckOpen(kExtraStuff, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen(kExtraStuff, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuff, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuff, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kExtraStuff));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kExtraStuff,
+                                                          kGoodInotifyMask));
+  // Extra characters and an extra filename on the allowlisted path shouldn't
+  // pass:
+  EXPECT_FALSE(
+      perm.CheckOpen(kExtraStuffFile, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(
+      perm.CheckOpen(kExtraStuffFile, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuffFile, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuffFile, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kExtraStuffFile));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kExtraStuffFile,
+                                                          kGoodInotifyMask));
+  // The sandbox doesn't bother parsing multiple separators in a row:
+  EXPECT_FALSE(perm.CheckOpen(kDoubleSlash, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen(kDoubleSlash, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kDoubleSlash, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kDoubleSlash, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kDoubleSlash));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kDoubleSlash,
+                                                          kGoodInotifyMask));
+  // The sandbox auto-rejects paths with parent references:
+  EXPECT_FALSE(perm.CheckOpen(kParentRef, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen(kParentRef, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kParentRef, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kParentRef, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kParentRef));
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates(kParentRef, kGoodInotifyMask));
+
+  // This permission should allow all access to `kPath` specifically.
+  perm = BrokerFilePermission::AllPermissions(kPath);
+  EXPECT_TRUE(perm.CheckOpen(kPath, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_TRUE(perm.CheckOpen(kPath, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_TRUE(perm.CheckAccess(kPath, R_OK));
+  EXPECT_TRUE(perm.CheckAccess(kPath, W_OK));
+  EXPECT_TRUE(perm.CheckStatWithIntermediates(kPath));
+  EXPECT_TRUE(
+      perm.CheckInotifyAddWatchWithIntermediates(kPath, kGoodInotifyMask));
+  // InotifyAddWatch should still fail without the correct mask.
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates(kPath, kBadInotifyMask));
+  // Empty string should always fail
+  EXPECT_FALSE(perm.CheckOpen("", O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen("", O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess("", R_OK));
+  EXPECT_FALSE(perm.CheckAccess("", W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(""));
+  EXPECT_FALSE(
+      perm.CheckInotifyAddWatchWithIntermediates("", kGoodInotifyMask));
+  // Extra characters on the allowlisted path shouldn't pass:
+  EXPECT_FALSE(perm.CheckOpen(kExtraStuff, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen(kExtraStuff, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuff, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuff, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kExtraStuff));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kExtraStuff,
+                                                          kGoodInotifyMask));
+  // Extra characters and an extra filename on the allowlisted path shouldn't
+  // pass:
+  EXPECT_FALSE(
+      perm.CheckOpen(kExtraStuffFile, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(
+      perm.CheckOpen(kExtraStuffFile, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuffFile, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kExtraStuffFile, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kExtraStuffFile));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kExtraStuffFile,
+                                                          kGoodInotifyMask));
+  // The sandbox doesn't bother parsing multiple separators in a row:
+  EXPECT_FALSE(perm.CheckOpen(kDoubleSlash, O_CREAT | O_EXCL | O_RDONLY).first);
+  EXPECT_FALSE(perm.CheckOpen(kDoubleSlash, O_CREAT | O_EXCL | O_RDWR).first);
+  EXPECT_FALSE(perm.CheckAccess(kDoubleSlash, R_OK));
+  EXPECT_FALSE(perm.CheckAccess(kDoubleSlash, W_OK));
+  EXPECT_FALSE(perm.CheckStatWithIntermediates(kDoubleSlash));
+  EXPECT_FALSE(perm.CheckInotifyAddWatchWithIntermediates(kDoubleSlash,
+                                                          kGoodInotifyMask));
+}
+
 TEST(BrokerFilePermission, ValidatePath) {
   EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path"));
   EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/"));
diff --git a/services/accessibility/BUILD.gn b/services/accessibility/BUILD.gn
index fab0e79d..88463a6 100644
--- a/services/accessibility/BUILD.gn
+++ b/services/accessibility/BUILD.gn
@@ -27,6 +27,15 @@
       "features/automation_internal_bindings.h",
       "features/bindings_isolate_holder.cc",
       "features/bindings_isolate_holder.h",
+      "features/interface_binder.h",
+      "features/mojo/mojo.cc",
+      "features/mojo/mojo.h",
+      "features/mojo/mojo_handle.cc",
+      "features/mojo/mojo_handle.h",
+      "features/mojo/mojo_watch_callback.cc",
+      "features/mojo/mojo_watch_callback.h",
+      "features/mojo/mojo_watcher.cc",
+      "features/mojo/mojo_watcher.h",
       "features/v8_manager.cc",
       "features/v8_manager.h",
       "os_accessibility_service.cc",
@@ -76,7 +85,12 @@
       "features/v8_manager_unittest.cc",
       "os_accessibility_service_unittest.cc",
     ]
-    deps += [ "//ui/accessibility:accessibility" ]
+    deps += [
+      "//base",
+      "//services/accessibility/features/mojo/test:mojom_js_api",
+    ]
+    data_deps =
+        [ "//services/accessibility/features/mojo/test:test_support_data" ]
   } else {
     sources = [ "browser_accessibility_service_unittest.cc" ]
   }
diff --git a/services/accessibility/features/bindings_isolate_holder.cc b/services/accessibility/features/bindings_isolate_holder.cc
index c9f63d15..fc28027 100644
--- a/services/accessibility/features/bindings_isolate_holder.cc
+++ b/services/accessibility/features/bindings_isolate_holder.cc
@@ -28,6 +28,24 @@
                                  gin::ArrayBufferAllocator::SharedInstance());
 }
 
+BindingsIsolateHolder::BindingsIsolateHolder() = default;
+
+BindingsIsolateHolder::~BindingsIsolateHolder() = default;
+
+void BindingsIsolateHolder::AddObserver(IsolateObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void BindingsIsolateHolder::RemoveObserver(IsolateObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void BindingsIsolateHolder::NotifyIsolateWillDestroy() {
+  for (IsolateObserver& obs : observers_) {
+    obs.OnIsolateWillDestroy();
+  }
+}
+
 bool BindingsIsolateHolder::ExecuteScriptInContext(const std::string& script) {
   // Enter isolate scope.
   v8::Isolate::Scope isolate_scope(GetIsolate());
@@ -56,8 +74,8 @@
     }
 
     // Run the script, checking for errors.
-    auto result = compiled->Run(GetContext());
-    if (result.IsEmpty()) {
+    v8::MaybeLocal<v8::Value> maybe_result = compiled->Run(GetContext());
+    if (maybe_result.IsEmpty()) {
       DCHECK(trycatch.HasCaught());
       HandleError(ExceptionToString(trycatch));
       return false;
diff --git a/services/accessibility/features/bindings_isolate_holder.h b/services/accessibility/features/bindings_isolate_holder.h
index 348cdfd9..682c84ce 100644
--- a/services/accessibility/features/bindings_isolate_holder.h
+++ b/services/accessibility/features/bindings_isolate_holder.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_ACCESSIBILITY_FEATURES_BINDINGS_ISOLATE_HOLDER_H_
 #define SERVICES_ACCESSIBILITY_FEATURES_BINDINGS_ISOLATE_HOLDER_H_
 
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "v8/include/v8-context.h"
 #include "v8/include/v8-exception.h"
 #include "v8/include/v8-local-handle.h"
@@ -23,6 +25,26 @@
   // Initializes V8 for the service. May be called from any thread.
   static void InitializeV8();
 
+  // An interface that allows classes to observe when an Isolate will be
+  // destroyed so that they can clean up state.
+  class IsolateObserver : public base::CheckedObserver {
+   public:
+    ~IsolateObserver() override = default;
+    virtual void OnIsolateWillDestroy() = 0;
+  };
+
+  BindingsIsolateHolder();
+  ~BindingsIsolateHolder();
+  BindingsIsolateHolder(const BindingsIsolateHolder&) = delete;
+  BindingsIsolateHolder& operator=(const BindingsIsolateHolder&) = delete;
+
+  void AddObserver(IsolateObserver* observer);
+
+  void RemoveObserver(IsolateObserver* observer);
+
+  // Notifies all the observers that the isolate will be destroyed.
+  void NotifyIsolateWillDestroy();
+
   // Gets the current isolate.
   virtual v8::Isolate* GetIsolate() const = 0;
 
@@ -45,6 +67,8 @@
   // Converts a V8 exception to a human-readable string including
   // line number, if relevant, within the script.
   std::string ExceptionToString(const v8::TryCatch& try_catch);
+
+  base::ObserverList<IsolateObserver> observers_;
 };
 
 }  // namespace ax
diff --git a/services/accessibility/features/interface_binder.h b/services/accessibility/features/interface_binder.h
new file mode 100644
index 0000000..4eb0e39
--- /dev/null
+++ b/services/accessibility/features/interface_binder.h
@@ -0,0 +1,29 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_ACCESSIBILITY_FEATURES_INTERFACE_BINDER_H_
+#define SERVICES_ACCESSIBILITY_FEATURES_INTERFACE_BINDER_H_
+
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
+
+namespace ax {
+
+// Virtual class that can bind to a GenericPendingReceiver to
+// implement one end of a mojo pipe. The V8Manager maps interface names
+// to InterfaceBinders when Mojo in JS receives a GenericPendingReceiver.
+class InterfaceBinder {
+ public:
+  virtual ~InterfaceBinder() = default;
+
+  // Returns true if `interface_name` is the interface for this InterfaceBinder.
+  virtual bool MatchesInterface(const std::string& interface_name) = 0;
+
+  // Binds a GenericPendingReceiver to an implementation for this
+  // interface.
+  virtual void BindReceiver(mojo::GenericPendingReceiver receiver) = 0;
+};
+
+}  // namespace ax
+
+#endif  // SERVICES_ACCESSIBILITY_FEATURES_INTERFACE_BINDER_H_
diff --git a/services/accessibility/features/mojo/mojo.cc b/services/accessibility/features/mojo/mojo.cc
new file mode 100644
index 0000000..a93d6445
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo.cc
@@ -0,0 +1,127 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/accessibility/features/mojo/mojo.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "gin/arguments.h"
+#include "gin/converter.h"
+#include "gin/data_object_builder.h"
+#include "gin/handle.h"
+#include "gin/public/wrapper_info.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/accessibility/features/mojo/mojo_handle.h"
+#include "services/accessibility/features/v8_manager.h"
+#include "v8/include/v8-isolate.h"
+#include "v8/include/v8-local-handle.h"
+#include "v8/include/v8-primitive.h"
+
+namespace ax {
+
+// static
+gin::WrapperInfo Mojo::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+// static
+gin::Handle<Mojo> Mojo::Create(v8::Isolate* isolate) {
+  return gin::CreateHandle(isolate, new Mojo());
+}
+
+gin::ObjectTemplateBuilder Mojo::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<Mojo>::GetObjectTemplateBuilder(isolate)
+      .SetMethod("bindInterface", &Mojo::BindInterface)
+      .SetMethod("createMessagePipe", &Mojo::CreateMessagePipe)
+      .SetValue("RESULT_OK", MOJO_RESULT_OK)
+      .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
+      .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
+      .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
+      .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
+      .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
+      .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
+      .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
+      .SetValue("RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED)
+      .SetValue("RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION)
+      .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
+      .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
+      .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
+      .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
+      .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
+      .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
+      .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
+      .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT);
+}
+
+void Mojo::CreateMessagePipe(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  DCHECK(isolate);
+  v8::HandleScope handle_scope(isolate);
+
+  DCHECK(arguments);
+
+  MojoCreateMessagePipeOptions options = {/*struct_size=*/0};
+  options.struct_size = sizeof(::MojoCreateMessagePipeOptions);
+  options.flags = MOJO_CREATE_MESSAGE_PIPE_FLAG_NONE;
+
+  mojo::ScopedMessagePipeHandle handle0, handle1;
+  MojoResult result = mojo::CreateMessagePipe(&options, &handle0, &handle1);
+
+  // Create a result of the form blink::CreateMessagePipeResult, see
+  // third_party/blink/renderer/core/mojo/mojo_create_message_pipe_result.idl.
+  gin::DataObjectBuilder v8_result_dict(isolate);
+  v8_result_dict.Set("result", result);
+
+  if (result == MOJO_RESULT_OK) {
+    v8_result_dict
+        .Set("handle0", MojoHandle::Create(isolate, mojo::ScopedHandle::From(
+                                                        std::move(handle0))))
+        .Set("handle1", MojoHandle::Create(isolate, mojo::ScopedHandle::From(
+                                                        std::move(handle1))));
+  }
+
+  arguments->Return(v8_result_dict.Build());
+}
+
+void Mojo::BindInterface(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  DCHECK(isolate);
+  v8::HandleScope handle_scope(isolate);
+
+  // The arguments are defined in third_party/blink/renderer/core/mojo/mojo.idl:
+  // static void bindInterface(DOMString interfaceName, MojoHandle
+  // request_handle, optional MojoScope scope = "context"); In this
+  // implementation, the MojoScope is unused.
+  std::vector<v8::Local<v8::Value>> args = arguments->GetAll();
+  v8::Local<v8::String> v8_interface_name = args[0].As<v8::String>();
+  std::string interface_name;
+  gin::ConvertFromV8(isolate, v8_interface_name, &interface_name);
+
+  gin::Handle<MojoHandle> gin_handle;
+  if (!gin::ConvertFromV8(isolate, args[1], &gin_handle)) {
+    LOG(ERROR) << "Failed to get handle from Mojo::BindInterface";
+    return;
+  }
+  auto handle = mojo::ScopedMessagePipeHandle::From(gin_handle->TakeHandle());
+
+  mojo::GenericPendingReceiver receiver(interface_name, std::move(handle));
+
+  // Use the context's global object to get the pointer to the V8 manager in
+  // order to bind this receiver.
+  v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
+  DCHECK(!context.IsEmpty());
+  v8::Local<v8::Object> global_proxy = context->Global();
+  CHECK_LT(V8Manager::kV8ContextWrapperIndex,
+           global_proxy->InternalFieldCount());
+  V8Manager* v8_manager = reinterpret_cast<V8Manager*>(
+      global_proxy->GetAlignedPointerFromInternalField(
+          V8Manager::kV8ContextWrapperIndex));
+
+  CHECK(v8_manager);
+  v8_manager->BindInterface(interface_name, std::move(receiver));
+}
+
+}  // namespace ax
diff --git a/services/accessibility/features/mojo/mojo.h b/services/accessibility/features/mojo/mojo.h
new file mode 100644
index 0000000..3a8a2dba
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo.h
@@ -0,0 +1,60 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_H_
+#define SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_H_
+
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+#include "v8/include/v8-isolate.h"
+
+namespace gin {
+class Arguments;
+}
+
+namespace ax {
+
+// Provides Mojo object to the Accessibility Service's V8 Javascript.
+// This class is a parallel to blink::Mojo, which does the same for
+// any blink renderer.
+class Mojo : public gin::Wrappable<Mojo> {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
+
+  static gin::Handle<Mojo> Create(v8::Isolate* isolate);
+
+  ~Mojo() override = default;
+  Mojo(const Mojo&) = delete;
+  Mojo& operator=(const Mojo&) = delete;
+
+  // gin::Wrappable:
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
+
+  //
+  // Methods exposed to Javascript.
+  // Note: gin::Wrappable's bound methods need to be public.
+  //
+
+  // Returns two MojoHandles, one for each end of a new pipe.
+  // See third_party/blink/renderer/core/mojo/mojo.idl.
+  void CreateMessagePipe(gin::Arguments* arguments);
+
+  // Passes a pipe handle to the AccessibilityService from V8 for someone
+  // to bind it.
+  // See third_party/blink/renderer/core/mojo/mojo.idl.
+  void BindInterface(gin::Arguments* arguments);
+
+  //
+  // End of methods exposed to Javascript.
+  //
+
+ private:
+  Mojo() = default;
+};
+
+}  // namespace ax
+
+#endif  // SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_H_
diff --git a/services/accessibility/features/mojo/mojo_handle.cc b/services/accessibility/features/mojo/mojo_handle.cc
new file mode 100644
index 0000000..9c52cc7
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_handle.cc
@@ -0,0 +1,239 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/accessibility/features/mojo/mojo_handle.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "gin/arguments.h"
+#include "gin/array_buffer.h"
+#include "gin/converter.h"
+#include "gin/data_object_builder.h"
+#include "gin/dictionary.h"
+#include "gin/handle.h"
+#include "gin/public/context_holder.h"
+#include "gin/public/wrapper_info.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/accessibility/features/mojo/mojo_watch_callback.h"
+#include "services/accessibility/features/mojo/mojo_watcher.h"
+#include "v8/include/v8-array-buffer.h"
+#include "v8/include/v8-container.h"
+#include "v8/include/v8-function.h"
+#include "v8/include/v8-isolate.h"
+#include "v8/include/v8-local-handle.h"
+
+namespace ax {
+
+// static
+gin::WrapperInfo MojoHandle::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+// static
+gin::Handle<MojoHandle> MojoHandle::Create(v8::Isolate* isolate,
+                                           mojo::ScopedHandle handle) {
+  return gin::CreateHandle(isolate, new MojoHandle(std::move(handle)));
+}
+
+MojoHandle::~MojoHandle() = default;
+
+gin::ObjectTemplateBuilder MojoHandle::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<MojoHandle>::GetObjectTemplateBuilder(isolate)
+      .SetMethod("watch", &MojoHandle::Watch)
+      .SetMethod("close", &MojoHandle::Close)
+      .SetMethod("readMessage", &MojoHandle::ReadMessage)
+      .SetMethod("writeMessage", &MojoHandle::WriteMessage);
+}
+
+void MojoHandle::Watch(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
+
+  std::vector<v8::Local<v8::Value>> args = arguments->GetAll();
+  DCHECK_EQ(args.size(), 2u);
+
+  // See third_party/blink/renderer/core/mojo/mojo_handle_signals.idl,
+  // which defines the first argument as:
+  // dictionary MojoHandleSignals {
+  //   boolean readable = false;
+  //   boolean writable = false;
+  //   boolean peerClosed = false;
+  // };
+  DCHECK(args[0]->IsObject());
+  gin::Dictionary signals(isolate, args[0].As<v8::Object>());
+  bool readable, writable, peer_closed = false;
+  signals.Get("readable", &readable);
+  signals.Get("writable", &writable);
+  signals.Get("peerClosed", &peer_closed);
+
+  // Now need to extract the MojoWatchCallback from the second
+  // argument, see third_party/blink/renderer/core/mojo/mojo_handle.idl.
+  DCHECK(args[1]->IsFunction());
+  v8::Local<v8::Function> v8_callback = args[1].As<v8::Function>();
+  auto context_holder = std::make_unique<gin::ContextHolder>(isolate);
+  context_holder->SetContext(context);
+  auto callback = std::make_unique<MojoWatchCallback>(std::move(context_holder),
+                                                      v8_callback);
+
+  // Then make a MojoWatcher with the signals and callback, and return it.
+  // The MojoWatcher should start watching when it's created
+  // and call the callback then.
+  arguments->Return(MojoWatcher::Create(isolate, handle_.get(), readable,
+                                        writable, peer_closed,
+                                        std::move(callback)));
+}
+
+void MojoHandle::Close(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::HandleScope handle_scope(isolate);
+  handle_.reset();
+}
+
+void MojoHandle::ReadMessage(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::HandleScope handle_scope(isolate);
+
+  // The result should be formatted as per
+  // third_party/blink/renderer/core/mojo/mojo_read_message_result.idl:
+  // dictionary MojoReadMessageResult {
+  //   required MojoResult result;
+  //   ArrayBuffer buffer;
+  //   sequence<MojoHandle> handles;
+  // };
+  gin::DataObjectBuilder result_dict(isolate);
+
+  mojo::ScopedMessageHandle message;
+  MojoResult result =
+      mojo::ReadMessageNew(mojo::MessagePipeHandle(handle_.get().value()),
+                           &message, MOJO_READ_MESSAGE_FLAG_NONE);
+  if (result != MOJO_RESULT_OK) {
+    result_dict.Set("result", result);
+    arguments->Return(result_dict.Build());
+    return;
+  }
+
+  result = MojoSerializeMessage(message->value(), nullptr);
+  if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) {
+    result_dict.Set("result", MOJO_RESULT_ABORTED);
+    arguments->Return(result_dict.Build());
+    return;
+  }
+
+  uint32_t num_bytes = 0, num_handles = 0;
+  void* bytes = nullptr;
+  std::vector<::MojoHandle> raw_handles;
+  result = MojoGetMessageData(message->value(), /*options=*/nullptr, &bytes,
+                              &num_bytes, nullptr, &num_handles);
+  if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
+    // We don't know how many handles are in a message at first. The first call
+    // retrieves that in num_handles. The second call can then provide adequate
+    // storage for the copies.
+    raw_handles.resize(num_handles);
+    result = MojoGetMessageData(message->value(), /*options=*/nullptr, &bytes,
+                                &num_bytes, raw_handles.data(), &num_handles);
+  }
+
+  if (result != MOJO_RESULT_OK) {
+    result_dict.Set("result", MOJO_RESULT_ABORTED);
+    arguments->Return(result_dict.Build());
+    return;
+  }
+
+  void* buffer =
+      gin::ArrayBufferAllocator::SharedInstance()->Allocate(num_bytes);
+  auto deleter = [](void* buffer, size_t length, void* data) {
+    gin::ArrayBufferAllocator::SharedInstance()->Free(buffer, length);
+  };
+  std::unique_ptr<v8::BackingStore> backing_store =
+      v8::ArrayBuffer::NewBackingStore(buffer, num_bytes, deleter, nullptr);
+
+  v8::Local<v8::ArrayBuffer> array_buffer =
+      v8::ArrayBuffer::New(isolate, std::move(backing_store));
+  if (num_bytes) {
+    CHECK(array_buffer->Data());
+    memcpy(array_buffer->Data(), bytes, num_bytes);
+  }
+  result_dict.Set("buffer", array_buffer);
+
+  std::vector<gin::Handle<MojoHandle>> handles(num_handles);
+  for (uint32_t i = 0; i < num_handles; ++i) {
+    handles[i] = MojoHandle::Create(
+        isolate, mojo::MakeScopedHandle(mojo::Handle(raw_handles[i])));
+  }
+  result_dict.Set("handles", handles);
+
+  result_dict.Set("result", result);
+  arguments->Return(result_dict.Build());
+}
+
+void MojoHandle::WriteMessage(gin::Arguments* arguments) {
+  v8::Isolate* isolate = arguments->isolate();
+  v8::HandleScope handle_scope(isolate);
+
+  // third_party/blink/renderer/core/mojo/mojo_handle.idl defines this
+  // method as:
+  // MojoResult writeMessage(BufferSource buffer, sequence<MojoHandle> handles);
+  std::vector<v8::Local<v8::Value>> args = arguments->GetAll();
+  DCHECK_EQ(args.size(), 2u);
+  DCHECK(args[0]->IsArrayBuffer() || args[0]->IsArrayBufferView());
+  DCHECK(args[1]->IsArray());
+
+  v8::Local<v8::Array> v8_handles = args[1].As<v8::Array>();
+
+  std::vector<gin::Handle<MojoHandle>> handles;
+  if (!gin::ConvertFromV8(isolate, v8_handles, &handles)) {
+    arguments->Return(MOJO_RESULT_INVALID_ARGUMENT);
+    return;
+  }
+
+  std::vector<mojo::ScopedHandle> scoped_handles;
+  scoped_handles.reserve(handles.size());
+  bool has_invalid_handles = false;
+  for (auto& handle : handles) {
+    if (!handle->handle_.is_valid()) {
+      has_invalid_handles = true;
+    } else {
+      scoped_handles.emplace_back(std::move(handle->handle_));
+    }
+  }
+  if (has_invalid_handles) {
+    arguments->Return(MOJO_RESULT_INVALID_ARGUMENT);
+    return;
+  }
+
+  const void* bytes = nullptr;
+  size_t num_bytes = 0;
+  if (args[0]->IsArrayBuffer()) {
+    v8::Local<v8::ArrayBuffer> array = args[0].As<v8::ArrayBuffer>();
+    bytes = array->Data();
+    num_bytes = array->ByteLength();
+  } else {
+    v8::Local<v8::ArrayBufferView> view = args[0].As<v8::ArrayBufferView>();
+    num_bytes = view->ByteLength();
+    void* bites[num_bytes];
+    view->CopyContents(bites, num_bytes);
+    bytes = bites;
+  }
+
+  auto message = mojo::Message(
+      base::make_span(static_cast<const uint8_t*>(bytes), num_bytes),
+      base::make_span(scoped_handles));
+  DCHECK(!message.IsNull());
+  MojoResult result = mojo::WriteMessageNew(
+      mojo::MessagePipeHandle(handle_.get().value()), message.TakeMojoMessage(),
+      MOJO_WRITE_MESSAGE_FLAG_NONE);
+  arguments->Return(result);
+}
+
+mojo::ScopedHandle MojoHandle::TakeHandle() {
+  return std::move(handle_);
+}
+
+MojoHandle::MojoHandle(mojo::ScopedHandle handle)
+    : handle_(std::move(handle)) {}
+
+}  // namespace ax
diff --git a/services/accessibility/features/mojo/mojo_handle.h b/services/accessibility/features/mojo/mojo_handle.h
new file mode 100644
index 0000000..2f20e76e
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_handle.h
@@ -0,0 +1,76 @@
+
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_HANDLE_H_
+#define SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_HANDLE_H_
+
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "v8/include/v8-isolate.h"
+
+namespace gin {
+class Arguments;
+}
+
+namespace ax {
+
+// Provides a MojoHandle object to the Accessibility Service's V8 Javascript.
+// This class is parallel to blink::MojoHandle, which does the same for any
+// blink renderer.
+class MojoHandle : public gin::Wrappable<MojoHandle> {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
+
+  static gin::Handle<MojoHandle> Create(v8::Isolate* isolate,
+                                        mojo::ScopedHandle handle);
+  ~MojoHandle() override;
+  MojoHandle(const MojoHandle&) = delete;
+  MojoHandle& operator=(const MojoHandle&) = delete;
+
+  // gin::Wrappable:
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
+
+  //
+  // Methods exposed to Javascript.
+  // Note: gin::Wrappable's bound methods need to be public.
+  //
+
+  // Calls a callback any time a pipe handle becomes (e.g.) readable; returns a
+  // MojoWatcher.
+  // See third_party/blink/renderer/core/mojo/mojo_handle.idl.
+  void Watch(gin::Arguments* arguments);
+
+  // Closes the handle.
+  // See third_party/blink/renderer/core/mojo/mojo_handle.idl.
+  void Close(gin::Arguments* arguments);
+
+  // Reads the next available message from a pipe (as a raw list of bytes and
+  // handles).
+  // See third_party/blink/renderer/core/mojo/mojo_handle.idl.
+  void ReadMessage(gin::Arguments* arguments);
+
+  // Writes a raw list of bytes and handles into a pipe.
+  // See third_party/blink/renderer/core/mojo/mojo_handle.idl.
+  void WriteMessage(gin::Arguments* arguments);
+
+  //
+  // End of methods exposed to Javascript.
+  //
+
+  // Used by mojo::BindInterface:
+  mojo::ScopedHandle TakeHandle();
+
+ private:
+  explicit MojoHandle(mojo::ScopedHandle handle);
+
+  mojo::ScopedHandle handle_;
+};
+
+}  // namespace ax
+
+#endif  // SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_HANDLE_H_
diff --git a/services/accessibility/features/mojo/mojo_watch_callback.cc b/services/accessibility/features/mojo/mojo_watch_callback.cc
new file mode 100644
index 0000000..2d698eb
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_watch_callback.cc
@@ -0,0 +1,45 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/accessibility/features/mojo/mojo_watch_callback.h"
+
+#include <memory>
+
+#include "gin/public/context_holder.h"
+#include "mojo/public/c/system/types.h"
+#include "v8/include/v8-function.h"
+#include "v8/include/v8-isolate.h"
+#include "v8/include/v8-local-handle.h"
+#include "v8/include/v8-primitive.h"
+
+namespace ax {
+
+MojoWatchCallback::MojoWatchCallback(
+    std::unique_ptr<gin::ContextHolder> context_holder,
+    v8::Local<v8::Function> callback)
+    : context_holder_(std::move(context_holder)),
+      callback_(context_holder_->isolate(), callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+MojoWatchCallback::~MojoWatchCallback() = default;
+
+void MojoWatchCallback::Call(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Enter the isolate, handle, and context scopes in order to call the
+  // callback.
+  v8::Isolate* isolate = context_holder_->isolate();
+  v8::Isolate::Scope isolate_scope(isolate);
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context = context_holder_->context();
+  v8::Context::Scope scope(context);
+
+  v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, result)};
+  callback_.Get(isolate)
+      ->Call(context, context->Global(), 1, args)
+      .ToLocalChecked();
+}
+
+}  // namespace ax
diff --git a/services/accessibility/features/mojo/mojo_watch_callback.h b/services/accessibility/features/mojo/mojo_watch_callback.h
new file mode 100644
index 0000000..8cff58cd
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_watch_callback.h
@@ -0,0 +1,45 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCH_CALLBACK_H_
+#define SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCH_CALLBACK_H_
+
+#include <memory>
+
+#include "base/sequence_checker.h"
+#include "gin/public/context_holder.h"
+#include "mojo/public/c/system/types.h"
+#include "v8/include/v8-function.h"
+#include "v8/include/v8-persistent-handle.h"
+
+namespace ax {
+
+// A class wrapping a v8 function which can execute that function
+// to send a result to Javascript.
+// Similar to blink::V8MojoWatchCallback, defined in
+// third_party/blink/renderer/core/mojo/mojo_handle.idl.
+class MojoWatchCallback {
+ public:
+  MojoWatchCallback(std::unique_ptr<gin::ContextHolder> context_holder,
+                    v8::Local<v8::Function> callback);
+  ~MojoWatchCallback();
+  MojoWatchCallback(const MojoWatchCallback&) = delete;
+  MojoWatchCallback& operator=(const MojoWatchCallback&) = delete;
+
+  // Sends the MojoResult to Javascript by calling the bound callback.
+  void Call(MojoResult result);
+
+ private:
+  std::unique_ptr<gin::ContextHolder> context_holder_;
+
+  // Keep a reference to the callback which ensures the callback will not be
+  // deleted until `this` goes out of scope.
+  v8::Persistent<v8::Function> callback_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace ax
+
+#endif  // SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCH_CALLBACK_H_
\ No newline at end of file
diff --git a/services/accessibility/features/mojo/mojo_watcher.cc b/services/accessibility/features/mojo/mojo_watcher.cc
new file mode 100644
index 0000000..155f2a2
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_watcher.cc
@@ -0,0 +1,394 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/accessibility/features/mojo/mojo_watcher.h"
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/single_thread_task_runner.h"
+#include "gin/arguments.h"
+#include "gin/converter.h"
+#include "gin/handle.h"
+#include "gin/public/wrapper_info.h"
+#include "mojo/public/c/system/trap.h"
+#include "mojo/public/c/system/types.h"
+#include "services/accessibility/features/mojo/mojo_watch_callback.h"
+#include "services/accessibility/features/v8_manager.h"
+#include "v8/include/v8-isolate.h"
+#include "v8/include/v8-local-handle.h"
+
+namespace ax {
+
+// Holds a Persistent to a MojoWatcher V8 object so that the MojoWatcher doesn't
+// get garbage collected before it has finished.
+class MojoWatcher::Persistent
+    : public base::RefCountedDeleteOnSequence<Persistent> {
+ public:
+  Persistent(scoped_refptr<base::SequencedTaskRunner> task_runner,
+             v8::Isolate* isolate,
+             v8::Local<v8::Value> mojo_watcher_obj,
+             MojoWatcher* mojo_watcher);
+  Persistent(const Persistent&) = delete;
+  Persistent& operator=(const Persistent&) = delete;
+
+  // Called by Mojo when there is a new MojoTrapEvent.
+  // Extracts a Persistent pointer from the event and uses
+  // it to RunReadyCallback.
+  // May be called from any thread.
+  static void OnHandleReady(const MojoTrapEvent*);
+
+  // Called by the owning MojoWatcher to request RunReadyCallback
+  // be scheduled in the task queue. Ensures that the MojoWatcher
+  // and `this` object cannot go out of scope until RunReadyCallback
+  // is completed by adding a ref before posting the task, and removing
+  // the ref when running the task.
+  void ScheduleRunReadyCallback(MojoResult result);
+
+  // Called by the owning MojowWatcher when it observes that the Isolate
+  // will be destroyed. This allows this Persistent to release the Isolate
+  // it was holding
+  void OnIsolateWillDestroy();
+
+ private:
+  friend class base::RefCountedDeleteOnSequence<Persistent>;
+  friend class base::DeleteHelper<Persistent>;
+  ~Persistent();
+
+  void RemoveRefAndRunReadyCallback(MojoResult result);
+  void RunReadyCallback(MojoResult result);
+
+  // A v8::Persistent around the MojoWatcher's V8/gin object.
+  v8::Persistent<v8::Value> persistent_;
+
+  // Unowned. This MojoWatcher owns the Persistent.
+  raw_ptr<MojoWatcher> mojo_watcher_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+//                                        //
+// MojoWatcher::Persistent implementation //
+//                                        //
+
+MojoWatcher::Persistent::Persistent(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    v8::Isolate* isolate,
+    v8::Local<v8::Value> mojo_watcher_obj,
+    MojoWatcher* mojo_watcher)
+    : base::RefCountedDeleteOnSequence<MojoWatcher::Persistent>(
+          std::move(task_runner)),
+      persistent_(isolate, mojo_watcher_obj),
+      mojo_watcher_(mojo_watcher) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+MojoWatcher::Persistent::~Persistent() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void MojoWatcher::Persistent::OnIsolateWillDestroy() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  mojo_watcher_ = nullptr;
+}
+
+// static
+void MojoWatcher::Persistent::OnHandleReady(const MojoTrapEvent* event) {
+  // It is safe to assume this MojoWatcher::Persistent still exists, because
+  // we keep it alive until we've dispatched MOJO_RESULT_CANCELLED from here to
+  // RunReadyCallback, and that is always the last notification we'll dispatch.
+  auto* wrap =
+      reinterpret_cast<MojoWatcher::Persistent*>(event->trigger_context);
+
+  // It is safe to use base::Unretained because MojoWatcher, which is in the
+  // v8::Persistent member var, has a ref to `this` Persistent that is not
+  // cleared until MOJO_RESULT_CANCELLED.
+  wrap->owning_task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&MojoWatcher::Persistent::RunReadyCallback,
+                                base::Unretained(wrap), event->result));
+}
+
+void MojoWatcher::Persistent::ScheduleRunReadyCallback(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  AddRef();
+  // Safe to use base::Unretained because this has another
+  // ref that won't be cleared until this method executes.
+  owning_task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&MojoWatcher::Persistent::RemoveRefAndRunReadyCallback,
+                     base::Unretained(this), result));
+}
+
+void MojoWatcher::Persistent::RemoveRefAndRunReadyCallback(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  Release();
+  RunReadyCallback(result);
+}
+
+void MojoWatcher::Persistent::RunReadyCallback(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!mojo_watcher_) {
+    return;
+  }
+  mojo_watcher_->RunReadyCallback(result);
+}
+
+//                            //
+// MojoWatcher implementation //
+//                            //
+
+// static
+gin::WrapperInfo MojoWatcher::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+// static
+v8::Local<v8::Object> MojoWatcher::Create(
+    v8::Isolate* isolate,
+    mojo::Handle handle,
+    bool readable,
+    bool writable,
+    bool peer_closed,
+    std::unique_ptr<MojoWatchCallback> callback) {
+  // Start observing.
+  MojoWatcher* watcher = new MojoWatcher(std::move(callback));
+  MojoResult result =
+      watcher->Watch(handle, readable, writable, peer_closed, isolate);
+
+  gin::Handle<MojoWatcher> mojo_watcher_handle =
+      gin::CreateHandle(isolate, watcher);
+  v8::Local<v8::Object> object = mojo_watcher_handle.ToV8()
+                                     ->ToObject(isolate->GetCurrentContext())
+                                     .ToLocalChecked();
+
+  // TODO(alokp): Consider raising an exception.
+  // Current clients expect to receive the initial error returned by MojoWatch
+  // via watch callback.
+  //
+  // Note that the usage of the Persistent is intentional so that the initial
+  // error is guaranteed to be reported to the client in case where the given
+  // handle is invalid and garbage collection happens before the callback
+  // is scheduled. This will work even if the MojoWatcher's `persistent_wrap_`
+  // was not constructed.
+  if (result != MOJO_RESULT_OK) {
+    v8::Global<v8::Object> global(isolate, object);
+
+    // base::Unretained is safe because MojoWatcher cannot be destroyed until
+    // the persistent `global` of itself is reset.
+    watcher->task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&MojoWatcher::CallCallbackFromTaskRunner,
+                       base::Unretained(watcher), result, std::move(global)));
+  }
+
+  return object;
+}
+
+MojoWatcher::~MojoWatcher() {
+  // It shouldn't be possible to destruct the MojoWatcher while its Persistent
+  // exists.
+  DCHECK(!persistent_wrap_);
+}
+
+void MojoWatcher::OnIsolateWillDestroy() {
+  if (persistent_wrap_) {
+    // May be null if this is during shutdown.
+    persistent_wrap_->OnIsolateWillDestroy();
+  }
+  Cancel(nullptr);
+}
+
+gin::ObjectTemplateBuilder MojoWatcher::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<MojoWatcher>::GetObjectTemplateBuilder(isolate)
+      .SetMethod("cancel", &MojoWatcher::Cancel);
+}
+
+void MojoWatcher::Cancel(gin::Arguments* arguments) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  MojoResult result;
+  if (!trap_handle_.is_valid()) {
+    result = MOJO_RESULT_INVALID_ARGUMENT;
+  } else {
+    trap_handle_.reset();
+    result = MOJO_RESULT_OK;
+  }
+  if (arguments) {
+    arguments->Return(result);
+  }
+
+  // We don't need to clear the persistent_wrap_ here because closing
+  // trap_handle_ will end up with a MOJO_RESULT_CANCELLED coming back in
+  // OnHandleReady.
+}
+
+MojoWatcher::MojoWatcher(std::unique_ptr<MojoWatchCallback> callback)
+    : callback_(std::move(callback)) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Get the current thread (which is the isolate thread).
+  task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
+}
+
+MojoResult MojoWatcher::Watch(mojo::Handle handle,
+                              bool readable,
+                              bool writable,
+                              bool peer_closed,
+                              v8::Isolate* isolate) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  v8::Local<v8::Context> context = isolate->GetCurrentContext();
+  DCHECK(!context.IsEmpty());
+  v8::Local<v8::Object> global_proxy = context->Global();
+  CHECK_LT(V8Manager::kV8ContextWrapperIndex,
+           global_proxy->InternalFieldCount());
+  V8Manager* v8_manager = reinterpret_cast<V8Manager*>(
+      global_proxy->GetAlignedPointerFromInternalField(
+          V8Manager::kV8ContextWrapperIndex));
+  observer_.Observe(v8_manager);
+
+  ::MojoHandleSignals signals = MOJO_HANDLE_SIGNAL_NONE;
+  if (readable) {
+    signals |= MOJO_HANDLE_SIGNAL_READABLE;
+  }
+  if (writable) {
+    signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
+  }
+  if (peer_closed) {
+    signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+  }
+
+  scoped_refptr<MojoWatcher::Persistent> persistent_wrap(
+      new MojoWatcher::Persistent(task_runner_, isolate,
+                                  GetWrapper(isolate).ToLocalChecked(), this));
+
+  MojoResult result =
+      mojo::CreateTrap(&MojoWatcher::Persistent::OnHandleReady, &trap_handle_);
+  DCHECK_EQ(MOJO_RESULT_OK, result);
+
+  result = MojoAddTrigger(trap_handle_.get().value(), handle.value(), signals,
+                          MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+                          reinterpret_cast<uintptr_t>(persistent_wrap.get()),
+                          nullptr);
+  if (result != MOJO_RESULT_OK) {
+    return result;
+  }
+
+  // If MojoAddTrigger succeeded above, we need this object to stay alive at
+  // least until OnHandleReady is invoked with MOJO_RESULT_CANCELLED, which
+  // signals the final invocation by the trap.
+  // Constructs a keep-alive by adding a reference to the Persistent which has
+  // the v8::Persistent to `this`.
+  persistent_wrap_ = persistent_wrap;
+
+  handle_ = handle;
+
+  MojoResult ready_result;
+  result = Arm(&ready_result);
+  if (result == MOJO_RESULT_OK) {
+    return result;
+  }
+
+  if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+    // We couldn't arm the watcher because the handle is already ready to
+    // notify with `ready_result`. Post a notification manually.
+    // Safe to use base::Unretained because the persistent_wrap_ adds another
+    // ref that won't be cleared until this method executes.
+    DCHECK(persistent_wrap_);
+    persistent_wrap->ScheduleRunReadyCallback(ready_result);
+    return MOJO_RESULT_OK;
+  }
+
+  // If MojoAddTrigger succeeds but Arm does not, that means another thread
+  // closed the watched handle in between. Treat it like we'd treat
+  // MojoAddTrigger trying to watch an invalid handle.
+  trap_handle_.reset();
+  return MOJO_RESULT_INVALID_ARGUMENT;
+}
+
+MojoResult MojoWatcher::Arm(MojoResult* ready_result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Nothing to do if the watcher is inactive.
+  if (!handle_.is_valid()) {
+    return MOJO_RESULT_OK;
+  }
+
+  uint32_t num_blocking_events = 1;
+  MojoTrapEvent blocking_event = {sizeof(blocking_event)};
+  MojoResult result = MojoArmTrap(trap_handle_.get().value(), nullptr,
+                                  &num_blocking_events, &blocking_event);
+  if (result == MOJO_RESULT_OK) {
+    return MOJO_RESULT_OK;
+  }
+
+  if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+    DCHECK_EQ(1u, num_blocking_events);
+    DCHECK_EQ(reinterpret_cast<uintptr_t>(this),
+              blocking_event.trigger_context);
+    *ready_result = blocking_event.result;
+    return result;
+  }
+
+  return result;
+}
+
+void MojoWatcher::RunReadyCallback(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (result == MOJO_RESULT_CANCELLED) {
+    // Last notification.
+    handle_ = mojo::Handle();
+
+    // Only dispatch to the callback if this cancellation was implicit due to
+    // |handle_| closure. If it was explicit, |trap_handle_| has already been
+    // reset.
+    if (trap_handle_.is_valid()) {
+      trap_handle_.reset();
+      CallCallbackWithResult(result);
+    }
+
+    // Resetting the Persistent will allow this object to be
+    // garbage collected as usual.
+    persistent_wrap_.reset();
+    return;
+  }
+
+  // Ignore callbacks if not watching.
+  if (!trap_handle_.is_valid()) {
+    return;
+  }
+
+  CallCallbackWithResult(result);
+
+  // The user callback may have canceled watching.
+  if (!trap_handle_.is_valid()) {
+    return;
+  }
+
+  // Rearm the watcher so another notification can fire.
+  MojoResult ready_result;
+  MojoResult arm_result = Arm(&ready_result);
+  if (arm_result == MOJO_RESULT_OK) {
+    return;
+  }
+
+  if (arm_result == MOJO_RESULT_FAILED_PRECONDITION) {
+    DCHECK(persistent_wrap_);
+    persistent_wrap_->ScheduleRunReadyCallback(ready_result);
+    return;
+  }
+}
+
+void MojoWatcher::CallCallbackWithResult(MojoResult result) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  callback_->Call(result);
+}
+
+void MojoWatcher::CallCallbackFromTaskRunner(
+    MojoResult result,
+    v8::Global<v8::Object> self_global) {
+  DCHECK(!self_global.IsEmpty());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  CallCallbackWithResult(result);
+}
+
+}  // namespace ax
diff --git a/services/accessibility/features/mojo/mojo_watcher.h b/services/accessibility/features/mojo/mojo_watcher.h
new file mode 100644
index 0000000..48c4b7d
--- /dev/null
+++ b/services/accessibility/features/mojo/mojo_watcher.h
@@ -0,0 +1,119 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCHER_H_
+#define SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCHER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
+#include "base/task/single_thread_task_runner.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/trap.h"
+#include "services/accessibility/features/bindings_isolate_holder.h"
+#include "v8/include/v8-function-callback.h"
+#include "v8/include/v8-isolate.h"
+#include "v8/include/v8-persistent-handle.h"
+
+namespace gin {
+class Arguments;
+}
+
+namespace ax {
+class MojoWatchCallback;
+
+// Provides MojoWatcher object to the Accessibility Service's V8 Javascript.
+// This class is a parallel to blink::MojoWatcher, which does the same for
+// any blink renderer.
+class MojoWatcher : public gin::Wrappable<MojoWatcher>,
+                    public BindingsIsolateHolder::IsolateObserver {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
+
+  static v8::Local<v8::Object> Create(
+      v8::Isolate* isolate,
+      mojo::Handle handle,
+      bool readable,
+      bool writable,
+      bool peer_closed,
+      std::unique_ptr<MojoWatchCallback> callback);
+
+  ~MojoWatcher() override;
+  MojoWatcher(const MojoWatcher&) = delete;
+  MojoWatcher& operator=(const MojoWatcher&) = delete;
+
+  // BindingsIsolateHolder::IsolateObserver:
+  void OnIsolateWillDestroy() override;
+
+  // gin::Wrappable:
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
+
+  //
+  // Methods exposed to Javascript.
+  // Note: gin::Wrappable's bound methods need to be public.
+  //
+
+  // Stops watching a pipe.
+  // See third_party/blink/renderer/core/mojo/mojo_watcher.idl.
+  void Cancel(gin::Arguments* arguments);
+
+  //
+  // End of methods exposed to Javascript.
+  //
+
+ private:
+  explicit MojoWatcher(std::unique_ptr<MojoWatchCallback> callback);
+
+  MojoResult Watch(mojo::Handle handle,
+                   bool readable,
+                   bool writable,
+                   bool peer_closed,
+                   v8::Isolate* isolate);
+
+  MojoResult Arm(MojoResult* ready_result);
+
+  void RunReadyCallback(MojoResult result);
+
+  void CallCallbackWithResult(MojoResult result);
+
+  // Bound as a posted task from the task runner.
+  // `self_global` is an unused v8::Persistent to this object, and allows this
+  // object to be kept alive by the V8 garbage collector until it goes
+  // out of scope. Passing it here allows the class to avoid garbage collection
+  // until this method is called from a base::OnceCallback where it was bound.
+  void CallCallbackFromTaskRunner(MojoResult result,
+                                  v8::Global<v8::Object> self_global);
+
+  // Keep a Persistent to the v8 object that is represented by this
+  // C++ object; thus |this| can't be destructed before it finishes
+  // calling the callback with MOJO_RESULT_CANCELLED.
+  class Persistent;
+  scoped_refptr<MojoWatcher::Persistent> persistent_wrap_;
+
+  // The task runner upon which to run Javascript.
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // The callback to inform Javascript of a MojoResult.
+  std::unique_ptr<MojoWatchCallback> callback_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
+  mojo::ScopedTrapHandle trap_handle_;
+
+  mojo::Handle handle_;
+
+  base::ScopedObservation<BindingsIsolateHolder,
+                          BindingsIsolateHolder::IsolateObserver>
+      observer_{this};
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<MojoWatcher> weak_ptr_factory_{this};
+};
+
+}  // namespace ax
+
+#endif  // SERVICES_ACCESSIBILITY_FEATURES_MOJO_MOJO_WATCHER_H_
\ No newline at end of file
diff --git a/services/accessibility/features/mojo/test/BUILD.gn b/services/accessibility/features/mojo/test/BUILD.gn
new file mode 100644
index 0000000..33eb6206
--- /dev/null
+++ b/services/accessibility/features/mojo/test/BUILD.gn
@@ -0,0 +1,52 @@
+# Copyright 2023 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/buildflag_header.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom_js_api") {
+  testonly = true
+  sources = [ "test_api.mojom" ]
+  public_deps = [ "//mojo/public/mojom/base" ]
+  webui_module_path = "/"
+}
+
+group("test_support_data") {
+  testonly = true
+  data = [ "$target_gen_dir/mojom_test_support.js" ]
+  deps = [ ":test_support_js" ]
+}
+
+# Based on mojo/public/js/build.gn, this concatinates Javascript files.
+template("concatenate_files") {
+  action(target_name) {
+    script = "//mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py"
+    inputs = invoker.inputs
+    output = "$target_gen_dir/${invoker.output}"
+    outputs = [ output ]
+    args = rebase_path(inputs, root_build_dir) +
+           [ rebase_path(output, root_build_dir) ]
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+}
+
+# Concatinates the mojom JS bindings and generated mojo from test_api.mojom into
+# one file as we haven't yet implemented module loading.
+# TODO(b:262637071): Implement module loading.
+concatenate_files("test_support_js") {
+  inputs = [
+    "shim.js",
+    "$root_gen_dir/mojo/public/js/mojo_bindings_lite.js",
+    "$root_gen_dir/services/accessibility/features/mojo/test/test_api.mojom-lite.js",
+  ]
+
+  deps = [
+    "//mojo/public/js:bindings_lite",
+    "//services/accessibility/features/mojo/test:mojom_js_api_js__generator",
+  ]
+
+  output = "mojom_test_support.js"
+}
diff --git a/services/accessibility/features/mojo/test/OWNERS b/services/accessibility/features/mojo/test/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/services/accessibility/features/mojo/test/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/accessibility/features/mojo/test/shim.js b/services/accessibility/features/mojo/test/shim.js
new file mode 100644
index 0000000..ef8c194
--- /dev/null
+++ b/services/accessibility/features/mojo/test/shim.js
@@ -0,0 +1,14 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The ATP V8 instance does not define 'self', which is needed by mojom.
+let self = this;
+
+// ATP doesn't have console.* yet, so shim these over.
+let console = atpconsole;
+console.assert = (check, message) => {
+  if (!check) {
+    atpconsole.error(message);
+  }
+};
diff --git a/services/accessibility/features/mojo/test/test_api.mojom b/services/accessibility/features/mojo/test/test_api.mojom
new file mode 100644
index 0000000..a8056e4
--- /dev/null
+++ b/services/accessibility/features/mojo/test/test_api.mojom
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines a test API with no other mojom dependencies that can be used to
+// verify the behavior of the Mojom implementation for the Accessibility
+// Service.
+
+module axtest.mojom;
+
+// A structure with some Mojom types.
+// TODO(b:262637071): Support TextEncoder/Decoder and add strings here.
+struct TestStruct {
+  bool is_structy;
+  int32 num;
+};
+
+// An enum type.
+enum TestEnum {
+    kFirst,
+    kSecond,
+    kThird
+};
+
+// A test interface with a method that takes an enum.
+interface TestInterface {
+    // A method that takes an enum.
+    TestMethod(TestEnum num);
+};
+
+// An interface which can allow for binding to the TestInterface
+// and also has methods to signal when the test is completed.
+interface TestBindingInterface {
+    // Returns a PendingReceiver to the TestInterface, which can be used
+    // to receive testMethod calls.
+    AddTestInterface() => (pending_receiver<TestInterface> interface_receiver);
+
+    // Returns a value asynchronously through a callback.
+    GetTestStruct(int32 num) => (TestStruct result);
+
+    // Requests that the TestBindingInterface send the enum to TestInterface,
+    // if bound.
+    SendEnumToTestInterface(TestEnum num);
+
+    // Disconnected the pipe from the TestBindingInterface implementation.
+    Disconnect();
+
+    // Called when the test is complete indicating if the test was successful
+    // or failed.
+    TestComplete(bool success);
+};
\ No newline at end of file
diff --git a/services/accessibility/features/v8_manager.cc b/services/accessibility/features/v8_manager.cc
index 5811d93..e4acd73 100644
--- a/services/accessibility/features/v8_manager.cc
+++ b/services/accessibility/features/v8_manager.cc
@@ -13,12 +13,16 @@
 #include "base/task/thread_pool.h"
 #include "gin/arguments.h"
 #include "gin/array_buffer.h"
+#include "gin/converter.h"
 #include "gin/function_template.h"
 #include "gin/public/context_holder.h"
 #include "gin/public/isolate_holder.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "services/accessibility/assistive_technology_controller_impl.h"
 #include "services/accessibility/features/automation_internal_bindings.h"
+#include "services/accessibility/features/mojo/mojo.h"
 #include "v8/include/v8-context.h"
+#include "v8/include/v8-object.h"
 #include "v8/include/v8-template.h"
 
 namespace ax {
@@ -56,6 +60,9 @@
 }  // namespace
 
 // static
+const int V8Manager::kV8ContextWrapperIndex = 0;
+
+// static
 scoped_refptr<V8Manager> V8Manager::Create() {
   // Create task runner for running V8. The Isolate should only ever be accessed
   // on this thread.
@@ -85,6 +92,8 @@
   if (!isolate_holder_)
     return;
 
+  NotifyIsolateWillDestroy();
+
   isolate_holder_->isolate()->TerminateExecution();
   context_holder_.reset();
   isolate_holder_.reset();
@@ -124,6 +133,25 @@
   return context_holder_->context();
 }
 
+void V8Manager::BindInterface(const std::string& interface_name,
+                              mojo::GenericPendingReceiver pending_receiver) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // TODO(b:262637071): Add mappings for bindings for other C++/JS mojom APIs.
+  if (test_mojo_interface_ &&
+      test_mojo_interface_->MatchesInterface(interface_name)) {
+    test_mojo_interface_->BindReceiver(std::move(pending_receiver));
+    return;
+  }
+  LOG(ERROR) << "Couldn't find remote implementation for interface "
+             << interface_name;
+}
+
+void V8Manager::SetTestMojoInterface(
+    std::unique_ptr<InterfaceBinder> test_interface) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  test_mojo_interface_ = std::move(test_interface);
+}
+
 void V8Manager::ConstructIsolateOnThread() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -141,37 +169,41 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(isolate_holder_) << "V8 has not been started, cannot bind.";
 
+  v8::Isolate* isolate = isolate_holder_->isolate();
+
   // Enter isolate scope.
-  v8::Isolate::Scope isolate_scope(isolate_holder_->isolate());
+  v8::Isolate::Scope isolate_scope(isolate);
 
   // Creates and enters stack-allocated handle scope.
   // All the Local handles (Local<>) in this function will belong to this
   // HandleScope and will be garbage collected when it goes out of scope in this
   // C++ function.
-  v8::HandleScope handle_scope(isolate_holder_->isolate());
+  v8::HandleScope handle_scope(isolate);
 
   // Create a template for the global object where we set the
   // built-in global functions.
   v8::Local<v8::ObjectTemplate> global_template =
-      v8::ObjectTemplate::New(isolate_holder_->isolate());
+      v8::ObjectTemplate::New(isolate);
+  global_template->SetInternalFieldCount(kV8ContextWrapperIndex + 1);
 
   // Create a template for the global "chrome" object.
+  // We add this because APIs are found in the chrome namespace in JS,
+  // like chrome.automation, etc.
   v8::Local<v8::ObjectTemplate> chrome_template =
-      v8::ObjectTemplate::New(isolate_holder_->isolate());
-  global_template->Set(isolate_holder_->isolate(), "chrome", chrome_template);
+      v8::ObjectTemplate::New(isolate);
+  global_template->Set(isolate, "chrome", chrome_template);
 
   // Add automation bindings if needed.
   if (automation_bindings_) {
     v8::Local<v8::ObjectTemplate> automation_template =
-        v8::ObjectTemplate::New(isolate_holder_->isolate());
+        v8::ObjectTemplate::New(isolate);
     automation_bindings_->AddAutomationRoutesToTemplate(&automation_template);
-    chrome_template->Set(isolate_holder_->isolate(), "automation",
-                         automation_template);
+    chrome_template->Set(isolate, "automation", automation_template);
     v8::Local<v8::ObjectTemplate> automation_internal_template =
-        v8::ObjectTemplate::New(isolate_holder_->isolate());
+        v8::ObjectTemplate::New(isolate);
     automation_bindings_->AddAutomationInternalRoutesToTemplate(
         &automation_internal_template);
-    chrome_template->Set(isolate_holder_->isolate(), "automationInternal",
+    chrome_template->Set(isolate, "automationInternal",
                          automation_internal_template);
   }
   // TODO(crbug.com/1355633): Add other API bindings to the global template.
@@ -182,29 +214,38 @@
   // TODO(crbug.com/1355633): Use blink::mojom::DevToolsAgent interface to
   // attach to Chrome devtools and remove these temporary bindings.
   v8::Local<v8::ObjectTemplate> console_template =
-      v8::ObjectTemplate::New(isolate_holder_->isolate());
+      v8::ObjectTemplate::New(isolate);
   console_template->Set(
-      isolate_holder_->isolate(), "log",
-      gin::CreateFunctionTemplate(isolate_holder_->isolate(),
-                                  base::BindRepeating(&ConsoleLog)));
+      isolate, "log",
+      gin::CreateFunctionTemplate(isolate, base::BindRepeating(&ConsoleLog)));
   console_template->Set(
-      isolate_holder_->isolate(), "warn",
-      gin::CreateFunctionTemplate(isolate_holder_->isolate(),
-                                  base::BindRepeating(&ConsoleWarn)));
+      isolate, "warn",
+      gin::CreateFunctionTemplate(isolate, base::BindRepeating(&ConsoleWarn)));
   console_template->Set(
-      isolate_holder_->isolate(), "error",
-      gin::CreateFunctionTemplate(isolate_holder_->isolate(),
-                                  base::BindRepeating(&ConsoleError)));
-  global_template->Set(isolate_holder_->isolate(), "atpconsole",
-                       console_template);
+      isolate, "error",
+      gin::CreateFunctionTemplate(isolate, base::BindRepeating(&ConsoleError)));
+  global_template->Set(isolate, "atpconsole", console_template);
 
   // Add the global template to the current context.
-  v8::Local<v8::Context> context = v8::Context::New(
-      isolate_holder_->isolate(), /*extensions=*/nullptr, global_template);
-  context_holder_ =
-      std::make_unique<gin::ContextHolder>(isolate_holder_->isolate());
+  v8::Local<v8::Context> context =
+      v8::Context::New(isolate, /*extensions=*/nullptr, global_template);
+  context_holder_ = std::make_unique<gin::ContextHolder>(isolate);
   context_holder_->SetContext(context);
 
+  // Make a pointer to `this` in the current context.
+  // This allows Mojo to use the context to find `this` and bind interfaces
+  // on it.
+  v8::Local<v8::Object> global_proxy = context->Global();
+  DCHECK_EQ(kV8ContextWrapperIndex + 1, global_proxy->InternalFieldCount());
+
+  global_proxy->SetAlignedPointerInInternalField(kV8ContextWrapperIndex, this);
+
+  // Create a template for the "Mojo" object in the context scope.
+  v8::Context::Scope context_scope(context);
+  gin::Handle<Mojo> mojo = Mojo::Create(isolate);
+  global_proxy->Set(context, gin::StringToV8(isolate, "Mojo"), mojo.ToV8())
+      .Check();
+
   // TODO(crbug.com/1355633): At this point we could load in API Javascript
   // using ExecuteScript.
 }
diff --git a/services/accessibility/features/v8_manager.h b/services/accessibility/features/v8_manager.h
index 56f22c3..f00190a 100644
--- a/services/accessibility/features/v8_manager.h
+++ b/services/accessibility/features/v8_manager.h
@@ -15,9 +15,12 @@
 #include "base/task/sequenced_task_runner_helpers.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/thread_annotations.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "services/accessibility/features/bindings_isolate_holder.h"
+#include "services/accessibility/features/interface_binder.h"
 #include "v8/include/v8-context.h"
 #include "v8/include/v8-local-handle.h"
+#include "v8/include/v8-value.h"
 
 namespace v8 {
 class Isolate;
@@ -43,6 +46,11 @@
 class V8Manager : public BindingsIsolateHolder,
                   public base::RefCountedDeleteOnSequence<V8Manager> {
  public:
+  // The index into the global template's internal fields that
+  // stores a pointer to this V8Manager. This allows any class with
+  // a v8::Context to access this V8Manager.
+  static const int kV8ContextWrapperIndex;
+
   // Creates a new V8Manager with its own isolate and context.
   static scoped_refptr<V8Manager> Create();
 
@@ -65,8 +73,16 @@
   v8::Isolate* GetIsolate() const override;
   v8::Local<v8::Context> GetContext() const override;
 
+  // Called from the V8 thread by Mojo when ready to bind an interface.
+  void BindInterface(const std::string& interface_name,
+                     mojo::GenericPendingReceiver pending_receiver);
+
+  // Sets the InterfaceBinder used for when trying to bind
+  // axtest.mojom.TestBindingInterface. Used for testing.
+  void SetTestMojoInterface(std::unique_ptr<InterfaceBinder> test_interface);
+
  private:
-  // Allows RefCountedDeleteOnSequence able access to the destructor.
+  // Allows RefCountedDeleteOnSequence access to the destructor.
   friend class base::RefCountedDeleteOnSequence<V8Manager>;
   friend class base::DeleteHelper<V8Manager>;
 
@@ -95,6 +111,10 @@
   std::unique_ptr<AutomationInternalBindings> automation_bindings_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
+  // Bindings wrappers for test.
+  std::unique_ptr<InterfaceBinder> test_mojo_interface_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
   // Holders for isolate and context.
   // These may only be accessed from the v8_runner_ thread.
   std::unique_ptr<gin::IsolateHolder> isolate_holder_
diff --git a/services/accessibility/features/v8_manager_unittest.cc b/services/accessibility/features/v8_manager_unittest.cc
index 35c1288..34f5c561 100644
--- a/services/accessibility/features/v8_manager_unittest.cc
+++ b/services/accessibility/features/v8_manager_unittest.cc
@@ -4,12 +4,84 @@
 
 #include "services/accessibility/features/v8_manager.h"
 
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/accessibility/features/mojo/test/test_api.mojom.h"
 #include "services/accessibility/public/mojom/accessibility_service.mojom-shared.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "v8_manager.h"
 
 namespace ax {
 
+// C++ implementation of the TestBindingInterface. The other end of the pipe is
+// held in Javascript.
+class TestBindingInterfaceImpl : public axtest::mojom::TestBindingInterface,
+                                 public InterfaceBinder {
+ public:
+  explicit TestBindingInterfaceImpl(base::OnceCallback<void(bool)> on_complete)
+      : on_complete_(std::move(on_complete)), receiver_(this) {}
+  ~TestBindingInterfaceImpl() override = default;
+  TestBindingInterfaceImpl& operator=(const TestBindingInterfaceImpl&) = delete;
+  TestBindingInterfaceImpl(const TestBindingInterfaceImpl&) = delete;
+
+  // InterfaceBinder overrides:
+  void BindReceiver(mojo::GenericPendingReceiver pending_receiver) override {
+    auto receiver = pending_receiver.As<axtest::mojom::TestBindingInterface>();
+    receiver_.Bind(std::move(receiver));
+    receiver_.set_disconnect_handler(base::BindLambdaForTesting(
+        [this]() { std::move(on_complete_).Run(false); }));
+  }
+
+  bool MatchesInterface(const std::string& interface_name) override {
+    return interface_name == "axtest.mojom.TestBindingInterface";
+  }
+
+  // axtest::mojom::TestBindingInterface overrides:
+  void AddTestInterface(AddTestInterfaceCallback callback) override {
+    int index = test_interface_receivers_.size();
+    test_interface_receivers_.emplace_back();
+    auto pending_receiver =
+        test_interface_receivers_[index].BindNewPipeAndPassReceiver();
+    std::move(callback).Run(std::move(pending_receiver));
+  }
+
+  void GetTestStruct(int num, GetTestStructCallback callback) override {
+    auto result = axtest::mojom::TestStruct::New();
+    result->is_structy = true;
+    result->num = num + 1;
+    std::move(callback).Run(std::move(result));
+  }
+
+  void SendEnumToTestInterface(axtest::mojom::TestEnum num) override {
+    for (auto& receiver : test_interface_receivers_) {
+      receiver->TestMethod(num);
+    }
+  }
+
+  void Disconnect() override { receiver_.reset(); }
+
+  void TestComplete(bool success) override {
+    std::move(on_complete_).Run(success);
+  }
+
+ private:
+  base::OnceCallback<void(bool)> on_complete_;
+  mojo::Receiver<axtest::mojom::TestBindingInterface> receiver_;
+  std::vector<mojo::Remote<axtest::mojom::TestInterface>>
+      test_interface_receivers_;
+};
+
 class V8ManagerTest : public testing::Test {
  public:
   V8ManagerTest() = default;
@@ -19,10 +91,43 @@
 
   void SetUp() override { BindingsIsolateHolder::InitializeV8(); }
 
+  std::string GetMojoTestSupportJS() {
+    base::FilePath gen_test_data_root;
+    base::PathService::Get(base::DIR_GEN_TEST_DATA_ROOT, &gen_test_data_root);
+    base::FilePath source_path = gen_test_data_root.Append(FILE_PATH_LITERAL(
+        "gen/services/accessibility/features/mojo/test/mojom_test_support.js"));
+    std::string script;
+    EXPECT_TRUE(ReadFileToString(source_path, &script));
+    return script;
+  }
+
+  void RunJSMojoTest(const std::string& js_script) {
+    base::RunLoop waiter;
+    std::unique_ptr<TestBindingInterfaceImpl> test_interface =
+        std::make_unique<TestBindingInterfaceImpl>(
+            base::BindLambdaForTesting([&waiter](bool success) {
+              EXPECT_TRUE(success) << "Mojo JS was not successful";
+              waiter.Quit();
+            }));
+    scoped_refptr<V8Manager> manager = V8Manager::Create();
+    manager->SetTestMojoInterface(std::move(test_interface));
+    manager->AddV8Bindings();
+
+    base::RunLoop script_waiter;
+    manager->ExecuteScript(GetMojoTestSupportJS(), script_waiter.QuitClosure());
+    // Wait for the script to be executed.
+    script_waiter.Run();
+
+    manager->ExecuteScript(js_script, base::DoNothing());
+    // Wait for the test mojom API testComplete method.
+    waiter.Run();
+  }
+
  private:
   base::test::TaskEnvironment task_environment_;
 };
 
+// Test to execute Javascript that doesn't involve Mojo.
 TEST_F(V8ManagerTest, ExecutesSimpleScript) {
   scoped_refptr<V8Manager> manager = V8Manager::Create();
   manager->AddV8Bindings();
@@ -33,10 +138,206 @@
     const d = 22;
     var m = 1;
     let y = 1973;
+    // By checking there's no error here, we know that V8 bindings
+    // can be installed on the context.
     atpconsole.log('Green is the loneliest color');
   )JS",
                          script_waiter.QuitClosure());
   script_waiter.Run();
 }
 
+// Test that we can do a simple mojom connection. This test will time out
+// if the JS remote is not bound to the test_interface.
+// TODO(b:262637071) Fails on Fuchsia due to ReadFileToString failing.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_SanityCheckMojoBindings DISABLED_SanityCheckMojoBindings
+#else
+#define MAYBE_SanityCheckMojoBindings SanityCheckMojoBindings
+#endif  // BUILDFLAG(IS_FUCHSIA)
+TEST_F(V8ManagerTest, MAYBE_SanityCheckMojoBindings) {
+  RunJSMojoTest(R"JS(
+    const TestBindingInterface = axtest.mojom.TestBindingInterface;
+    const remote = TestBindingInterface.getRemote();
+    remote.testComplete(/*success=*/true);)JS");
+}
+
+// Test that Mojo constants are defined.
+// TODO(b:262637071) Fails on Fuchsia due to ReadFileToString failing.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_CheckMojoConstants DISABLED_CheckMojoConstants
+#else
+#define MAYBE_CheckMojoConstants CheckMojoConstants
+#endif  // BUILDFLAG(IS_FUCHSIA)
+TEST_F(V8ManagerTest, MAYBE_CheckMojoConstants) {
+  base::RunLoop waiter;
+  std::unique_ptr<TestBindingInterfaceImpl> test_interface =
+      std::make_unique<TestBindingInterfaceImpl>(
+          base::BindLambdaForTesting([&waiter](bool success) {
+            EXPECT_TRUE(success) << "Mojo JS was not successful";
+            waiter.Quit();
+          }));
+  scoped_refptr<V8Manager> manager = V8Manager::Create();
+  manager->SetTestMojoInterface(std::move(test_interface));
+  manager->AddV8Bindings();
+
+  base::RunLoop script_waiter;
+  manager->ExecuteScript(GetMojoTestSupportJS(), script_waiter.QuitClosure());
+  // Wait for the script to be executed.
+  script_waiter.Run();
+
+  struct TestCase {
+    std::string name;
+    MojoResult value;
+  };
+  const TestCase kTestCases[] = {
+      {"RESULT_OK", MOJO_RESULT_OK},
+      {"RESULT_CANCELLED", MOJO_RESULT_CANCELLED},
+      {"RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN},
+      {"RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT},
+      {"RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED},
+      {"RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND},
+      {"RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS},
+      {"RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED},
+      {"RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED},
+      {"RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION},
+      {"RESULT_ABORTED", MOJO_RESULT_ABORTED},
+      {"RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE},
+      {"RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED},
+      {"RESULT_INTERNAL", MOJO_RESULT_INTERNAL},
+      {"RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE},
+      {"RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS},
+      {"RESULT_BUSY", MOJO_RESULT_BUSY},
+      {"RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT},
+  };
+  uint32_t index = 0;
+  for (auto test : kTestCases) {
+    // Make sure the test doesn't skip any MojoResult.
+    EXPECT_EQ(test.value, index);
+    index++;
+
+    // This will call testComplete(false) if an enum value is missing.
+    const std::string script =
+        base::StringPrintf(R"JS(
+      if (Mojo.%s !== %i) {
+        TestBindingInterface.getRemote().testComplete(/*success=*/false);
+      }
+      )JS",
+                           test.name.c_str(), test.value);
+    base::RunLoop test_waiter;
+    manager->ExecuteScript(script, test_waiter.QuitClosure());
+    test_waiter.Run();
+  }
+}
+
+// Test to load Mojo bindings and test that an asynchronous callback from JS
+// to the remote interface in C++ returns the expected value.
+// TODO(b:262637071) Fails on Fuchsia due to ReadFileToString failing.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_MojoBindingsGetsCallback DISABLED_MojoBindingsGetsCallback
+#else
+#define MAYBE_MojoBindingsGetsCallback MojoBindingsGetsCallback
+#endif  // BUILDFLAG(IS_FUCHSIA)
+TEST_F(V8ManagerTest, MAYBE_MojoBindingsGetsCallback) {
+  RunJSMojoTest(R"JS(
+    class TestWrapper {
+      constructor() {
+        const TestBindingInterface = axtest.mojom.TestBindingInterface;
+        this.remote_ = TestBindingInterface.getRemote();
+        this.remote_.onConnectionError.addListener(() => {
+            console.error('Connection error');
+            this.remote_.testComplete(/*success=*/false);
+        });
+        this.init_();
+      }
+
+      async init_() {
+        const response = await this.remote_.getTestStruct(41);
+        // Expect the result struct to have the number passed in plus 1.
+        if (response.result.isStructy && response.result.num === 42) {
+          this.remote_.testComplete(/*success=*/true);
+        } else {
+          this.remote_.testComplete(/*success=*/false);
+        }
+      }
+    };
+    new TestWrapper();)JS");
+}
+
+// Test to see that a PendingReceiver can be send from C++ to
+// be bound in Javascript and that it can receive calls from C++.
+// TODO(b:262637071) Fails on Fuchsia due to ReadFileToString failing.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_MojoBindingsPendingReceiver DISABLED_MojoBindingsPendingReceiver
+#else
+#define MAYBE_MojoBindingsPendingReceiver MojoBindingsPendingReceiver
+#endif  // BUILDFLAG(IS_FUCHSIA)
+TEST_F(V8ManagerTest, MAYBE_MojoBindingsPendingReceiver) {
+  RunJSMojoTest(R"JS(
+    class TestReceiver {
+      constructor(pendingReceiver, callback) {
+        this.callback_ = callback;
+        this.receiver_ = new axtest.mojom.TestInterfaceReceiver(this);
+        this.receiver_.$.bindHandle(pendingReceiver.handle);
+      }
+
+      /** @override */
+      testMethod(num) {
+        this.callback_(num);
+      }
+    };
+
+    class TestWrapper {
+      constructor() {
+        const TestBindingInterface = axtest.mojom.TestBindingInterface;
+        this.remote_ = TestBindingInterface.getRemote();
+        this.remote_.onConnectionError.addListener(() => {
+            console.error('Connection error');
+            this.remote_.testComplete(/*success=*/false);
+        });
+        this.init_();
+      }
+
+      async init_() {
+        let pendingReceiver =
+            (await this.remote_.addTestInterface()).interfaceReceiver;
+        const receiver = new TestReceiver(pendingReceiver, (num) => {
+          if (num == axtest.mojom.TestEnum.kThird) {
+            this.remote_.testComplete(/*success=*/true);
+          } else {
+            this.remote_.testComplete(/*success=*/false);
+          }
+        });
+        await this.remote_.sendEnumToTestInterface(
+            axtest.mojom.TestEnum.kThird);
+      }
+    };
+    new TestWrapper();
+  )JS");
+}
+
+// Test to load Mojo bindings and then disconnect.
+// TODO(b:262637071) Fails on Fuchsia due to ReadFileToString failing.
+#if BUILDFLAG(IS_FUCHSIA)
+#define MAYBE_MojoCancelBindings DISABLED_MojoCancelBindings
+#else
+#define MAYBE_MojoCancelBindings MojoCancelBindings
+#endif  // BUILDFLAG(IS_FUCHSIA)
+TEST_F(V8ManagerTest, MAYBE_MojoCancelBindings) {
+  RunJSMojoTest(R"JS(
+    class TestWrapper {
+      constructor() {
+        const TestBindingInterface = axtest.mojom.TestBindingInterface;
+        this.remote_ = TestBindingInterface.getRemote();
+        this.remote_.onConnectionError.addListener(() => {
+            this.remote_ = TestBindingInterface.getRemote();
+            this.remote_.testComplete(true);
+        });
+        // Disconnecting from C++ will cause onConnectionError to be
+        // called, which is the plumbing we're testing here.
+        this.remote_.disconnect();
+      }
+    };
+    new TestWrapper();)JS");
+}
+
 }  // namespace ax
diff --git a/services/network/network_sandbox_hook_linux.cc b/services/network/network_sandbox_hook_linux.cc
index 47f5667..25c6bd67 100644
--- a/services/network/network_sandbox_hook_linux.cc
+++ b/services/network/network_sandbox_hook_linux.cc
@@ -28,7 +28,8 @@
 }
 
 std::vector<BrokerFilePermission> GetNetworkFilePermissions() {
-  return {BrokerFilePermission::AllPermissionsRecursive("/")};
+  return {BrokerFilePermission::AllPermissions("/"),
+          BrokerFilePermission::AllPermissionsRecursive("/")};
 }
 
 bool NetworkPreSandboxHook(sandbox::policy::SandboxLinux::Options options) {
diff --git a/services/network/public/mojom/url_loader_network_service_observer.mojom b/services/network/public/mojom/url_loader_network_service_observer.mojom
index e2a7c7e..77e4b6e3 100644
--- a/services/network/public/mojom/url_loader_network_service_observer.mojom
+++ b/services/network/public/mojom/url_loader_network_service_observer.mojom
@@ -81,7 +81,7 @@
 // of authentication and certificate events. This is typically implemented
 // by a trusted process such as the browser process.
 interface URLLoaderNetworkServiceObserver {
-  // Called when an SSL certificate is encountered.
+  // Called when an SSL certificate error is encountered.
   // The callback argument is a net::ERROR value. If it's net::OK, then the
   // request is resumed. Otherwise it's cancelled with the given error.
   OnSSLCertificateError(url.mojom.Url url,
diff --git a/services/network/tls_socket_factory.h b/services/network/tls_socket_factory.h
index 8e87642..a00ca63 100644
--- a/services/network/tls_socket_factory.h
+++ b/services/network/tls_socket_factory.h
@@ -80,12 +80,13 @@
       mojom::TCPConnectedSocket::UpgradeToTLSCallback callback);
 
   // The following are used when |unsafely_skip_cert_verification| is specified
-  // in upgrade options.
-  std::unique_ptr<net::SSLClientContext> no_verification_ssl_client_context_;
+  // in upgrade options. The SSLClientContext must be last so that it does not
+  // outlive its input parameters.
   std::unique_ptr<net::CertVerifier> no_verification_cert_verifier_;
   std::unique_ptr<net::TransportSecurityState>
       no_verification_transport_security_state_;
   std::unique_ptr<net::CTPolicyEnforcer> no_verification_ct_policy_enforcer_;
+  std::unique_ptr<net::SSLClientContext> no_verification_ssl_client_context_;
 
   net::SSLClientContext ssl_client_context_;
   raw_ptr<net::ClientSocketFactory> client_socket_factory_;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8174cde..08198f24 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8090,6 +8090,27 @@
             ]
         }
     ],
+    "NetworkServiceSandboxLinuxAndChromeOS": [
+        {
+            "platforms": [
+                "linux",
+                "chromeos",
+                "chromeos_lacros"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NetworkServiceSandbox"
+                    ],
+                    "disable_features": [
+                        "NetworkServiceFileAllowlist",
+                        "NetworkServiceSyscallFilter"
+                    ]
+                }
+            ]
+        }
+    ],
     "NeuralPalmRejectionModelForRedrix": [
         {
             "platforms": [
@@ -9602,7 +9623,7 @@
                         "IPH_BatterySaverMode_session_rate": "==0",
                         "IPH_HighEfficiencyMode_availability": "any",
                         "IPH_HighEfficiencyMode_event_1": "name:high_efficiency_prompt_in_trigger;comparator:<3;window:360;storage:360",
-                        "IPH_HighEfficiencyMode_event_trigger": "name:high_efficiency_prompt_in_trigger;comparator:<1;window:1;storage:360",
+                        "IPH_HighEfficiencyMode_event_trigger": "name:high_efficiency_prompt_in_trigger;comparator:<1;window:7;storage:360",
                         "IPH_HighEfficiencyMode_event_used": "name:high_efficiency_prompt_in_used;comparator:==0;window:360;storage:360",
                         "IPH_HighEfficiencyMode_session_rate": "any",
                         "IPH_PerformanceNewBadge_availability": "any",
@@ -13208,21 +13229,6 @@
             ]
         }
     ],
-    "UseThreadQoSMac": [
-        {
-            "platforms": [
-                "mac"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "UseThreadQoSMac"
-                    ]
-                }
-            ]
-        }
-    ],
     "UserAgentOverrideExperiment": [
         {
             "platforms": [
diff --git a/third_party/blink/common/rust_crash/BUILD.gn b/third_party/blink/common/rust_crash/BUILD.gn
index 09c17d2a..3e39aca5 100644
--- a/third_party/blink/common/rust_crash/BUILD.gn
+++ b/third_party/blink/common/rust_crash/BUILD.gn
@@ -24,6 +24,7 @@
 rust_static_library("rs") {
   sources = [ "src/lib.rs" ]
   cxx_bindings = [ "src/lib.rs" ]
+  allow_unsafe = true
   if (is_asan) {
     features = [ "rust_crash_asan_enabled" ]
   }
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 a36fa99..18690c3 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
@@ -51,7 +51,6 @@
 #include "third_party/blink/renderer/core/css/style_color.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h"
 #include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -1712,8 +1711,7 @@
   const Vector<GridTrackSize, 1>& auto_repeat_track_sizes =
       computed_grid_track_list.auto_repeat_track_sizes;
 
-  const bool is_layout_grid =
-      layout_object && layout_object->IsLayoutGridIncludingNG();
+  const bool is_layout_grid = layout_object && layout_object->IsLayoutNGGrid();
 
   // Handle the 'none' case.
   bool is_track_list_empty =
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 74c0286..bacf892d 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -3866,7 +3866,7 @@
 
 bool GridTemplateColumns::IsLayoutDependent(const ComputedStyle* style,
                                             LayoutObject* layout_object) const {
-  return layout_object && layout_object->IsLayoutGridIncludingNG();
+  return layout_object && layout_object->IsLayoutNGGrid();
 }
 
 const CSSValue* GridTemplateColumns::CSSValueFromComputedStyleInternal(
@@ -3890,7 +3890,7 @@
 
 bool GridTemplateRows::IsLayoutDependent(const ComputedStyle* style,
                                          LayoutObject* layout_object) const {
-  return layout_object && layout_object->IsLayoutGridIncludingNG();
+  return layout_object && layout_object->IsLayoutNGGrid();
 }
 
 const CSSValue* GridTemplateRows::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index dffd08d4..5225eaf 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -2181,7 +2181,7 @@
 
 bool Grid::IsLayoutDependent(const ComputedStyle* style,
                              LayoutObject* layout_object) const {
-  return layout_object && layout_object->IsLayoutGridIncludingNG();
+  return layout_object && layout_object->IsLayoutNGGrid();
 }
 
 const CSSValue* Grid::CSSValueFromComputedStyleInternal(
@@ -2324,7 +2324,7 @@
 
 bool GridTemplate::IsLayoutDependent(const ComputedStyle* style,
                                      LayoutObject* layout_object) const {
-  return layout_object && layout_object->IsLayoutGridIncludingNG();
+  return layout_object && layout_object->IsLayoutNGGrid();
 }
 
 const CSSValue* GridTemplate::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index a9f0eb2..5b89f88 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -499,24 +499,17 @@
 bool ElementIsDescendantOfShadowIncludingAncestor(
     const Element& attribute_element,
     const Element& candidate) {
-  // TODO(meredithl): Update this to allow setting relationships for elements
-  // outside of the DOM once the spec is finalized. For consistency and
-  // simplicity, for now it is disallowed.
-  if (!attribute_element.IsInTreeScope() || !candidate.IsInTreeScope()) {
-    return false;
-  }
-  ShadowRoot* nearest_root = attribute_element.ContainingShadowRoot();
-  const Element* shadow_host = &attribute_element;
-  while (nearest_root) {
-    shadow_host = &nearest_root->host();
-    if (candidate.IsDescendantOf(nearest_root)) {
+  auto* candidate_root = &candidate.TreeRoot();
+  auto* element_root = &attribute_element.TreeRoot();
+  while (true) {
+    if (candidate_root == element_root) {
       return true;
     }
-    nearest_root = shadow_host->ContainingShadowRoot();
+    if (!element_root->IsInShadowTree()) {
+      return false;
+    }
+    element_root = &element_root->OwnerShadowHost()->TreeRoot();
   }
-
-  Element* document_element = shadow_host->GetDocument().documentElement();
-  return candidate.IsDescendantOf(document_element);
 }
 
 // The first algorithm in
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index b51ad11..0a257ca 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -194,7 +194,7 @@
       return nullptr;
     } else if (first_letter_text_layout_object
                    ->IsFlexibleBoxIncludingDeprecatedAndNG() ||
-               first_letter_text_layout_object->IsLayoutGridIncludingNG()) {
+               first_letter_text_layout_object->IsLayoutNGGrid()) {
       first_letter_text_layout_object =
           first_letter_text_layout_object->NextSibling();
     } else if (!first_letter_text_layout_object->IsInline() &&
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc
index 53ddcac2..34592d8 100644
--- a/third_party/blink/renderer/core/dom/text.cc
+++ b/third_party/blink/renderer/core/dom/text.cc
@@ -263,7 +263,7 @@
 
   if (parent.IsTable() || parent.IsTableRow() || parent.IsTableSection() ||
       parent.IsLayoutTableCol() || parent.IsFrameSetIncludingNG() ||
-      parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutGridIncludingNG() ||
+      parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutNGGrid() ||
       parent.IsSVGRoot() || parent.IsSVGContainer() || parent.IsSVGImage() ||
       parent.IsSVGShape()) {
     if (!context.use_previous_in_flow || !context.previous_in_flow ||
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 417b757c..8c145f41 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -1075,7 +1075,7 @@
 
   if (layout_object->IsLayoutBlockFlow() ||
       layout_object->IsFlexibleBoxIncludingNG() ||
-      layout_object->IsLayoutGridIncludingNG()) {
+      layout_object->IsLayoutNGGrid()) {
     if (To<LayoutBlock>(layout_object)->LogicalHeight() ||
         anchor_node->GetDocument().body() == anchor_node) {
       if (!HasRenderedNonAnonymousDescendantsWithHeight(layout_object))
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 167ed28d..ddfed2de 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1456,9 +1456,9 @@
   DCHECK(To<LayoutBox>(root).IsOrthogonalWritingModeRoot());
   if (!root.NeedsLayout() || root.IsOutOfFlowPositioned() ||
       root.IsColumnSpanAll() || root.StyleRef().LogicalHeight().IsSpecified() ||
-      To<LayoutBox>(root).IsGridItem() || root.IsTablePart() ||
-      root.IsLayoutFlowThread())
+      root.IsTablePart() || root.IsLayoutFlowThread()) {
     return false;
+  }
 
   // Do not pre-layout objects that are fully managed by LayoutNG; it is not
   // necessary and may lead to double layouts. We do need to pre-layout objects
diff --git a/third_party/blink/renderer/core/html/resources/selectmenu.css b/third_party/blink/renderer/core/html/resources/selectmenu.css
index 99ac34c5..815ceb9a 100644
--- a/third_party/blink/renderer/core/html/resources/selectmenu.css
+++ b/third_party/blink/renderer/core/html/resources/selectmenu.css
@@ -11,6 +11,7 @@
 
 selectmenu {
   display: inline-block;
+  user-select: none;
 }
 
 selectmenu::-internal-selectmenu-button {
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 10859e7..df8f440 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -890,9 +890,7 @@
                                                           source_capabilities);
   }
 
-  if ((!RuntimeEnabledFeatures::MouseSubframeNoImplicitCaptureEnabled() &&
-       event_result == WebInputEventResult::kNotHandled) ||
-      mev.GetScrollbar()) {
+  if (event_result == WebInputEventResult::kNotHandled || mev.GetScrollbar()) {
     mouse_event_manager_->SetCapturesDragging(true);
     // Outermost main frames don't implicitly capture mouse input on MouseDown,
     // all subframes do (regardless of whether local or remote or fenced).
@@ -1447,28 +1445,6 @@
 
   if (captured && pointer_id == PointerEventFactory::kMouseId) {
     CaptureMouseEventsToWidget(true);
-
-    // TODO(crbug.com/919908) This is a temporary approach to make pointer
-    // capture work across in-process frames while mouse subframe capture
-    // disabled. It's to experiment removing the frame capture logic. This
-    // must be re-write before the flag enabled.
-    if (RuntimeEnabledFeatures::MouseSubframeNoImplicitCaptureEnabled()) {
-      LocalFrame* frame = frame_;
-      LocalFrame* parent = DynamicTo<LocalFrame>(frame_->Tree().Parent());
-      while (parent) {
-        Element* subframe_element = nullptr;
-        if (frame->OwnerLayoutObject() &&
-            frame->OwnerLayoutObject()->GetNode()) {
-          subframe_element =
-              DynamicTo<Element>(frame->OwnerLayoutObject()->GetNode());
-        }
-
-        parent->GetEventHandler().capturing_subframe_element_ =
-            subframe_element;
-        frame = parent;
-        parent = DynamicTo<LocalFrame>(parent->Tree().Parent());
-      }
-    }
   }
 }
 
@@ -1483,17 +1459,6 @@
 
   if (released && pointer_id == PointerEventFactory::kMouseId) {
     CaptureMouseEventsToWidget(false);
-
-    // TODO(crbug/919908) same as SetPointerCapture, this is temporary
-    // approach for removing mouse subframe capture. It must be re-write
-    // before enable the flag.
-    if (RuntimeEnabledFeatures::MouseSubframeNoImplicitCaptureEnabled()) {
-      LocalFrame* parent = DynamicTo<LocalFrame>(frame_->Tree().Parent());
-      while (parent) {
-        parent->GetEventHandler().capturing_subframe_element_ = nullptr;
-        parent = DynamicTo<LocalFrame>(parent->Tree().Parent());
-      }
-    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/input/event_handler_test.cc b/third_party/blink/renderer/core/input/event_handler_test.cc
index bbb784c..2cfc7e100 100644
--- a/third_party/blink/renderer/core/input/event_handler_test.cc
+++ b/third_party/blink/renderer/core/input/event_handler_test.cc
@@ -3195,184 +3195,6 @@
   EXPECT_EQ("Some text to select", GetDocument().GetSelection()->toString());
 }
 
-// Test that with MouseSubframeNoImplicitCapture enable, mouse down at inner
-// frame and move to outer frame does not capture mouse to inner frame.
-TEST_F(EventHandlerSimTest, MouseDragWithNoSubframeImplicitCapture) {
-  ScopedMouseSubframeNoImplicitCaptureForTest scoped_feature(true);
-  WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
-
-  SimRequest main_resource("https://example.com/test.html", "text/html");
-  SimRequest frame_resource("https://example.com/frame.html", "text/html");
-
-  LoadURL("https://example.com/test.html");
-
-  main_resource.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      iframe {
-        width: 200px;
-        height: 200px;
-      }
-      div {
-        width: 200px;
-        height: 200px;
-      }
-    </style>
-    <iframe id='frame' src='frame.html'></iframe>
-    <div id='outside'></div>
-  )HTML");
-
-  frame_resource.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        margin: 0;
-      }
-      div {
-        width: 100px;
-        height: 100px;
-      }
-    </style>
-    <div id='target'></div>
-  )HTML");
-  Compositor().BeginFrame();
-
-  WebMouseEvent mouse_down_inside_event(
-      WebMouseEvent::Type::kMouseDown, gfx::PointF(50, 50), gfx::PointF(50, 50),
-      WebPointerProperties::Button::kLeft, 0,
-      WebInputEvent::Modifiers::kLeftButtonDown,
-      WebInputEvent::GetStaticTimeStampForTests());
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_down_inside_event, ui::LatencyInfo()));
-
-  WebMouseEvent mouse_move_inside_event(
-      WebInputEvent::Type::kMouseMove, gfx::PointF(100, 100),
-      gfx::PointF(100, 100), WebPointerProperties::Button::kLeft, 1,
-      WebInputEvent::Modifiers::kLeftButtonDown,
-      WebInputEvent::GetStaticTimeStampForTests());
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_move_inside_event, ui::LatencyInfo()));
-  auto* iframe_element =
-      To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
-  Document* iframe_doc = iframe_element->contentDocument();
-  Element* target = iframe_doc->getElementById("target");
-
-  EXPECT_EQ(iframe_doc->GetFrame()
-                ->GetEventHandler()
-                .LastKnownMousePositionInRootFrame(),
-            gfx::PointF(100, 100));
-  EXPECT_EQ(iframe_doc->HoverElement(), target);
-  EXPECT_FALSE(target->hasPointerCapture(PointerEventFactory::kMouseId));
-
-  // Without capturing, next mouse move will be send to outer frame.
-  WebMouseEvent mouse_move_outside_event(
-      WebInputEvent::Type::kMouseMove, gfx::PointF(100, 300),
-      gfx::PointF(100, 300), WebPointerProperties::Button::kLeft, 1,
-      WebInputEvent::Modifiers::kLeftButtonDown,
-      WebInputEvent::GetStaticTimeStampForTests());
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_move_outside_event, ui::LatencyInfo()));
-
-  // Mouse is hovering the element in outer frame.
-  EXPECT_FALSE(iframe_doc->HoverElement());
-  EXPECT_TRUE(
-      iframe_doc->GetFrame()->GetEventHandler().IsMousePositionUnknown());
-  EXPECT_EQ(GetDocument().HoverElement(),
-            GetDocument().getElementById("outside"));
-}
-
-// Test that with MouseSubframeNoImplicitCapture enable, mouse down at inner
-// frame, set pointer capture and move to outer frame will capture mouse to
-// the capture target in inner frame.
-TEST_F(EventHandlerSimTest,
-       MouseDragWithPointerCaptureAndNoSubframeImplicitCapture) {
-  ScopedMouseSubframeNoImplicitCaptureForTest scoped_feature(true);
-
-  WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
-
-  SimRequest main_resource("https://example.com/test.html", "text/html");
-  SimRequest frame_resource("https://example.com/frame.html", "text/html");
-
-  LoadURL("https://example.com/test.html");
-
-  main_resource.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      iframe {
-        width: 200px;
-        height: 200px;
-      }
-      div {
-        width: 200px;
-        height: 200px;
-      }
-    </style>
-    <iframe id='frame' src='frame.html'></iframe>
-    <div id='outside'></div>
-  )HTML");
-
-  frame_resource.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      body {
-        margin: 0;
-      }
-      div {
-        width: 100px;
-        height: 100px;
-      }
-    </style>
-    <div id='target'></div>
-  )HTML");
-  Compositor().BeginFrame();
-
-  WebMouseEvent mouse_down_inside_event(
-      WebMouseEvent::Type::kMouseDown, gfx::PointF(50, 50), gfx::PointF(50, 50),
-      WebPointerProperties::Button::kLeft, 0,
-      WebInputEvent::Modifiers::kLeftButtonDown,
-      WebInputEvent::GetStaticTimeStampForTests());
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_down_inside_event, ui::LatencyInfo()));
-
-  auto* iframe_element =
-      To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
-  Document* iframe_doc = iframe_element->contentDocument();
-  Element* target = iframe_doc->getElementById("target");
-
-  ExceptionState exception(nullptr, ExceptionState::kExecutionContext, "", "");
-
-  target->setPointerCapture(PointerEventFactory::kMouseId, exception);
-  EXPECT_TRUE(target->hasPointerCapture(PointerEventFactory::kMouseId));
-
-  // With pointercapture, next mouse move will be send to inner frame.
-  WebMouseEvent mouse_move_event(WebInputEvent::Type::kMouseMove,
-                                 gfx::PointF(100, 300), gfx::PointF(100, 300),
-                                 WebPointerProperties::Button::kLeft, 1,
-                                 WebInputEvent::Modifiers::kLeftButtonDown,
-                                 WebInputEvent::GetStaticTimeStampForTests());
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_move_event, ui::LatencyInfo()));
-
-  EXPECT_EQ(iframe_doc->GetFrame()
-                ->GetEventHandler()
-                .LastKnownMousePositionInRootFrame(),
-            gfx::PointF(100, 300));
-  EXPECT_EQ(iframe_doc->HoverElement(), target);
-
-  // Release capture and move event will be send to outer frame.
-  target->releasePointerCapture(PointerEventFactory::kMouseId, exception);
-  WebView().MainFrameWidget()->HandleInputEvent(
-      WebCoalescedInputEvent(mouse_move_event, ui::LatencyInfo()));
-
-  // iframe no longer gets mouse move events.
-  EXPECT_FALSE(iframe_doc->HoverElement());
-  EXPECT_TRUE(
-      iframe_doc->GetFrame()->GetEventHandler().IsMousePositionUnknown());
-  // Mouse is hovering the element in outer frame.
-  EXPECT_EQ(GetDocument().HoverElement(),
-            GetDocument().getElementById("outside"));
-}
-
 // Test that mouse right button down and move to an iframe will route the events
 // to iframe correctly.
 TEST_F(EventHandlerSimTest, MouseRightButtonDownMoveToIFrame) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index b37ce0e..1a69edfb 100644
--- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -585,19 +584,10 @@
 LayoutUnit TranslateRTLCoordinate(const LayoutObject* layout_object,
                                   LayoutUnit position,
                                   const Vector<LayoutUnit>& column_positions) {
-  // TranslateRTLCoordinate exists in legacy grid, but is not implemented in
-  // GridNG, duplicating implementation from legacy here. Once legacy grid is
-  // removed, the implementation for TranslateRTLCoordinate will only exist
-  // here.
-  // If this is a legacy grid, use the legacy grid method.
-  if (layout_object->IsLayoutGrid()) {
-    return To<LayoutGrid>(layout_object)->TranslateRTLCoordinate(position);
-  }
-  // This should only be called on grid layout objects. If the object is not
-  // legacy grid, it must be GridNG.
+  // This should only be called on grid layout objects.
   DCHECK(layout_object->IsLayoutNGGrid());
-
   DCHECK(!layout_object->StyleRef().IsLeftToRightDirection());
+
   LayoutUnit alignment_offset = column_positions.front();
   LayoutUnit right_grid_edge_position = column_positions.back();
   return right_grid_edge_position + alignment_offset - position;
@@ -1945,7 +1935,7 @@
   if (highlight_config.css_grid != Color::kTransparent ||
       highlight_config.grid_highlight_config) {
     grid_info_ = protocol::ListValue::create();
-    if (layout_object->IsLayoutGridIncludingNG()) {
+    if (layout_object->IsLayoutNGGrid()) {
       grid_info_->pushValue(
           BuildGridInfo(node, highlight_config, scale_, true));
     }
@@ -2163,8 +2153,9 @@
 
   float scale = DeviceScaleFromFrameView(frame_view);
   LayoutObject* layout_object = node->GetLayoutObject();
-  if (!layout_object || !layout_object->IsLayoutGridIncludingNG())
+  if (!layout_object || !layout_object->IsLayoutNGGrid()) {
     return nullptr;
+  }
 
   std::unique_ptr<protocol::DictionaryValue> grid_info =
       BuildGridInfo(node, config, scale, true);
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index e7c98bd..3e00167e 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -95,15 +95,6 @@
   "geometry/transform_state.h",
   "geometry/writing_mode_converter.cc",
   "geometry/writing_mode_converter.h",
-  "grid.cc",
-  "grid.h",
-  "grid_baseline_alignment.cc",
-  "grid_baseline_alignment.h",
-  "grid_layout_utils.cc",
-  "grid_layout_utils.h",
-  "grid_linked_list.h",
-  "grid_track_sizing_algorithm.cc",
-  "grid_track_sizing_algorithm.h",
   "hit_test_cache.cc",
   "hit_test_cache.h",
   "hit_test_canvas_result.cc",
@@ -151,8 +142,6 @@
   "layout_frame.h",
   "layout_frame_set.cc",
   "layout_frame_set.h",
-  "layout_grid.cc",
-  "layout_grid.h",
   "layout_html_canvas.cc",
   "layout_html_canvas.h",
   "layout_iframe.cc",
@@ -860,7 +849,6 @@
   "geometry/physical_rect_test.cc",
   "geometry/physical_size_test.cc",
   "geometry/writing_mode_converter_test.cc",
-  "grid_linked_list_test.cc",
   "hit_testing_test.cc",
   "layout_block_flow_test.cc",
   "layout_block_test.cc",
diff --git a/third_party/blink/renderer/core/layout/grid.cc b/third_party/blink/renderer/core/layout/grid.cc
deleted file mode 100644
index f1b8094..0000000
--- a/third_party/blink/renderer/core/layout/grid.cc
+++ /dev/null
@@ -1,465 +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 "third_party/blink/renderer/core/layout/grid.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
-
-namespace blink {
-
-namespace {
-
-static inline GridTrackSizingDirection OrthogonalDirection(
-    GridTrackSizingDirection direction) {
-  return direction == kForRows ? kForColumns : kForRows;
-}
-
-}  // namespace
-
-Grid* Grid::Create(const LayoutGrid* layout_grid) {
-  return MakeGarbageCollected<ListGrid>(layout_grid);
-}
-
-Grid::Grid(const LayoutGrid* grid) : order_iterator_(grid) {}
-
-void Grid::SetExplicitGridStart(wtf_size_t row_start, wtf_size_t column_start) {
-  explicit_row_start_ = row_start;
-  explicit_column_start_ = column_start;
-}
-
-wtf_size_t Grid::ExplicitGridStart(GridTrackSizingDirection direction) const {
-  return direction == kForRows ? explicit_row_start_ : explicit_column_start_;
-}
-
-GridArea Grid::GridItemArea(const LayoutBox& item) const {
-  DCHECK(grid_item_area_.Contains(&item));
-  return grid_item_area_.at(&item);
-}
-
-void Grid::SetGridItemArea(const LayoutBox& item, GridArea area) {
-  grid_item_area_.Set(&item, area);
-}
-
-wtf_size_t Grid::GridItemPaintOrder(const LayoutBox& item) const {
-  return grid_items_indexes_map_.at(&item);
-}
-
-void Grid::SetGridItemPaintOrder(const LayoutBox& item, wtf_size_t order) {
-  grid_items_indexes_map_.Set(&item, order);
-}
-
-#if DCHECK_IS_ON()
-bool Grid::HasAnyGridItemPaintOrder() const {
-  return !grid_items_indexes_map_.empty();
-}
-#endif
-
-void Grid::SetAutoRepeatTracks(wtf_size_t auto_repeat_rows,
-                               wtf_size_t auto_repeat_columns) {
-  DCHECK_GE(static_cast<wtf_size_t>(kLegacyGridMaxTracks),
-            NumTracks(kForRows) + auto_repeat_rows);
-  DCHECK_GE(static_cast<wtf_size_t>(kLegacyGridMaxTracks),
-            NumTracks(kForColumns) + auto_repeat_columns);
-  auto_repeat_rows_ = auto_repeat_rows;
-  auto_repeat_columns_ = auto_repeat_columns;
-}
-
-wtf_size_t Grid::AutoRepeatTracks(GridTrackSizingDirection direction) const {
-  return direction == kForRows ? auto_repeat_rows_ : auto_repeat_columns_;
-}
-
-void Grid::SetAutoRepeatEmptyColumns(
-    std::unique_ptr<OrderedTrackIndexSet> auto_repeat_empty_columns) {
-  auto_repeat_empty_columns_ = std::move(auto_repeat_empty_columns);
-}
-
-void Grid::SetAutoRepeatEmptyRows(
-    std::unique_ptr<OrderedTrackIndexSet> auto_repeat_empty_rows) {
-  auto_repeat_empty_rows_ = std::move(auto_repeat_empty_rows);
-}
-
-bool Grid::HasAutoRepeatEmptyTracks(GridTrackSizingDirection direction) const {
-  return direction == kForColumns ? !!auto_repeat_empty_columns_
-                                  : !!auto_repeat_empty_rows_;
-}
-
-bool Grid::IsEmptyAutoRepeatTrack(GridTrackSizingDirection direction,
-                                  wtf_size_t line) const {
-  DCHECK(HasAutoRepeatEmptyTracks(direction));
-  return AutoRepeatEmptyTracks(direction)->Contains(line);
-}
-
-OrderedTrackIndexSet* Grid::AutoRepeatEmptyTracks(
-    GridTrackSizingDirection direction) const {
-  DCHECK(HasAutoRepeatEmptyTracks(direction));
-  return direction == kForColumns ? auto_repeat_empty_columns_.get()
-                                  : auto_repeat_empty_rows_.get();
-}
-
-GridSpan Grid::GridItemSpan(const LayoutBox& grid_item,
-                            GridTrackSizingDirection direction) const {
-  GridArea area = GridItemArea(grid_item);
-  return direction == kForColumns ? area.columns : area.rows;
-}
-
-void Grid::SetNeedsItemsPlacement(bool needs_items_placement) {
-  needs_items_placement_ = needs_items_placement;
-
-  if (!needs_items_placement) {
-    ConsolidateGridDataStructure();
-    return;
-  }
-
-  ClearGridDataStructure();
-  grid_item_area_.clear();
-  grid_items_indexes_map_.clear();
-  explicit_row_start_ = 0;
-  explicit_column_start_ = 0;
-  auto_repeat_columns_ = 0;
-  auto_repeat_rows_ = 0;
-  auto_repeat_empty_columns_ = nullptr;
-  auto_repeat_empty_rows_ = nullptr;
-}
-
-Grid::GridIterator::GridIterator(GridTrackSizingDirection direction,
-                                 wtf_size_t fixed_track_index,
-                                 wtf_size_t varying_track_index)
-    : direction_(direction),
-      row_index_((direction == kForColumns) ? varying_track_index
-                                            : fixed_track_index),
-      column_index_((direction == kForColumns) ? fixed_track_index
-                                               : varying_track_index),
-      child_index_(0) {}
-
-ListGrid::GridCell* ListGrid::GridTrack::Find(wtf_size_t index) const {
-  auto orthogonal_axis = OrthogonalDirection(direction_);
-  for (GridCell* cell = cells_->Head(); cell;
-       cell = cell->NextInDirection(direction_)) {
-    wtf_size_t cell_index = cell->Index(orthogonal_axis);
-    if (cell_index == index)
-      return cell;
-    if (cell_index > index)
-      return nullptr;
-  }
-  return nullptr;
-}
-
-static int ComparePositions(wtf_size_t first, wtf_size_t second) {
-  return first < second ? -1 : (first != second);
-}
-
-GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
-    GridCell* cell) {
-  cell->SetTraversalMode(direction_);
-
-  return cells_->Insert(
-      cell, [this](ListGrid::GridCell* first, ListGrid::GridCell* second) {
-        // This is ugly but we need to do this in order the
-        // DoublyLinkedList::Insert() algorithm to work at that code
-        // only uses next_ and prev_.
-        first->SetTraversalMode(direction_);
-        second->SetTraversalMode(direction_);
-        auto ortho_direction = OrthogonalDirection(direction_);
-        return ComparePositions(first->Index(ortho_direction),
-                                second->Index(ortho_direction));
-      });
-}
-
-GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::Insert(
-    LayoutBox& item,
-    const GridSpan& span) {
-  auto compare_cells = [this](ListGrid::GridCell* first,
-                              ListGrid::GridCell* second) {
-    first->SetTraversalMode(direction_);
-    second->SetTraversalMode(direction_);
-    auto ortho_direction = OrthogonalDirection(direction_);
-    return ComparePositions(first->Index(ortho_direction),
-                            second->Index(ortho_direction));
-  };
-
-  wtf_size_t col_index = direction_ == kForColumns ? Index() : span.StartLine();
-  wtf_size_t row_index = direction_ == kForColumns ? span.StartLine() : Index();
-
-  auto result = cells_->Insert(
-      MakeGarbageCollected<GridCell>(row_index, col_index), compare_cells);
-  GridCell* cell = result.node;
-  for (auto index : span) {
-    cell->AppendItem(item);
-
-    if (index == span.EndLine() - 1)
-      break;
-
-    cell->SetTraversalMode(direction_);
-    auto ortho_direction = OrthogonalDirection(direction_);
-    if (!cell->Next() ||
-        (cell->Next()->Index(ortho_direction) != (index + 1))) {
-      wtf_size_t next_col_index =
-          direction_ == kForColumns ? Index() : index + 1;
-      wtf_size_t next_row_index =
-          direction_ == kForColumns ? index + 1 : Index();
-      GridCell* next_cell =
-          MakeGarbageCollected<GridCell>(next_row_index, next_col_index);
-      InsertAfter(next_cell, cell);
-    }
-    cell = cell->Next();
-  }
-  return result;
-}
-
-GridLinkedList<ListGrid::GridCell>::AddResult ListGrid::GridTrack::InsertAfter(
-    GridCell* cell,
-    GridCell* insertion_point) {
-  insertion_point->SetTraversalMode(direction_);
-  cell->SetTraversalMode(direction_);
-  if (GridCell* next = insertion_point->Next()) {
-    if (next == cell)
-      return {cell, false};
-    // We need to set the traversal mode for the next cell as we're
-    // going to insert in between and we need to properly update next_
-    // and prev_ pointers.
-    next->SetTraversalMode(direction_);
-  }
-  return cells_->InsertAfter(cell, insertion_point);
-}
-
-const GridItemList& ListGrid::Cell(wtf_size_t row_index,
-                                   wtf_size_t column_index) const {
-  DEFINE_STATIC_LOCAL(const Persistent<const GridItemList>, empty_vector,
-                      (MakeGarbageCollected<GridItemList>()));
-  for (auto* row = rows_->Head(); row; row = row->Next()) {
-    if (row->Index() == row_index) {
-      GridCell* cell = row->Find(column_index);
-      return cell ? cell->Items() : *empty_vector;
-    }
-    if (row->Index() > row_index)
-      return *empty_vector;
-  }
-  return *empty_vector;
-}
-
-ListGrid::GridTrack* ListGrid::InsertTracks(
-    GridLinkedList<GridTrack>& tracks,
-    const GridSpan& span,
-    GridTrackSizingDirection direction) {
-  auto compare_tracks = [](ListGrid::GridTrack* first,
-                           ListGrid::GridTrack* second) {
-    return ComparePositions(first->Index(), second->Index());
-  };
-
-  wtf_size_t start_line = span.StartLine();
-  wtf_size_t end_line = span.EndLine();
-
-  GridLinkedList<ListGrid::GridTrack>::AddResult result = tracks.Insert(
-      MakeGarbageCollected<GridTrack>(start_line, direction), compare_tracks);
-  auto* track = result.node;
-  DCHECK(track);
-
-  auto* iter = track;
-  for (wtf_size_t track_index = start_line + 1; iter && track_index < end_line;
-       ++track_index) {
-    if (!iter->Next() || track_index < iter->Next()->Index()) {
-      tracks.InsertAfter(
-          MakeGarbageCollected<GridTrack>(track_index, direction), iter);
-    }
-    iter = iter->Next();
-  }
-
-  return track;
-}
-
-void ListGrid::Insert(LayoutBox& item, const GridArea& area) {
-  DCHECK(area.rows.IsTranslatedDefinite() &&
-         area.columns.IsTranslatedDefinite());
-  EnsureGridSize(area.rows.EndLine(), area.columns.EndLine());
-
-  GridTrack* first_row = InsertTracks(*rows_, area.rows, kForRows);
-  DCHECK(first_row);
-  GridTrack* first_column = InsertTracks(*columns_, area.columns, kForColumns);
-  DCHECK(first_column);
-
-  GridCell* above_cell = nullptr;
-  GridTrack* row = first_row;
-  for (auto row_index : area.rows) {
-    auto result = row->Insert(item, area.columns);
-    // We need to call Insert() for the first row of cells to get the
-    // column pointers right. For the following rows we can use
-    // InsertAfter() as it's cheaper (it doesn't traverse the
-    // list). We need to keep track of the cell in the row above
-    // (above_cell) in order to properly update the column next_ &
-    // prev_ pointers.
-    auto* cell_iter = result.node;
-    auto* col_iter = first_column;
-    while (col_iter && col_iter->Index() < area.columns.EndLine()) {
-      if (row_index == area.rows.StartLine()) {
-        col_iter->Insert(cell_iter);
-      } else {
-        col_iter->InsertAfter(cell_iter, above_cell);
-        above_cell = above_cell->NextInDirection(kForRows);
-      }
-      cell_iter = cell_iter->NextInDirection(kForRows);
-      col_iter = col_iter->Next();
-    }
-    above_cell = result.node;
-    row = row->Next();
-  }
-
-  SetGridItemArea(item, area);
-}
-
-void ListGrid::EnsureGridSize(wtf_size_t maximum_row_size,
-                              wtf_size_t maximum_column_size) {
-  num_rows_ = std::max(num_rows_, maximum_row_size);
-  num_columns_ = std::max(num_columns_, maximum_column_size);
-}
-
-void ListGrid::ClearGridDataStructure() {
-  num_rows_ = num_columns_ = 0;
-  rows_->Clear();
-  columns_->Clear();
-}
-
-void ListGrid::GridCell::SetTraversalMode(GridTrackSizingDirection direction) {
-  if (direction == direction_)
-    return;
-  direction_ = direction;
-  GridCell* next = Next();
-  SetNext(next_ortho_);
-  next_ortho_ = next;
-  GridCell* prev = Prev();
-  SetPrev(prev_ortho_);
-  prev_ortho_ = prev;
-}
-
-ListGrid::GridCell* ListGrid::GridCell::NextInDirection(
-    GridTrackSizingDirection direction) const {
-  return direction_ == direction ? Next() : next_ortho_.Get();
-}
-
-Grid::GridIterator* ListGrid::CreateIterator(
-    GridTrackSizingDirection direction,
-    wtf_size_t fixed_track_index,
-    wtf_size_t varying_track_index) const {
-  return MakeGarbageCollected<ListGridIterator>(
-      *this, direction, fixed_track_index, varying_track_index);
-}
-
-ListGridIterator::ListGridIterator(const ListGrid& grid,
-                                   GridTrackSizingDirection direction,
-                                   wtf_size_t fixed_track_index,
-                                   wtf_size_t varying_track_index)
-    : GridIterator(direction, fixed_track_index, varying_track_index),
-      grid_(grid) {}
-
-LayoutBox* ListGridIterator::NextGridItem() {
-  DCHECK(grid_->NumTracks(kForRows));
-  DCHECK(grid_->NumTracks(kForColumns));
-
-  bool is_row_axis = direction_ == kForColumns;
-  if (!cell_node_) {
-    auto* track = is_row_axis ? grid_->columns_->Head() : grid_->rows_->Head();
-    DCHECK(track);
-    const wtf_size_t fixed_index = is_row_axis ? column_index_ : row_index_;
-    while (track && track->Index() != fixed_index)
-      track = track->Next();
-
-    if (!track)
-      return nullptr;
-
-    child_index_ = 0;
-    cell_node_ = track->Cells().Head();
-    DCHECK(cell_node_);
-    DCHECK(!cell_node_->Items().empty());
-    return cell_node_->Items()[child_index_++];
-  }
-
-  GridTrackSizingDirection other_direction =
-      is_row_axis ? kForRows : kForColumns;
-  while (true) {
-    LayoutBox* candidate;
-    if (child_index_ < cell_node_->Items().size()) {
-      candidate = cell_node_->Items()[child_index_++];
-    } else {
-      child_index_ = 0;
-      cell_node_ = cell_node_->NextInDirection(direction_);
-      if (!cell_node_)
-        return nullptr;
-
-      DCHECK(!cell_node_->Items().empty());
-      candidate = cell_node_->Items()[child_index_++];
-    }
-    // Skip items already processed in an earlier cell of the track.
-    const GridSpan& span = grid_->GridItemSpan(*candidate, other_direction);
-    if (span.StartLine() == cell_node_->Index(other_direction))
-      return candidate;
-  }
-}
-
-std::unique_ptr<GridArea> ListGridIterator::NextEmptyGridArea(
-    wtf_size_t fixed_track_span,
-    wtf_size_t varying_track_span) {
-  auto FindCellOrClosest = [](ListGrid::GridCell* cell_node,
-                              GridTrackSizingDirection direction,
-                              wtf_size_t index) {
-    auto ortho_direction = OrthogonalDirection(direction);
-    while (cell_node && cell_node->Index(direction) < index)
-      cell_node = cell_node->NextInDirection(ortho_direction);
-
-    return cell_node;
-  };
-
-  auto CreateUniqueGridArea = [this, fixed_track_span, varying_track_span]() {
-    bool is_row_axis = direction_ == kForColumns;
-    wtf_size_t row_span = is_row_axis ? varying_track_span : fixed_track_span;
-    wtf_size_t column_span =
-        is_row_axis ? fixed_track_span : varying_track_span;
-    return std::make_unique<GridArea>(
-        GridSpan::TranslatedDefiniteGridSpan(row_index_, row_index_ + row_span),
-        GridSpan::TranslatedDefiniteGridSpan(column_index_,
-                                             column_index_ + column_span));
-  };
-
-  auto CellIsInsideSpan = [](ListGrid::GridCell* cell_node,
-                             GridTrackSizingDirection direction,
-                             wtf_size_t start, wtf_size_t end) {
-    DCHECK(cell_node);
-    wtf_size_t cell_index = cell_node->Index(direction);
-    return cell_index >= start && cell_index <= end;
-  };
-
-  auto orthogonal_axis = OrthogonalDirection(direction_);
-  auto& tracks = grid_->Tracks(orthogonal_axis);
-
-  bool is_row_axis = direction_ == kForColumns;
-  auto& varying_index = is_row_axis ? row_index_ : column_index_;
-  const wtf_size_t fixed_index = is_row_axis ? column_index_ : row_index_;
-  const wtf_size_t end_fixed_span = fixed_index + fixed_track_span - 1;
-  auto* track_node = tracks.Head();
-  while (track_node && track_node->Index() < varying_index)
-    track_node = track_node->Next();
-
-  for (; track_node; track_node = track_node->Next()) {
-    if (!track_node)
-      return CreateUniqueGridArea();
-
-    if (track_node->Index() - varying_index >= varying_track_span)
-      return CreateUniqueGridArea();
-
-    auto* cell_node =
-        FindCellOrClosest(track_node->Cells().Head(), direction_, fixed_index);
-    if (cell_node &&
-        CellIsInsideSpan(cell_node, direction_, fixed_index, end_fixed_span))
-      varying_index = track_node->Index() + 1;
-    else if (track_node->Index() - varying_index >= varying_track_span)
-      return CreateUniqueGridArea();
-  }
-
-  return CreateUniqueGridArea();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid.h b/third_party/blink/renderer/core/layout/grid.h
deleted file mode 100644
index 97d4474..0000000
--- a/third_party/blink/renderer/core/layout/grid.h
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_H_
-
-#include "base/dcheck_is_on.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/grid_linked_list.h"
-#include "third_party/blink/renderer/core/layout/order_iterator.h"
-#include "third_party/blink/renderer/core/style/grid_area.h"
-#include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
-
-namespace blink {
-
-typedef HeapVector<Member<LayoutBox>, 1> GridItemList;
-typedef LinkedHashSet<wtf_size_t, IntWithZeroKeyHashTraits<wtf_size_t>>
-    OrderedTrackIndexSet;
-
-class LayoutGrid;
-class GridIterator;
-
-// The Grid class represent a generic storage for grid items. This
-// class is used by the LayoutGrid object to place the grid items on a
-// grid like structure, so that they could be accessed by rows/columns
-// instead of just traversing the DOM or Layout trees. The other user
-// of this class is the GridTrackSizingAlgorithm class.
-class CORE_EXPORT Grid : public GarbageCollected<Grid> {
- public:
-  static Grid* Create(const LayoutGrid*);
-
-  virtual wtf_size_t NumTracks(GridTrackSizingDirection) const = 0;
-
-  virtual void EnsureGridSize(wtf_size_t maximum_row_size,
-                              wtf_size_t maximum_column_size) = 0;
-  virtual void Insert(LayoutBox&, const GridArea&) = 0;
-
-  virtual const GridItemList& Cell(wtf_size_t row, wtf_size_t column) const = 0;
-
-  virtual ~Grid() {}
-
-  virtual void Trace(Visitor* visitor) const {
-    visitor->Trace(order_iterator_);
-    visitor->Trace(grid_item_area_);
-    visitor->Trace(grid_items_indexes_map_);
-  }
-
-  // Note that out of flow children are not grid items.
-  bool HasGridItems() const { return !grid_item_area_.empty(); }
-
-  GridArea GridItemArea(const LayoutBox&) const;
-  void SetGridItemArea(const LayoutBox&, GridArea);
-
-  GridSpan GridItemSpan(const LayoutBox&, GridTrackSizingDirection) const;
-
-  wtf_size_t GridItemPaintOrder(const LayoutBox&) const;
-  void SetGridItemPaintOrder(const LayoutBox&, wtf_size_t order);
-
-  wtf_size_t ExplicitGridStart(GridTrackSizingDirection) const;
-  void SetExplicitGridStart(wtf_size_t row_start, wtf_size_t column_start);
-
-  wtf_size_t AutoRepeatTracks(GridTrackSizingDirection) const;
-  void SetAutoRepeatTracks(wtf_size_t auto_repeat_rows,
-                           wtf_size_t auto_repeat_columns);
-
-  void SetAutoRepeatEmptyColumns(std::unique_ptr<OrderedTrackIndexSet>);
-  void SetAutoRepeatEmptyRows(std::unique_ptr<OrderedTrackIndexSet>);
-
-  bool HasAutoRepeatEmptyTracks(GridTrackSizingDirection) const;
-  bool IsEmptyAutoRepeatTrack(GridTrackSizingDirection, wtf_size_t) const;
-
-  OrderedTrackIndexSet* AutoRepeatEmptyTracks(GridTrackSizingDirection) const;
-
-  OrderIterator& GetOrderIterator() { return order_iterator_; }
-
-  void SetNeedsItemsPlacement(bool);
-  bool NeedsItemsPlacement() const { return needs_items_placement_; }
-
-#if DCHECK_IS_ON()
-  bool HasAnyGridItemPaintOrder() const;
-#endif
-
-  class GridIterator : public GarbageCollected<GridIterator> {
-   public:
-    virtual LayoutBox* NextGridItem() = 0;
-
-    virtual std::unique_ptr<GridArea> NextEmptyGridArea(
-        wtf_size_t fixed_track_span,
-        wtf_size_t varying_track_span) = 0;
-
-    GridIterator(const GridIterator&) = delete;
-    GridIterator& operator=(const GridIterator&) = delete;
-    virtual ~GridIterator() = default;
-
-    virtual void Trace(Visitor* visitor) const {}
-
-   protected:
-    // |direction| is the direction that is fixed to |fixed_track_index| so e.g
-    // GridIterator(grid_, kForColumns, 1) will walk over the rows of the 2nd
-    // column.
-    GridIterator(GridTrackSizingDirection,
-                 wtf_size_t fixed_track_index,
-                 wtf_size_t varying_track_index);
-
-    GridTrackSizingDirection direction_;
-    wtf_size_t row_index_;
-    wtf_size_t column_index_;
-    wtf_size_t child_index_;
-  };
-
-  virtual GridIterator* CreateIterator(
-      GridTrackSizingDirection,
-      wtf_size_t fixed_track_index,
-      wtf_size_t varying_track_index = 0) const = 0;
-
- protected:
-  Grid(const LayoutGrid*);
-
-  virtual void ClearGridDataStructure() = 0;
-  virtual void ConsolidateGridDataStructure() = 0;
-
- private:
-  friend class GridIterator;
-
-  OrderIterator order_iterator_;
-
-  wtf_size_t explicit_column_start_{0};
-  wtf_size_t explicit_row_start_{0};
-
-  wtf_size_t auto_repeat_columns_{0};
-  wtf_size_t auto_repeat_rows_{0};
-
-  bool needs_items_placement_{true};
-
-  HeapHashMap<Member<const LayoutBox>, GridArea> grid_item_area_;
-  HeapHashMap<Member<const LayoutBox>, wtf_size_t> grid_items_indexes_map_;
-
-  std::unique_ptr<OrderedTrackIndexSet> auto_repeat_empty_columns_{nullptr};
-  std::unique_ptr<OrderedTrackIndexSet> auto_repeat_empty_rows_{nullptr};
-};
-
-// This is a Grid specialization which uses doubly linked lists (DLL)
-// for the grid data structure. Each axis will be represented by a DLL
-// of GridTrack's. The grid will only have list nodes for those tracks
-// which actually contain at least one item. Those DLL are ordered by
-// the track index.
-class CORE_EXPORT ListGrid final : public Grid {
- public:
-  explicit ListGrid(const LayoutGrid* grid)
-      : Grid(grid),
-        rows_(MakeGarbageCollected<GridLinkedList<GridTrack>>()),
-        columns_(MakeGarbageCollected<GridLinkedList<GridTrack>>()) {}
-
-  void Trace(Visitor* visitor) const final {
-    visitor->Trace(rows_);
-    visitor->Trace(columns_);
-    Grid::Trace(visitor);
-  }
-
-  wtf_size_t NumTracks(GridTrackSizingDirection direction) const override {
-    return direction == kForRows ? num_rows_ : num_columns_;
-  }
-  const GridItemList& Cell(wtf_size_t row, wtf_size_t column) const override;
-  void Insert(LayoutBox&, const GridArea&) override;
-  void EnsureGridSize(wtf_size_t maximum_row_size,
-                      wtf_size_t maximum_column_size) override;
-
-  // This is the class representing a cell in the grid. GridCell's are
-  // only created for those cells which do have items inside. Each
-  // GridCell will be part of two different DLL, one representing the
-  // column and another one representing the row.
-  class GridCell final : public GridLinkedListNodeBase<GridCell> {
-   public:
-    GridCell(wtf_size_t row, wtf_size_t column) : row_(row), column_(column) {}
-
-    wtf_size_t Index(GridTrackSizingDirection direction) const {
-      return direction == kForRows ? row_ : column_;
-    }
-
-    void AppendItem(LayoutBox& item) { items_.push_back(&item); }
-
-    const GridItemList& Items() const { return items_; }
-
-    void Trace(Visitor* visitor) const final {
-      visitor->Trace(prev_ortho_);
-      visitor->Trace(next_ortho_);
-      visitor->Trace(items_);
-      GridLinkedListNodeBase<GridCell>::Trace(visitor);
-    }
-
-    // DoublyLinkedListNode classes must provide a next_ and prev_
-    // pointers to the DoublyLinkedList class so that it could perform
-    // the list operations. In the case of GridCells we need them to
-    // be shared by two lists the row and the column. This means that
-    // we need to maintain 4 separate pointers. In order to accomodate
-    // this in the DoublyLinkedList model, we must set the proper
-    // traversal mode (navigation by rows or columns) before any
-    // operation with a GridCell involving the use of the next_/prev_
-    // pointers.
-    // TODO(svillar): we could probably use DoublyLinkedLists just for
-    // one axis, this will remove the need for this and some other
-    // clumsy things like different behaviours in ~GridTrack() for
-    // each axis.
-    void SetTraversalMode(GridTrackSizingDirection);
-    GridTrackSizingDirection TraversalMode() const { return direction_; }
-
-    // Use this ONLY for traversals. If your code performs any
-    // modification in the list of cells while traversing then this
-    // might not work as expected and you should use
-    // SetTraversalMode()+Next() instead.
-    GridCell* NextInDirection(GridTrackSizingDirection) const;
-
-   private:
-    Member<GridCell> prev_ortho_;
-    Member<GridCell> next_ortho_;
-
-    GridTrackSizingDirection direction_{kForColumns};
-    GridItemList items_;
-    wtf_size_t row_;
-    wtf_size_t column_;
-  };
-
-  // This class represents a track (column or row) of the grid. Each
-  // GridTrack will be part of a DLL stored in the ListGrid class,
-  // either rows_ or columns_. GridTrack's are never empty, i.e., they
-  // are only created whenever an item spans through them. Each
-  // GridTrack keeps a sorted list of the cells containing grid items
-  // in that particular track. The list of cells is ordered by the
-  // index of the cell in the orthogonal direction, i.e., the list of
-  // cells in a GridTrack representing a column will be sorted by
-  // their row index.
-  class CORE_EXPORT GridTrack final : public GridLinkedListNodeBase<GridTrack> {
-   public:
-    GridTrack(wtf_size_t index, GridTrackSizingDirection direction)
-        : cells_(MakeGarbageCollected<GridLinkedList<GridCell>>()),
-          index_(index),
-          direction_(direction) {}
-
-    wtf_size_t Index() const { return index_; }
-
-    void Trace(Visitor* visitor) const final {
-      visitor->Trace(cells_);
-      GridLinkedListNodeBase<GridTrack>::Trace(visitor);
-    }
-
-    GridLinkedList<GridCell>::AddResult Insert(GridCell*);
-    GridLinkedList<GridCell>::AddResult InsertAfter(GridCell* cell,
-                                                    GridCell* insertion_point);
-    GridLinkedList<GridCell>::AddResult Insert(LayoutBox&, const GridSpan&);
-    GridCell* Find(wtf_size_t cell_index) const;
-
-    const GridLinkedList<GridCell>& Cells() const { return *cells_; }
-
-   private:
-    Member<GridLinkedList<GridCell>> cells_;
-    wtf_size_t index_;
-    GridTrackSizingDirection direction_;
-  };
-
- private:
-  friend class ListGridIterator;
-
-  // Returns a pointer to the first track.
-  GridTrack* InsertTracks(GridLinkedList<GridTrack>&,
-                          const GridSpan&,
-                          GridTrackSizingDirection);
-
-  void ClearGridDataStructure() override;
-  void ConsolidateGridDataStructure() override {}
-
-  const GridLinkedList<GridTrack>& Tracks(
-      GridTrackSizingDirection direction) const {
-    return direction == kForRows ? *rows_ : *columns_;
-  }
-
-  GridIterator* CreateIterator(
-      GridTrackSizingDirection,
-      wtf_size_t fixed_track_index,
-      wtf_size_t varying_track_index = 0) const override;
-
-  wtf_size_t num_rows_{0};
-  wtf_size_t num_columns_{0};
-
-  Member<GridLinkedList<GridTrack>> rows_;
-  Member<GridLinkedList<GridTrack>> columns_;
-};
-
-class ListGridIterator final : public Grid::GridIterator {
- public:
-  ListGridIterator(const ListGrid& grid,
-                   GridTrackSizingDirection,
-                   wtf_size_t fixed_track_index,
-                   wtf_size_t varying_track_index = 0);
-  ListGridIterator(const ListGridIterator&) = delete;
-  ListGridIterator& operator=(const ListGridIterator&) = delete;
-
-  void Trace(Visitor* visitor) const final {
-    visitor->Trace(grid_);
-    visitor->Trace(cell_node_);
-    GridIterator::Trace(visitor);
-  }
-
-  LayoutBox* NextGridItem() override;
-  std::unique_ptr<GridArea> NextEmptyGridArea(
-      wtf_size_t fixed_track_span,
-      wtf_size_t varying_track_span) override;
-
- private:
-  Member<const ListGrid> grid_;
-  Member<ListGrid::GridCell> cell_node_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_H_
diff --git a/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc b/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc
deleted file mode 100644
index f9f27b3..0000000
--- a/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/layout/grid_baseline_alignment.h"
-
-#include "third_party/blink/renderer/core/style/computed_style.h"
-
-namespace blink {
-
-// This function gives the margin 'over' based on the baseline-axis,
-// since in grid we can can 2-dimensional alignment by baseline. In
-// horizontal writing-mode, the row-axis is the horizontal axis. When
-// we use this axis to move the grid items so that they are
-// baseline-aligned, we want their "horizontal" margin (right); the
-// same will happen when using the column-axis under vertical writing
-// mode, we also want in this case the 'right' margin.
-LayoutUnit GridBaselineAlignment::MarginOverForChild(const LayoutBox& child,
-                                                     GridAxis axis) const {
-  return IsHorizontalBaselineAxis(axis) ? child.MarginRight()
-                                        : child.MarginTop();
-}
-
-// This function gives the margin 'under' based on the baseline-axis,
-// since in grid we can can 2-dimensional alignment by baseline. In
-// horizontal writing-mode, the row-axis is the horizontal axis. When
-// we use this axis to move the grid items so that they are
-// baseline-aligned, we want their "horizontal" margin (left); the
-// same will happen when using the column-axis under vertical writing
-// mode, we also want in this case the 'left' margin.
-LayoutUnit GridBaselineAlignment::MarginUnderForChild(const LayoutBox& child,
-                                                      GridAxis axis) const {
-  return IsHorizontalBaselineAxis(axis) ? child.MarginLeft()
-                                        : child.MarginBottom();
-}
-
-LayoutUnit GridBaselineAlignment::LogicalAscentForChild(
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  LayoutUnit ascent = AscentForChild(child, baseline_axis);
-  return IsDescentBaselineForChild(child, baseline_axis)
-             ? DescentForChild(child, ascent, baseline_axis)
-             : ascent;
-}
-
-LayoutUnit GridBaselineAlignment::AscentForChild(const LayoutBox& child,
-                                                 GridAxis baseline_axis) const {
-  LayoutUnit margin = IsDescentBaselineForChild(child, baseline_axis)
-                          ? MarginUnderForChild(child, baseline_axis)
-                          : MarginOverForChild(child, baseline_axis);
-  LayoutUnit baseline = IsParallelToBaselineAxisForChild(child, baseline_axis)
-                            ? child.FirstLineBoxBaseline()
-                            : LayoutUnit(-1);
-  // We take border-box's under edge if no valid baseline.
-  if (baseline == -1) {
-    if (IsHorizontalBaselineAxis(baseline_axis)) {
-      return IsFlippedBlocksWritingMode(block_flow_)
-                 ? child.Size().Width().ToInt() + margin
-                 : margin;
-    }
-    return child.Size().Height() + margin;
-  }
-  return baseline + margin;
-}
-
-LayoutUnit GridBaselineAlignment::DescentForChild(
-    const LayoutBox& child,
-    LayoutUnit ascent,
-    GridAxis baseline_axis) const {
-  if (IsParallelToBaselineAxisForChild(child, baseline_axis))
-    return child.MarginLogicalHeight() + child.LogicalHeight() - ascent;
-  return child.MarginLogicalWidth() + child.LogicalWidth() - ascent;
-}
-
-bool GridBaselineAlignment::IsDescentBaselineForChild(
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  return IsHorizontalBaselineAxis(baseline_axis) &&
-         ((child.StyleRef().IsFlippedBlocksWritingMode() &&
-           !IsFlippedBlocksWritingMode(block_flow_)) ||
-          (child.StyleRef().IsFlippedLinesWritingMode() &&
-           IsFlippedBlocksWritingMode(block_flow_)));
-}
-
-bool GridBaselineAlignment::IsHorizontalBaselineAxis(GridAxis axis) const {
-  return axis == kGridRowAxis ? IsHorizontalWritingMode(block_flow_)
-                              : !IsHorizontalWritingMode(block_flow_);
-}
-
-bool GridBaselineAlignment::IsOrthogonalChildForBaseline(
-    const LayoutBox& child) const {
-  return IsHorizontalWritingMode(block_flow_) !=
-         child.IsHorizontalWritingMode();
-}
-
-bool GridBaselineAlignment::IsParallelToBaselineAxisForChild(
-    const LayoutBox& child,
-    GridAxis axis) const {
-  return axis == kGridColumnAxis ? !IsOrthogonalChildForBaseline(child)
-                                 : IsOrthogonalChildForBaseline(child);
-}
-
-const BaselineGroup& GridBaselineAlignment::GetBaselineGroupForChild(
-    ItemPosition preference,
-    unsigned shared_context,
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  DCHECK(IsBaselinePosition(preference));
-  bool is_row_axis_context = baseline_axis == kGridColumnAxis;
-  auto& contexts_map = is_row_axis_context ? row_axis_alignment_context_
-                                           : col_axis_alignment_context_;
-  auto* context = contexts_map.at(shared_context);
-  DCHECK(context);
-  return context->GetSharedGroup(child, preference);
-}
-
-void GridBaselineAlignment::UpdateBaselineAlignmentContext(
-    ItemPosition preference,
-    unsigned shared_context,
-    const LayoutBox& child,
-    GridAxis baseline_axis) {
-  DCHECK(IsBaselinePosition(preference));
-  DCHECK(!child.NeedsLayout());
-
-  // Determine Ascent and Descent values of this child with respect to
-  // its grid container.
-  LayoutUnit ascent = AscentForChild(child, baseline_axis);
-  LayoutUnit descent = DescentForChild(child, ascent, baseline_axis);
-  if (IsDescentBaselineForChild(child, baseline_axis))
-    std::swap(ascent, descent);
-
-  // Looking up for a shared alignment context perpendicular to the
-  // baseline axis.
-  bool is_row_axis_context = baseline_axis == kGridColumnAxis;
-  auto& contexts_map = is_row_axis_context ? row_axis_alignment_context_
-                                           : col_axis_alignment_context_;
-  auto add_result = contexts_map.insert(shared_context, nullptr);
-
-  // Looking for a compatible baseline-sharing group.
-  if (add_result.is_new_entry) {
-    add_result.stored_value->value = MakeGarbageCollected<BaselineContext>(
-        child, preference, ascent, descent);
-  } else {
-    BaselineContext* context = add_result.stored_value->value;
-    context->UpdateSharedGroup(child, preference, ascent, descent);
-  }
-}
-
-LayoutUnit GridBaselineAlignment::BaselineOffsetForChild(
-    ItemPosition preference,
-    unsigned shared_context,
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  DCHECK(IsBaselinePosition(preference));
-  auto& group = GetBaselineGroupForChild(preference, shared_context, child,
-                                         baseline_axis);
-  if (group.size() > 1) {
-    return group.MaxAscent() - LogicalAscentForChild(child, baseline_axis);
-  }
-  return LayoutUnit();
-}
-
-void GridBaselineAlignment::Clear(GridAxis baseline_axis) {
-  if (baseline_axis == kGridColumnAxis)
-    row_axis_alignment_context_.clear();
-  else
-    col_axis_alignment_context_.clear();
-}
-
-BaselineGroup::BaselineGroup(WritingMode block_flow,
-                             ItemPosition child_preference)
-    : max_ascent_(0), max_descent_(0), items_() {
-  block_flow_ = block_flow;
-  preference_ = child_preference;
-}
-
-void BaselineGroup::Update(const LayoutBox& child,
-                           LayoutUnit ascent,
-                           LayoutUnit descent) {
-  if (items_.insert(&child).is_new_entry) {
-    max_ascent_ = std::max(max_ascent_, ascent);
-    max_descent_ = std::max(max_descent_, descent);
-  }
-}
-
-bool BaselineGroup::IsOppositeBlockFlow(WritingMode block_flow) const {
-  switch (block_flow) {
-    case WritingMode::kHorizontalTb:
-      return false;
-    case WritingMode::kVerticalLr:
-      return block_flow_ == WritingMode::kVerticalRl;
-    case WritingMode::kVerticalRl:
-      return block_flow_ == WritingMode::kVerticalLr;
-    default:
-      NOTREACHED();
-      return false;
-  }
-}
-
-bool BaselineGroup::IsOrthogonalBlockFlow(WritingMode block_flow) const {
-  switch (block_flow) {
-    case WritingMode::kHorizontalTb:
-      return block_flow_ != WritingMode::kHorizontalTb;
-    case WritingMode::kVerticalLr:
-    case WritingMode::kVerticalRl:
-      return block_flow_ == WritingMode::kHorizontalTb;
-    default:
-      NOTREACHED();
-      return false;
-  }
-}
-
-bool BaselineGroup::IsCompatible(WritingMode child_block_flow,
-                                 ItemPosition child_preference) const {
-  DCHECK(IsBaselinePosition(child_preference));
-  DCHECK_GT(size(), 0);
-  return ((block_flow_ == child_block_flow ||
-           IsOrthogonalBlockFlow(child_block_flow)) &&
-          preference_ == child_preference) ||
-         (IsOppositeBlockFlow(child_block_flow) &&
-          preference_ != child_preference);
-}
-
-BaselineContext::BaselineContext(const LayoutBox& child,
-                                 ItemPosition preference,
-                                 LayoutUnit ascent,
-                                 LayoutUnit descent) {
-  DCHECK(IsBaselinePosition(preference));
-  UpdateSharedGroup(child, preference, ascent, descent);
-}
-
-const BaselineGroup& BaselineContext::GetSharedGroup(
-    const LayoutBox& child,
-    ItemPosition preference) const {
-  DCHECK(IsBaselinePosition(preference));
-  return const_cast<BaselineContext*>(this)->FindCompatibleSharedGroup(
-      child, preference);
-}
-
-void BaselineContext::UpdateSharedGroup(const LayoutBox& child,
-                                        ItemPosition preference,
-                                        LayoutUnit ascent,
-                                        LayoutUnit descent) {
-  DCHECK(IsBaselinePosition(preference));
-  BaselineGroup& group = FindCompatibleSharedGroup(child, preference);
-  group.Update(child, ascent, descent);
-}
-
-// TODO Properly implement baseline-group compatibility
-// See https://github.com/w3c/csswg-drafts/issues/721
-BaselineGroup& BaselineContext::FindCompatibleSharedGroup(
-    const LayoutBox& child,
-    ItemPosition preference) {
-  WritingMode block_direction = child.StyleRef().GetWritingMode();
-  for (auto& group : shared_groups_) {
-    if (group.IsCompatible(block_direction, preference))
-      return group;
-  }
-  shared_groups_.push_front(BaselineGroup(block_direction, preference));
-  return shared_groups_[0];
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid_baseline_alignment.h b/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
deleted file mode 100644
index b6ff861a..0000000
--- a/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_BASELINE_ALIGNMENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_BASELINE_ALIGNMENT_H_
-
-#include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-// These classes are used to implement the Baseline Alignment logic, as
-// described in the CSS Box Alignment specification.
-// https://drafts.csswg.org/css-align/#baseline-terms
-
-// A baseline-sharing group is composed of boxes that participate in
-// baseline alignment together. This is possible only if they:
-//
-//   * Share an alignment context along an axis perpendicular to their
-//   baseline alignment axis.
-//   * Have compatible baseline alignment preferences (i.e., the baselines
-//   that want to align are on the same side of the alignment context).
-//
-// Once the BaselineGroup is instantiated, defined by a
-// 'block-direction' (WritingMode) and a 'baseline-preference'
-// (first/last baseline), it's ready to collect the items that will
-// participate in the Baseline Alignment logic.
-//
-// The 'Update' method is used to store an item (if not already
-// present) and update the max_ascent and max_descent associated to
-// this baseline-sharing group.
-class BaselineGroup {
-  DISALLOW_NEW();
-
- public:
-  void Update(const LayoutBox&, LayoutUnit ascent, LayoutUnit descent);
-  LayoutUnit MaxAscent() const { return max_ascent_; }
-  LayoutUnit MaxDescent() const { return max_descent_; }
-  int size() const { return items_.size(); }
-  void Trace(Visitor* visitor) const { visitor->Trace(items_); }
-
- private:
-  friend class BaselineContext;
-  BaselineGroup(WritingMode block_flow, ItemPosition child_preference);
-
-  // Determines whether a baseline-sharing group is compatible with an
-  // item, based on its 'block-flow' and 'baseline-preference'
-  bool IsCompatible(WritingMode, ItemPosition) const;
-
-  // Determines whether the baseline-sharing group's associated
-  // block-flow is opposite (LR vs RL) to particular item's
-  // writing-mode.
-  bool IsOppositeBlockFlow(WritingMode block_flow) const;
-
-  // Determines whether the baseline-sharing group's associated
-  // block-flow is orthogonal (vertical vs horizontal) to particular
-  // item's writing-mode.
-  bool IsOrthogonalBlockFlow(WritingMode block_flow) const;
-
-  WritingMode block_flow_;
-  ItemPosition preference_;
-  LayoutUnit max_ascent_;
-  LayoutUnit max_descent_;
-  HeapHashSet<Member<const LayoutBox>> items_;
-};
-
-// Boxes share an alignment context along a particular axis when they
-// are:
-//
-//  * table cells in the same row, along the table's row (inline) axis
-//  * table cells in the same column, along the table's column (block)
-//  axis
-//  * grid items in the same row, along the grid's row (inline) axis
-//  * grid items in the same column, along the grid's colum (block) axis
-//  * flex items in the same flex line, along the flex container's main
-//  axis
-//
-// A Baseline alignment-context may handle several baseline-sharing
-// groups. In order to create an instance, we need to pass the
-// required data to define the first baseline-sharing group; a
-// Baseline Context must have at least one baseline-sharing group.
-//
-// By adding new items to a Baseline Context, the baseline-sharing
-// groups it handles are automatically updated, if there is one that
-// is compatible with such item. Otherwise, a new baseline-sharing
-// group is created, compatible with the new item.
-class BaselineContext : public GarbageCollected<BaselineContext> {
- public:
-  BaselineContext(const LayoutBox& child,
-                  ItemPosition preference,
-                  LayoutUnit ascent,
-                  LayoutUnit descent);
-  HeapVector<BaselineGroup>& SharedGroups() { return shared_groups_; }
-  const BaselineGroup& GetSharedGroup(const LayoutBox& child,
-                                      ItemPosition preference) const;
-
-  // Updates the baseline-sharing group compatible with the item.
-  // We pass the item's baseline-preference to avoid dependencies with
-  // the LayoutGrid class, which is the one managing the alignment
-  // behavior of the Grid Items.
-  void UpdateSharedGroup(const LayoutBox& child,
-                         ItemPosition preference,
-                         LayoutUnit ascent,
-                         LayoutUnit descent);
-
-  void Trace(Visitor* visitor) const { visitor->Trace(shared_groups_); }
-
- private:
-  // Returns the baseline-sharing group compatible with an item.
-  // We pass the item's baseline-preference to avoid dependencies with
-  // the LayoutGrid class, which is the one managing the alignment
-  // behavior of the Grid Items.
-  // TODO Properly implement baseline-group compatibility
-  // See https://github.com/w3c/csswg-drafts/issues/721
-  BaselineGroup& FindCompatibleSharedGroup(const LayoutBox& child,
-                                           ItemPosition preference);
-
-  HeapVector<BaselineGroup> shared_groups_;
-};
-
-static inline bool IsBaselinePosition(ItemPosition position) {
-  return position == ItemPosition::kBaseline ||
-         position == ItemPosition::kLastBaseline;
-}
-
-// This is the class that implements the Baseline Alignment logic,
-// using internally the BaselineContext and BaselineGroupd classes
-// (described above).
-//
-// The first phase is to collect the items that will participate in
-// baseline alignment together. During this phase the required
-// baseline- sharing groups will be created for each Baseline
-// alignment-context shared by the items participating in the baseline
-// alignment.
-//
-// Additionally, the baseline-sharing groups' offsets, max-ascend and
-// max-descent will be computed and stored. This class also computes
-// the baseline offset for a particular item, based on the max-ascent
-// for its associated baseline-sharing group.
-class GridBaselineAlignment {
-  DISALLOW_NEW();
-
- public:
-  // Collects the items participating in baseline alignment and
-  // updates the corresponding baseline-sharing group of the Baseline
-  // Context the items belongs to.
-  // All the baseline offsets are updated accordingly based on the
-  // added item.
-  void UpdateBaselineAlignmentContext(ItemPosition,
-                                      unsigned shared_context,
-                                      const LayoutBox&,
-                                      GridAxis);
-
-  // Returns the baseline offset of a particular item, based on the
-  // max-ascent for its associated baseline-sharing group
-  LayoutUnit BaselineOffsetForChild(ItemPosition,
-                                    unsigned shared_context,
-                                    const LayoutBox&,
-                                    GridAxis) const;
-
-  // Sets the Grid Container's writing-mode so that we can avoid the
-  // dependecy of the LayoutGrid class for determining whether a grid
-  // item is orthogonal or not.
-  void SetBlockFlow(WritingMode block_flow) { block_flow_ = block_flow; }
-
-  // Clearing the Baseline Alignment context and their internal
-  // classes and data structures.
-  void Clear(GridAxis);
-
-  void Trace(Visitor* visitor) const {
-    visitor->Trace(row_axis_alignment_context_);
-    visitor->Trace(col_axis_alignment_context_);
-  }
-
- private:
-  const BaselineGroup& GetBaselineGroupForChild(ItemPosition,
-                                                unsigned shared_context,
-                                                const LayoutBox&,
-                                                GridAxis) const;
-  LayoutUnit MarginOverForChild(const LayoutBox&, GridAxis) const;
-  LayoutUnit MarginUnderForChild(const LayoutBox&, GridAxis) const;
-  LayoutUnit LogicalAscentForChild(const LayoutBox&, GridAxis) const;
-  LayoutUnit AscentForChild(const LayoutBox&, GridAxis) const;
-  LayoutUnit DescentForChild(const LayoutBox&, LayoutUnit, GridAxis) const;
-  bool IsDescentBaselineForChild(const LayoutBox&, GridAxis) const;
-  bool IsHorizontalBaselineAxis(GridAxis) const;
-  bool IsOrthogonalChildForBaseline(const LayoutBox&) const;
-  bool IsParallelToBaselineAxisForChild(const LayoutBox&, GridAxis) const;
-
-  typedef HeapHashMap<unsigned,
-                      Member<BaselineContext>,
-                      IntWithZeroKeyHashTraits<unsigned>>
-      BaselineContextsMap;
-
-  // Grid Container's WritingMode, used to determine grid item's orthogonality.
-  WritingMode block_flow_;
-  BaselineContextsMap row_axis_alignment_context_;
-  BaselineContextsMap col_axis_alignment_context_;
-};
-
-}  // namespace blink
-
-WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::BaselineGroup)
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_BASELINE_ALIGNMENT_H_
diff --git a/third_party/blink/renderer/core/layout/grid_layout_utils.cc b/third_party/blink/renderer/core/layout/grid_layout_utils.cc
deleted file mode 100644
index aaaf55a..0000000
--- a/third_party/blink/renderer/core/layout/grid_layout_utils.cc
+++ /dev/null
@@ -1,126 +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 "third_party/blink/renderer/core/layout/grid_layout_utils.h"
-
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
-
-namespace blink {
-
-static inline bool MarginStartIsAuto(const LayoutBox& child,
-                                     GridTrackSizingDirection direction) {
-  return direction == kForColumns ? child.StyleRef().MarginStart().IsAuto()
-                                  : child.StyleRef().MarginBefore().IsAuto();
-}
-
-static inline bool MarginEndIsAuto(const LayoutBox& child,
-                                   GridTrackSizingDirection direction) {
-  return direction == kForColumns ? child.StyleRef().MarginEnd().IsAuto()
-                                  : child.StyleRef().MarginAfter().IsAuto();
-}
-
-static bool ChildHasMargin(const LayoutBox& child,
-                           GridTrackSizingDirection direction) {
-  // Length::IsZero returns true for 'auto' margins, which is aligned with the
-  // purpose of this function.
-  if (direction == kForColumns) {
-    return !child.StyleRef().MarginStart().IsZero() ||
-           !child.StyleRef().MarginEnd().IsZero();
-  }
-  return !child.StyleRef().MarginBefore().IsZero() ||
-         !child.StyleRef().MarginAfter().IsZero();
-}
-
-static LayoutUnit ComputeMarginLogicalSizeForChild(
-    const LayoutGrid& grid,
-    MarginDirection for_direction,
-    const LayoutBox& child) {
-  bool is_inline_direction = for_direction == kInlineDirection;
-  GridTrackSizingDirection direction =
-      is_inline_direction ? kForColumns : kForRows;
-  if (!ChildHasMargin(child, direction))
-    return LayoutUnit();
-
-  LayoutUnit margin_start;
-  LayoutUnit margin_end;
-  LayoutUnit logical_size =
-      is_inline_direction ? child.LogicalWidth() : child.LogicalHeight();
-  const Length& margin_start_length = is_inline_direction
-                                          ? child.StyleRef().MarginStart()
-                                          : child.StyleRef().MarginBefore();
-  const Length& margin_end_length = is_inline_direction
-                                        ? child.StyleRef().MarginEnd()
-                                        : child.StyleRef().MarginAfter();
-  child.ComputeMarginsForDirection(
-      for_direction, &grid, child.ContainingBlockLogicalWidthForContent(),
-      logical_size, margin_start, margin_end, margin_start_length,
-      margin_end_length);
-
-  return MarginStartIsAuto(child, direction)
-             ? margin_end
-             : MarginEndIsAuto(child, direction) ? margin_start
-                                                 : margin_start + margin_end;
-}
-
-LayoutUnit GridLayoutUtils::MarginLogicalWidthForChild(const LayoutGrid& grid,
-                                                       const LayoutBox& child) {
-  if (child.NeedsLayout())
-    return ComputeMarginLogicalSizeForChild(grid, kInlineDirection, child);
-  // TODO(rego): Evaluate the possibility of using
-  // LayoutBlock::MarginIntrinsicLogicalWidthForChild() (note that this is
-  // protected so it cannot be directly used right now) or some similar method
-  // for this case.
-  LayoutUnit margin_start = child.StyleRef().MarginStart().IsAuto()
-                                ? LayoutUnit()
-                                : child.MarginStart();
-  LayoutUnit margin_end =
-      child.StyleRef().MarginEnd().IsAuto() ? LayoutUnit() : child.MarginEnd();
-  return margin_start + margin_end;
-}
-
-LayoutUnit GridLayoutUtils::MarginLogicalHeightForChild(
-    const LayoutGrid& grid,
-    const LayoutBox& child) {
-  if (child.NeedsLayout())
-    return ComputeMarginLogicalSizeForChild(grid, kBlockDirection, child);
-  LayoutUnit margin_before = child.StyleRef().MarginBefore().IsAuto()
-                                 ? LayoutUnit()
-                                 : child.MarginBefore();
-  LayoutUnit margin_after = child.StyleRef().MarginAfter().IsAuto()
-                                ? LayoutUnit()
-                                : child.MarginAfter();
-  return margin_before + margin_after;
-}
-
-bool GridLayoutUtils::IsOrthogonalChild(const LayoutGrid& grid,
-                                        const LayoutBox& child) {
-  return child.IsHorizontalWritingMode() != grid.IsHorizontalWritingMode();
-}
-
-GridTrackSizingDirection GridLayoutUtils::FlowAwareDirectionForChild(
-    const LayoutGrid& grid,
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  return !IsOrthogonalChild(grid, child)
-             ? direction
-             : (direction == kForColumns ? kForRows : kForColumns);
-}
-
-bool GridLayoutUtils::HasOverrideContainingBlockContentSizeForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  return direction == kForColumns
-             ? child.HasOverrideContainingBlockContentLogicalWidth()
-             : child.HasOverrideContainingBlockContentLogicalHeight();
-}
-
-LayoutUnit GridLayoutUtils::OverrideContainingBlockContentSizeForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  return direction == kForColumns
-             ? child.OverrideContainingBlockContentLogicalWidth()
-             : child.OverrideContainingBlockContentLogicalHeight();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid_layout_utils.h b/third_party/blink/renderer/core/layout/grid_layout_utils.h
deleted file mode 100644
index a28c338..0000000
--- a/third_party/blink/renderer/core/layout/grid_layout_utils.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LAYOUT_UTILS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LAYOUT_UTILS_H_
-
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-enum GridAxis { kGridRowAxis, kGridColumnAxis };
-
-class LayoutGrid;
-
-class GridLayoutUtils {
-  STATIC_ONLY(GridLayoutUtils);
-
- public:
-  static LayoutUnit MarginLogicalWidthForChild(const LayoutGrid&,
-                                               const LayoutBox&);
-  static LayoutUnit MarginLogicalHeightForChild(const LayoutGrid&,
-                                                const LayoutBox&);
-  static bool IsOrthogonalChild(const LayoutGrid&, const LayoutBox&);
-  static GridTrackSizingDirection FlowAwareDirectionForChild(
-      const LayoutGrid&,
-      const LayoutBox&,
-      GridTrackSizingDirection);
-  static bool HasOverrideContainingBlockContentSizeForChild(
-      const LayoutBox&,
-      GridTrackSizingDirection);
-  static LayoutUnit OverrideContainingBlockContentSizeForChild(
-      const LayoutBox&,
-      GridTrackSizingDirection);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LAYOUT_UTILS_H_
diff --git a/third_party/blink/renderer/core/layout/grid_linked_list.h b/third_party/blink/renderer/core/layout/grid_linked_list.h
deleted file mode 100644
index a7403d3a..0000000
--- a/third_party/blink/renderer/core/layout/grid_linked_list.h
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LINKED_LIST_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LINKED_LIST_H_
-
-#include "base/check_op.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/member.h"
-#include "third_party/blink/renderer/platform/heap/visitor.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-// GridLinkedList has structure of doubly linked list, and is garbage
-// collected. Its use is intended for CSS Grid Layout.
-//
-// In order to use, define a class that inherits GridLinkedListNodeBase.
-// This will give MyNode previous and next pointers.
-//
-//   class MyNode : public GridLinkedListNodeBase<MyNode> {
-//     ...
-//   };
-//
-// When initializing MyNode and GridLinkedList instance, make them garbage
-// collected.
-//
-//   Persistent<GridLinkedList<MyNode>> gll =
-//       MakeGarbageCollected<GridLinkedList<MyNode>>();
-//
-//   MyNode* node1 = MakeGarbageCollected<MyNode>(var1);
-//
-// For adding and removing nodes, use the following functions.
-//
-//   gll->Append(node);         add the given node at tail
-//   gll->Push(node);           add the given node at head
-//   gll->Remove(node);         remove the given node from list and connect the
-//                              node before and after
-//
-// In order to obtain information of list, use
-//
-//   gll->IsEmpty();            returns true if the list is empty
-//   gll->Size();               returns the size of list
-//
-// It can also be used for making an ordered list. For this, use the following
-// function solely.
-//
-//   gll->Insert(node, compare_func);
-//
-// This function inserts the given node before the first element that is
-// larger than the node according to the compare_func. However, if there is
-// already a same element in the list, nothing will be done to the list. Return
-// values will be {node, true} in the first case, and {<node of the same value>,
-// false} in the latter case.
-//
-
-namespace blink {
-
-template <typename NodeType>
-class GridLinkedList;
-
-// A class defining the type of node in the GridLinkedList should inherit
-// GridLinkedListNodeBase. This will give previous and next pointer for the
-// node, as well as apply garbage collection to all nodes.
-template <typename NodeType>
-class GridLinkedListNodeBase
-    : public GarbageCollected<GridLinkedListNodeBase<NodeType>> {
- public:
-  GridLinkedListNodeBase() = default;
-  virtual ~GridLinkedListNodeBase() = default;
-
-  NodeType* Prev() const { return prev_; }
-  NodeType* Next() const { return next_; }
-
-  virtual void Trace(Visitor* visitor) const {
-    visitor->Trace(prev_);
-    visitor->Trace(next_);
-  }
-
- protected:
-  friend class GridLinkedList<NodeType>;
-  void SetPrev(NodeType* prev) { prev_ = prev; }
-  void SetNext(NodeType* next) { next_ = next; }
-
- private:
-  Member<NodeType> prev_;
-  Member<NodeType> next_;
-};
-
-// GridLinkedList has data structure of doubly linked list, and its use is
-// intended for CSS Grid Layout. NodeType must inherit GridLinkedListNodeBase.
-template <typename NodeType>
-class GridLinkedList : public GarbageCollected<GridLinkedList<NodeType>> {
- public:
-  GridLinkedList() {
-    static_assert(IsGarbageCollectedType<NodeType>::value,
-                  "NodeType must be a garbage collected object.");
-    static_assert(
-        std::is_base_of<GridLinkedListNodeBase<NodeType>, NodeType>::value,
-        "NodeType should inherit GridLinkedListNodeBase.");
-  }
-
-  NodeType* Head() const { return head_; }
-  NodeType* Tail() const { return tail_; }
-
-  bool IsEmpty() { return !head_; }
-  void Clear();
-
-  // Returns the size of the list. O(n).
-  int Size();
-
-  // Adds node at the tail of the grid linked list. The node to add should not
-  // have adjacent nodes, nor has already been added to the list.
-  void Append(NodeType* node);
-
-  // Adds node at the head of the grid linked list. The node to add should not
-  // have adjacent nodes, nor has already been added to the list.
-  void Push(NodeType* node);
-
-  // Removes specified node from the list. If they exist, previous node and the
-  // next node will be connected. This function should not be called when the
-  // list is empty.
-  void Remove(NodeType* node);
-
-  struct AddResult {
-    STACK_ALLOCATED();
-
-   public:
-    NodeType* node;
-    bool is_new_entry;
-
-    explicit operator bool() const { return is_new_entry; }
-  };
-
-  // Inserts node in sorted order. By using only Insert(), the list will be
-  // sorted. Returns two values of AddResult type, 'node' and 'is_new_entry'.
-  // 'node' is the inserted node, or the corresponding node if the element was
-  // already in the list. 'is_new_entry' shows if the node is a new entry and
-  // the list operation is performed.
-
-  // CompareFunc should return <0 if the first argument is smaller than the
-  // second argument, 0 if they are equal, and >0 if the second argument is
-  // smaller.
-  template <typename CompareFunc>
-  AddResult Insert(NodeType* node, const CompareFunc& compare_func);
-
-  // Inserts node after a specified node. If 'prev_node' is null, 'node' will be
-  // added at head. Returns {node, true}.
-  AddResult InsertAfter(NodeType* node, NodeType* prev_node);
-
-  // Set objects to trace for garbage collection.
-  void Trace(Visitor* visitor) const {
-    visitor->Trace(head_);
-    visitor->Trace(tail_);
-  }
-
- private:
-  Member<NodeType> head_;
-  Member<NodeType> tail_;
-};
-
-template <typename NodeType>
-void GridLinkedList<NodeType>::Clear() {
-  head_.Clear();
-  tail_.Clear();
-}
-
-template <typename NodeType>
-int GridLinkedList<NodeType>::Size() {
-  int len = 0;
-  NodeType* node = head_;
-  while (node) {
-    node = node->Next();
-    len++;
-  }
-  return len;
-}
-
-template <typename NodeType>
-void GridLinkedList<NodeType>::Append(NodeType* node) {
-  DCHECK(node);
-  DCHECK(!node->Prev());
-  DCHECK(!node->Next());
-  DCHECK_NE(node, head_);
-  if (!head_) {
-    DCHECK(!tail_);
-    head_ = node;
-    tail_ = node;
-  } else {
-    node->SetPrev(tail_);
-    tail_->SetNext(node);
-    tail_ = node;
-  }
-}
-
-template <typename NodeType>
-void GridLinkedList<NodeType>::Push(NodeType* node) {
-  DCHECK(node);
-  DCHECK(!node->Prev());
-  DCHECK(!node->Next());
-  DCHECK_NE(node, head_);
-  if (!head_) {
-    DCHECK(!tail_);
-    head_ = node;
-    tail_ = node;
-  } else {
-    head_->SetPrev(node);
-    node->SetNext(head_);
-    head_ = node;
-  }
-}
-
-template <typename NodeType>
-void GridLinkedList<NodeType>::Remove(NodeType* node) {
-  DCHECK(node);
-  if (node->Prev()) {
-    DCHECK_NE(node, head_);
-    node->Prev()->SetNext(node->Next());
-  } else {
-    DCHECK_EQ(node, head_);
-    head_ = node->Next();
-  }
-  if (node->Next()) {
-    DCHECK_NE(node, tail_);
-    node->Next()->SetPrev(node->Prev());
-  } else {
-    DCHECK_EQ(node, tail_);
-    tail_ = node->Prev();
-  }
-}
-
-template <typename NodeType>
-template <typename CompareFunc>
-typename GridLinkedList<NodeType>::AddResult GridLinkedList<NodeType>::Insert(
-    NodeType* node,
-    const CompareFunc& compare_func) {
-  DCHECK(node);
-  for (NodeType* iter_node = head_; iter_node; iter_node = iter_node->Next()) {
-    int diff = compare_func(iter_node, node);
-    if (!diff)
-      return {iter_node, false};
-    if (diff > 0)
-      return InsertAfter(node, iter_node->Prev());
-  }
-  return InsertAfter(node, tail_);
-}
-
-template <typename NodeType>
-typename GridLinkedList<NodeType>::AddResult
-GridLinkedList<NodeType>::InsertAfter(NodeType* node, NodeType* prev_node) {
-  DCHECK(node);
-  if (!prev_node) {
-    Push(node);
-    DCHECK_EQ(node, head_);
-    return {node, true};
-  }
-  node->SetNext(prev_node->Next());
-  if (!prev_node->Next()) {
-    DCHECK_EQ(prev_node, tail_);
-    tail_ = node;
-  } else {
-    DCHECK_NE(prev_node, tail_);
-    prev_node->Next()->SetPrev(node);
-  }
-  prev_node->SetNext(node);
-  node->SetPrev(prev_node);
-  return {node, true};
-}
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_LINKED_LIST_H_
diff --git a/third_party/blink/renderer/core/layout/grid_linked_list_test.cc b/third_party/blink/renderer/core/layout/grid_linked_list_test.cc
deleted file mode 100644
index 0979273..0000000
--- a/third_party/blink/renderer/core/layout/grid_linked_list_test.cc
+++ /dev/null
@@ -1,168 +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 "third_party/blink/renderer/core/layout/grid_linked_list.h"
-
-#include <atomic>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/heap/thread_state.h"
-
-namespace blink {
-
-namespace {
-
-// IntNode defines a node class inheriting GridLinkedListNodeBase, with a member
-// of value (int). It can be applied for NodeType in the GridLinkedList.
-class IntNode : public GridLinkedListNodeBase<IntNode> {
- public:
-  explicit IntNode(int value) : value_(value) {}
-  ~IntNode() override {
-    destructor_calls.fetch_add(1, std::memory_order_relaxed);
-  }
-
-  int Value() const { return value_; }
-
-  static int Compare(IntNode* a, IntNode* b);
-
-  static std::atomic_int destructor_calls;
-
- private:
-  int value_ = -1;
-};
-
-int IntNode::Compare(IntNode* a, IntNode* b) {
-  DCHECK(a);
-  DCHECK(b);
-  return a->Value() - b->Value();
-}
-
-std::atomic_int IntNode::destructor_calls{0};
-
-class GridLinkedListTest : public testing::Test {
- public:
-  void SetUp() override;
-
-  template <typename NodeType>
-  static NodeType* NthElement(GridLinkedList<NodeType>* gll, int n);
-
-  template <typename NodeType, typename CompareFunc>
-  static bool IsSorted(GridLinkedList<NodeType>* gll,
-                       const CompareFunc& compare_func);
-};
-
-void GridLinkedListTest::SetUp() {
-  IntNode::destructor_calls = 0;
-}
-
-// Helper function for obtaining the nth element (starting from 0) of
-// GridLinkedList. n should be smaller than the size of the list.
-template <typename NodeType>
-NodeType* GridLinkedListTest::NthElement(GridLinkedList<NodeType>* gll, int n) {
-  DCHECK(gll);
-  DCHECK_LT(n, gll->Size());
-  NodeType* node = gll->Head();
-  for (int i = 0; i < n; i++) {
-    node = node->Next();
-  }
-  return node;
-}
-
-template <typename NodeType, typename CompareFunc>
-bool GridLinkedListTest::IsSorted(GridLinkedList<NodeType>* gll,
-                                  const CompareFunc& compare_func) {
-  DCHECK(gll);
-  for (NodeType* node = gll->Head(); node && node->Next();
-       node = node->Next()) {
-    if (compare_func(node, node->Next()) >= 0)
-      return false;
-  }
-  return true;
-}
-
-}  // namespace
-
-TEST_F(GridLinkedListTest, IntNodeBasic) {
-  IntNode* num1 = MakeGarbageCollected<IntNode>(1);
-  IntNode* num2 = MakeGarbageCollected<IntNode>(2);
-  IntNode* num3 = MakeGarbageCollected<IntNode>(3);
-
-  Persistent<GridLinkedList<IntNode>> gll_persistent =
-      MakeGarbageCollected<GridLinkedList<IntNode>>();
-  GridLinkedList<IntNode>* gll = gll_persistent;
-
-  EXPECT_EQ(gll->Size(), 0);
-  EXPECT_TRUE(gll->IsEmpty());
-
-  gll->Append(num1);
-  EXPECT_EQ(gll->Size(), 1);
-  EXPECT_EQ(NthElement(gll, 0)->Value(), 1);
-
-  gll->Append(num2);
-  EXPECT_EQ(gll->Size(), 2);
-  EXPECT_EQ(NthElement(gll, 0)->Value(), 1);
-  EXPECT_EQ(NthElement(gll, 1)->Value(), 2);
-
-  gll->Push(num3);
-  EXPECT_EQ(gll->Size(), 3);
-  EXPECT_EQ(NthElement(gll, 0)->Value(), 3);
-  EXPECT_EQ(NthElement(gll, 1)->Value(), 1);
-  EXPECT_EQ(NthElement(gll, 2)->Value(), 2);
-
-  gll->Remove(num1);
-  EXPECT_EQ(gll->Size(), 2);
-  EXPECT_EQ(NthElement(gll, 0)->Value(), 3);
-  EXPECT_EQ(NthElement(gll, 1)->Value(), 2);
-
-  ThreadState::Current()->CollectAllGarbageForTesting();
-  EXPECT_EQ(1, IntNode::destructor_calls);
-
-  gll->Remove(num3);
-  EXPECT_EQ(gll->Size(), 1);
-  EXPECT_EQ(NthElement(gll, 0)->Value(), 2);
-
-  ThreadState::Current()->CollectAllGarbageForTesting();
-  EXPECT_EQ(2, IntNode::destructor_calls);
-
-  gll->Remove(num2);
-  EXPECT_EQ(gll->Size(), 0);
-  EXPECT_TRUE(gll->IsEmpty());
-
-  ThreadState::Current()->CollectAllGarbageForTesting();
-  EXPECT_EQ(3, IntNode::destructor_calls);
-}
-
-TEST_F(GridLinkedListTest, Insert) {
-  IntNode* num1 = MakeGarbageCollected<IntNode>(1);
-  IntNode* num2 = MakeGarbageCollected<IntNode>(2);
-  IntNode* num3 = MakeGarbageCollected<IntNode>(3);
-  IntNode* num2_again = MakeGarbageCollected<IntNode>(2);
-
-  Persistent<GridLinkedList<IntNode>> gll_persistent =
-      MakeGarbageCollected<GridLinkedList<IntNode>>();
-  GridLinkedList<IntNode>* gll = gll_persistent;
-  EXPECT_TRUE(IsSorted(gll, IntNode::Compare));
-
-  EXPECT_TRUE(gll->Insert(num2, IntNode::Compare));
-  EXPECT_TRUE(IsSorted(gll, IntNode::Compare));
-
-  EXPECT_TRUE(gll->Insert(num1, IntNode::Compare));
-  EXPECT_TRUE(IsSorted(gll, IntNode::Compare));
-
-  EXPECT_TRUE(gll->Insert(num3, IntNode::Compare));
-  EXPECT_TRUE(IsSorted(gll, IntNode::Compare));
-
-  EXPECT_FALSE(gll->Insert(num2_again, IntNode::Compare));
-  EXPECT_EQ(gll->Insert(num2_again, IntNode::Compare).node, num2);
-  EXPECT_TRUE(IsSorted(gll, IntNode::Compare));
-
-  gll->Clear();
-  DCHECK(gll->IsEmpty());
-  ThreadState::Current()->CollectAllGarbageForTesting();
-  EXPECT_EQ(4, IntNode::destructor_calls);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
deleted file mode 100644
index 65fe49c..0000000
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ /dev/null
@@ -1,1856 +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 "third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h"
-
-#include "third_party/blink/renderer/core/frame/web_feature.h"
-#include "third_party/blink/renderer/core/layout/grid.h"
-#include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
-#include "third_party/blink/renderer/platform/geometry/length_functions.h"
-
-namespace blink {
-
-class GridSizingData;
-
-LayoutUnit GridTrack::BaseSize() const {
-  DCHECK(IsGrowthLimitBiggerThanBaseSize());
-  return base_size_;
-}
-
-LayoutUnit GridTrack::GrowthLimit() const {
-  DCHECK(IsGrowthLimitBiggerThanBaseSize());
-  DCHECK(!growth_limit_cap_ || growth_limit_cap_.value() >= growth_limit_ ||
-         base_size_ >= growth_limit_cap_.value());
-  return growth_limit_;
-}
-
-void GridTrack::SetBaseSize(LayoutUnit base_size) {
-  base_size_ = base_size;
-  EnsureGrowthLimitIsBiggerThanBaseSize();
-}
-
-void GridTrack::SetGrowthLimit(LayoutUnit growth_limit) {
-  growth_limit_ =
-      growth_limit == kInfinity
-          ? growth_limit
-          : std::min(growth_limit, growth_limit_cap_.value_or(growth_limit));
-  EnsureGrowthLimitIsBiggerThanBaseSize();
-}
-
-bool GridTrack::InfiniteGrowthPotential() const {
-  return GrowthLimitIsInfinite() || infinitely_growable_;
-}
-
-void GridTrack::SetPlannedSize(LayoutUnit planned_size) {
-  DCHECK(planned_size >= 0 || planned_size == kInfinity);
-  planned_size_ = planned_size;
-}
-
-void GridTrack::SetSizeDuringDistribution(LayoutUnit size_during_distribution) {
-  DCHECK_GE(size_during_distribution, 0);
-  DCHECK(GrowthLimitIsInfinite() || GrowthLimit() >= size_during_distribution);
-  size_during_distribution_ = size_during_distribution;
-}
-
-void GridTrack::GrowSizeDuringDistribution(
-    LayoutUnit size_during_distribution) {
-  DCHECK_GE(size_during_distribution, 0);
-  size_during_distribution_ += size_during_distribution;
-}
-
-void GridTrack::SetInfinitelyGrowable(bool infinitely_growable) {
-  infinitely_growable_ = infinitely_growable;
-}
-
-void GridTrack::SetGrowthLimitCap(absl::optional<LayoutUnit> growth_limit_cap) {
-  DCHECK(!growth_limit_cap || *growth_limit_cap >= 0);
-  growth_limit_cap_ = growth_limit_cap;
-}
-
-void GridTrack::SetCachedTrackSize(const GridTrackSize& cached_track_size) {
-  cached_track_size_ = cached_track_size;
-}
-
-bool GridTrack::IsGrowthLimitBiggerThanBaseSize() const {
-  return GrowthLimitIsInfinite() || growth_limit_ >= base_size_;
-}
-
-void GridTrack::EnsureGrowthLimitIsBiggerThanBaseSize() {
-  if (growth_limit_ != kInfinity && growth_limit_ < base_size_)
-    growth_limit_ = base_size_;
-}
-
-static GridAxis GridAxisForDirection(GridTrackSizingDirection direction) {
-  return direction == kForColumns ? kGridRowAxis : kGridColumnAxis;
-}
-
-static GridTrackSizingDirection GridDirectionForAxis(GridAxis axis) {
-  return axis == kGridRowAxis ? kForColumns : kForRows;
-}
-
-template <typename F>
-static void IterateGridItemsInTrackIndices(const Grid& grid,
-                                           GridTrackSizingDirection direction,
-                                           Vector<wtf_size_t>& track_indices,
-                                           F callback) {
-#if DCHECK_IS_ON()
-  HeapHashSet<Member<LayoutBox>> items_set;
-#endif
-  for (wtf_size_t i = 0; i < track_indices.size(); ++i) {
-    auto* iterator = grid.CreateIterator(direction, track_indices[i]);
-    while (LayoutBox* grid_item = iterator->NextGridItem()) {
-      const GridSpan& span = grid.GridItemSpan(*grid_item, direction);
-      if (i > 0) {
-        // Skip items already processed in an earlier track.
-        DCHECK_LT(track_indices[i - 1], track_indices[i]);
-        if (span.StartLine() <= track_indices[i - 1])
-          continue;
-      }
-#if DCHECK_IS_ON()
-      DCHECK(items_set.insert(grid_item).is_new_entry);
-#endif
-      callback(grid_item, span);
-    }
-  }
-}
-
-class IndefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
- public:
-  IndefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm)
-      : GridTrackSizingAlgorithmStrategy(algorithm) {}
-
- private:
-  void LayoutGridItemForMinSizeComputation(
-      LayoutBox&,
-      bool override_size_has_changed) const override;
-  void MaximizeTracks(Vector<GridTrack>&,
-                      absl::optional<LayoutUnit>& free_space) override;
-  double FindUsedFlexFraction(
-      Vector<wtf_size_t>& flexible_sized_tracks_index,
-      GridTrackSizingDirection,
-      absl::optional<LayoutUnit> free_space) const override;
-  bool RecomputeUsedFlexFractionIfNeeded(
-      double& flex_fraction,
-      Vector<LayoutUnit>& increments,
-      LayoutUnit& total_growth) const override;
-  LayoutUnit FreeSpaceForStretchAutoTracksStep() const override;
-  LayoutUnit MinContentForChild(LayoutBox&) const override;
-  LayoutUnit MaxContentForChild(LayoutBox&) const override;
-  bool IsComputingSizeContainment() const override;
-};
-
-class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
- public:
-  DefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm)
-      : GridTrackSizingAlgorithmStrategy(algorithm) {}
-
- private:
-  void LayoutGridItemForMinSizeComputation(
-      LayoutBox&,
-      bool override_size_has_changed) const override;
-  void MaximizeTracks(Vector<GridTrack>&,
-                      absl::optional<LayoutUnit>& free_space) override;
-  double FindUsedFlexFraction(
-      Vector<wtf_size_t>& flexible_sized_tracks_index,
-      GridTrackSizingDirection,
-      absl::optional<LayoutUnit> free_space) const override;
-  bool RecomputeUsedFlexFractionIfNeeded(
-      double& flex_fraction,
-      Vector<LayoutUnit>& increments,
-      LayoutUnit& total_growth) const override {
-    return false;
-  }
-  LayoutUnit FreeSpaceForStretchAutoTracksStep() const override;
-  LayoutUnit MinContentForChild(LayoutBox&) const override;
-  LayoutUnit MinLogicalSizeForChild(LayoutBox&,
-                                    const Length& child_min_size,
-                                    LayoutUnit available_size) const override;
-  bool IsComputingSizeContainment() const override { return false; }
-};
-
-GridTrackSizingAlgorithmStrategy::~GridTrackSizingAlgorithmStrategy() = default;
-
-bool GridTrackSizingAlgorithmStrategy::HasRelativeMarginOrPaddingForChild(
-    const LayoutGrid& grid,
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(grid, child, kForColumns);
-  if (direction == child_inline_direction) {
-    return child.StyleRef().MarginStart().IsPercentOrCalc() ||
-           child.StyleRef().MarginEnd().IsPercentOrCalc() ||
-           child.StyleRef().PaddingStart().IsPercentOrCalc() ||
-           child.StyleRef().PaddingEnd().IsPercentOrCalc();
-  }
-  return child.StyleRef().MarginBefore().IsPercentOrCalc() ||
-         child.StyleRef().MarginAfter().IsPercentOrCalc() ||
-         child.StyleRef().PaddingBefore().IsPercentOrCalc() ||
-         child.StyleRef().PaddingAfter().IsPercentOrCalc();
-}
-
-bool GridTrackSizingAlgorithmStrategy::HasRelativeOrIntrinsicSizeForChild(
-    const LayoutGrid& grid,
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(grid, child, kForColumns);
-  if (direction == child_inline_direction) {
-    return child.HasRelativeLogicalWidth() ||
-           !child.StyleRef().LogicalWidth().IsSpecified();
-  }
-  return child.HasRelativeLogicalHeight() ||
-         !child.StyleRef().LogicalHeight().IsSpecified();
-}
-
-bool GridTrackSizingAlgorithmStrategy::
-    ShouldClearOverrideContainingBlockContentSizeForChild(
-        const LayoutGrid& grid,
-        const LayoutBox& child,
-        GridTrackSizingDirection direction) {
-  return HasRelativeOrIntrinsicSizeForChild(grid, child, direction) ||
-         HasRelativeMarginOrPaddingForChild(grid, child, direction);
-}
-
-void GridTrackSizingAlgorithmStrategy::
-    SetOverrideContainingBlockContentSizeForChild(
-        LayoutBox& child,
-        GridTrackSizingDirection direction,
-        LayoutUnit size) {
-  if (direction == kForColumns)
-    child.SetOverrideContainingBlockContentLogicalWidth(size);
-  else
-    child.SetOverrideContainingBlockContentLogicalHeight(size);
-}
-
-LayoutSize GridTrackSizingAlgorithm::EstimatedGridAreaBreadthForChild(
-    const LayoutBox& child) const {
-  return {EstimatedGridAreaBreadthForChild(child, kForColumns),
-          EstimatedGridAreaBreadthForChild(child, kForRows)};
-}
-
-LayoutUnit GridTrackSizingAlgorithm::EstimatedGridAreaBreadthForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  const GridSpan& span = grid_->GridItemSpan(child, direction);
-  LayoutUnit grid_area_size;
-  bool grid_area_is_indefinite = false;
-  absl::optional<LayoutUnit> available_size = AvailableSpace(direction);
-  for (auto track_position : span) {
-    // We may need to estimate the grid area size before running the track
-    // sizing algorithm in order to perform the pre-layout of orthogonal
-    // items.
-    // We cannot use Tracks(direction)[track_position].CachedTrackSize()
-    // because Tracks(direction) is empty, since we are either performing
-    // pre-layout or are running the track sizing algorithm in the opposite
-    // direction and haven't run it in the desired direction yet.
-    const GridTrackSize& track_size =
-        WasSetup() ? CalculateGridTrackSize(direction, track_position)
-                   : RawGridTrackSize(direction, track_position);
-    GridLength max_track_size = track_size.MaxTrackBreadth();
-    if (max_track_size.IsContentSized() || max_track_size.IsFlex() ||
-        IsRelativeGridLengthAsAuto(max_track_size, direction)) {
-      grid_area_is_indefinite = true;
-    } else {
-      grid_area_size += ValueForLength(max_track_size.length(),
-                                       available_size.value_or(LayoutUnit()));
-    }
-  }
-
-  grid_area_size += layout_grid_->GuttersSize(
-      *grid_, direction, span.StartLine(), span.IntegerSpan(), available_size);
-
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*layout_grid_, child,
-                                                  kForColumns);
-  if (grid_area_is_indefinite) {
-    return direction == child_inline_direction
-               ? std::max(child.PreferredLogicalWidths().max_size,
-                          grid_area_size)
-               : LayoutUnit(-1);
-  }
-  return grid_area_size;
-}
-
-LayoutUnit GridTrackSizingAlgorithm::GridAreaBreadthForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  bool add_content_alignment_offset =
-      direction == kForColumns && sizing_state_ == kRowSizingFirstIteration;
-  if (direction == kForRows &&
-      (sizing_state_ == kColumnSizingFirstIteration ||
-       sizing_state_ == kColumnSizingSecondIteration)) {
-    DCHECK(GridLayoutUtils::IsOrthogonalChild(*layout_grid_, child));
-    // TODO (jfernandez) Content Alignment should account for this heuristic
-    // https://github.com/w3c/csswg-drafts/issues/2697
-    if (sizing_state_ == kColumnSizingFirstIteration)
-      return EstimatedGridAreaBreadthForChild(child, kForRows);
-    add_content_alignment_offset = true;
-  }
-
-  const Vector<GridTrack>& all_tracks = Tracks(direction);
-  const GridSpan& span = grid_->GridItemSpan(child, direction);
-  LayoutUnit grid_area_breadth;
-  for (auto track_position : span)
-    grid_area_breadth += all_tracks[track_position].BaseSize();
-
-  if (add_content_alignment_offset) {
-    grid_area_breadth +=
-        (span.IntegerSpan() - 1) * layout_grid_->GridItemOffset(direction);
-  }
-
-  grid_area_breadth +=
-      layout_grid_->GuttersSize(*grid_, direction, span.StartLine(),
-                                span.IntegerSpan(), AvailableSpace(direction));
-
-  return grid_area_breadth;
-}
-
-bool GridTrackSizingAlgorithm::IsIntrinsicSizedGridArea(const LayoutBox& child,
-                                                        GridAxis axis) const {
-  DCHECK(WasSetup());
-  GridTrackSizingDirection direction = GridDirectionForAxis(axis);
-  const GridSpan& span = grid_->GridItemSpan(child, direction);
-  for (auto track_position : span) {
-    const GridTrackSize& track_size =
-        RawGridTrackSize(direction, track_position);
-    // We consider fr units as 'auto' for the min sizing function.
-    // TODO(jfernandez): https://github.com/w3c/csswg-drafts/issues/2611
-    //
-    // The use of AvailableSize function may imply different results
-    // for the same item when assuming indefinite or definite size
-    // constraints depending on the phase we evaluate the item's
-    // baseline participation.
-    // TODO(jfernandez): https://github.com/w3c/csswg-drafts/issues/3046
-    if (track_size.IsContentSized() || track_size.IsFitContent() ||
-        track_size.MinTrackBreadth().IsFlex() ||
-        (track_size.MaxTrackBreadth().IsFlex() && !AvailableSpace(direction)))
-      return true;
-  }
-  return false;
-}
-
-bool GridTrackSizingAlgorithmStrategy::
-    UpdateOverrideContainingBlockContentSizeForChild(
-        LayoutBox& child,
-        GridTrackSizingDirection direction,
-        absl::optional<LayoutUnit> override_size) const {
-  if (!override_size)
-    override_size = algorithm_->GridAreaBreadthForChild(child, direction);
-  if (GridLayoutUtils::OverrideContainingBlockContentSizeForChild(
-          child, direction) == override_size.value())
-    return false;
-
-  SetOverrideContainingBlockContentSizeForChild(child, direction,
-                                                override_size.value());
-  return true;
-}
-
-LayoutUnit GridTrackSizingAlgorithmStrategy::LogicalHeightForChild(
-    LayoutBox& child) const {
-  GridTrackSizingDirection child_block_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForRows);
-  // If |child| has a relative block-axis size, we shouldn't let it override its
-  // intrinsic size, which is what we are interested in here. Thus we
-  // need to set the block-axis OverrideContainingBlock size to -1 (no possible
-  // resolution).
-  if (ShouldClearOverrideContainingBlockContentSizeForChild(
-          *GetLayoutGrid(), child, child_block_direction)) {
-    SetOverrideContainingBlockContentSizeForChild(child, child_block_direction,
-                                                  LayoutUnit(-1));
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-  }
-
-  child.LayoutIfNeeded();
-
-  return child.LogicalHeight() +
-         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child) +
-         algorithm_->BaselineOffsetForChild(child,
-                                            GridAxisForDirection(Direction()));
-}
-
-DISABLE_CFI_PERF
-LayoutUnit GridTrackSizingAlgorithmStrategy::MinContentForChild(
-    LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  if (Direction() == child_inline_direction) {
-    // FIXME: It's unclear if we should return the intrinsic width or the
-    // preferred width.
-    // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
-    if (child.NeedsPreferredWidthsRecalculation())
-      child.SetIntrinsicLogicalWidthsDirty();
-    return child.PreferredLogicalWidths().min_size +
-           GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
-                                                       child) +
-           algorithm_->BaselineOffsetForChild(
-               child, GridAxisForDirection(Direction()));
-  }
-
-  if (UpdateOverrideContainingBlockContentSizeForChild(
-          child, child_inline_direction)) {
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-  }
-  return LogicalHeightForChild(child);
-}
-
-DISABLE_CFI_PERF
-LayoutUnit GridTrackSizingAlgorithmStrategy::MaxContentForChild(
-    LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  if (Direction() == child_inline_direction) {
-    // FIXME: It's unclear if we should return the intrinsic width or the
-    // preferred width.
-    // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
-    if (child.NeedsPreferredWidthsRecalculation())
-      child.SetIntrinsicLogicalWidthsDirty();
-    return child.PreferredLogicalWidths().max_size +
-           GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
-                                                       child) +
-           algorithm_->BaselineOffsetForChild(
-               child, GridAxisForDirection(Direction()));
-  }
-
-  if (UpdateOverrideContainingBlockContentSizeForChild(
-          child, child_inline_direction)) {
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-  }
-  return LogicalHeightForChild(child);
-}
-
-LayoutUnit GridTrackSizingAlgorithmStrategy::MinSizeForChild(
-    LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  bool is_row_axis = Direction() == child_inline_direction;
-  const Length& child_size = is_row_axis ? child.StyleRef().LogicalWidth()
-                                         : child.StyleRef().LogicalHeight();
-  if (!child_size.IsAuto() && !child_size.IsPercentOrCalc())
-    return MinContentForChild(child);
-
-  const Length& child_min_size = is_row_axis
-                                     ? child.StyleRef().LogicalMinWidth()
-                                     : child.StyleRef().LogicalMinHeight();
-  auto overflow = is_row_axis ? child.StyleRef().OverflowInlineDirection()
-                              : child.StyleRef().OverflowBlockDirection();
-  bool overflow_allows_auto =
-      overflow == EOverflow::kVisible || overflow == EOverflow::kClip;
-  LayoutUnit baseline_shim = algorithm_->BaselineOffsetForChild(
-      child, GridAxisForDirection(Direction()));
-
-  if (child_min_size.IsAuto() && overflow_allows_auto) {
-    LayoutUnit min_size = MinContentForChild(child);
-    const GridSpan& span =
-        algorithm_->GetGrid().GridItemSpan(child, Direction());
-    LayoutUnit max_breadth;
-    const Vector<GridTrack>& all_tracks = algorithm_->Tracks(Direction());
-    for (auto track_position : span) {
-      const GridTrackSize& track_size =
-          all_tracks[track_position].CachedTrackSize();
-      if (!track_size.HasFixedMaxTrackBreadth())
-        return min_size;
-      max_breadth += ValueForLength(track_size.MaxTrackBreadth().length(),
-                                    AvailableSpace().value_or(LayoutUnit()));
-    }
-    if (min_size > max_breadth) {
-      LayoutUnit margin_and_border_and_padding =
-          is_row_axis ? GridLayoutUtils::MarginLogicalWidthForChild(
-                            *GetLayoutGrid(), child) +
-                            child.BorderAndPaddingLogicalWidth()
-                      : GridLayoutUtils::MarginLogicalHeightForChild(
-                            *GetLayoutGrid(), child) +
-                            child.BorderAndPaddingLogicalHeight();
-      min_size =
-          std::max(max_breadth, margin_and_border_and_padding + baseline_shim);
-    }
-    return min_size;
-  }
-
-  LayoutUnit grid_area_size =
-      algorithm_->GridAreaBreadthForChild(child, child_inline_direction);
-  return MinLogicalSizeForChild(child, child_min_size, grid_area_size) +
-         baseline_shim;
-}
-
-bool GridTrackSizingAlgorithm::CanParticipateInBaselineAlignment(
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  DCHECK(baseline_axis == kGridColumnAxis
-             ? column_baseline_items_map_.Contains(&child)
-             : row_baseline_items_map_.Contains(&child));
-
-  // Baseline cyclic dependencies only happen with synthesized
-  // baselines. These cases include orthogonal or empty grid items
-  // and replaced elements.
-  bool is_parallel_to_baseline_axis =
-      baseline_axis == kGridColumnAxis
-          ? !GridLayoutUtils::IsOrthogonalChild(*layout_grid_, child)
-          : GridLayoutUtils::IsOrthogonalChild(*layout_grid_, child);
-  if (is_parallel_to_baseline_axis && child.FirstLineBoxBaseline() != -1)
-    return true;
-
-  // Baseline cyclic dependencies only happen in grid areas with
-  // intrinsically-sized tracks.
-  if (!IsIntrinsicSizedGridArea(child, baseline_axis))
-    return true;
-
-  return is_parallel_to_baseline_axis
-             ? !child.HasRelativeLogicalHeight()
-             : !child.HasRelativeLogicalWidth() &&
-                   !child.StyleRef().LogicalWidth().IsAuto();
-}
-
-bool GridTrackSizingAlgorithm::ParticipateInBaselineAlignment(
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  if (baseline_axis == kGridColumnAxis) {
-    auto it = column_baseline_items_map_.find(&child);
-    return it != column_baseline_items_map_.end() ? it->value : false;
-  }
-  auto it = row_baseline_items_map_.find(&child);
-  return it != row_baseline_items_map_.end() ? it->value : false;
-}
-
-void GridTrackSizingAlgorithm::UpdateBaselineAlignmentContext(
-    const LayoutBox& child,
-    GridAxis baseline_axis) {
-  DCHECK(WasSetup());
-  DCHECK(CanParticipateInBaselineAlignment(child, baseline_axis));
-  DCHECK(!child.NeedsLayout());
-
-  ItemPosition align =
-      layout_grid_->SelfAlignmentForChild(baseline_axis, child).GetPosition();
-  const auto& span =
-      grid_->GridItemSpan(child, GridDirectionForAxis(baseline_axis));
-  baseline_alignment_.UpdateBaselineAlignmentContext(align, span.StartLine(),
-                                                     child, baseline_axis);
-}
-
-LayoutUnit GridTrackSizingAlgorithm::BaselineOffsetForChild(
-    const LayoutBox& child,
-    GridAxis baseline_axis) const {
-  if (!ParticipateInBaselineAlignment(child, baseline_axis))
-    return LayoutUnit();
-
-  ItemPosition align =
-      layout_grid_->SelfAlignmentForChild(baseline_axis, child).GetPosition();
-  const auto& span =
-      grid_->GridItemSpan(child, GridDirectionForAxis(baseline_axis));
-  return baseline_alignment_.BaselineOffsetForChild(align, span.StartLine(),
-                                                    child, baseline_axis);
-}
-
-void GridTrackSizingAlgorithm::ClearBaselineItemsCache() {
-  column_baseline_items_map_.clear();
-  row_baseline_items_map_.clear();
-}
-
-void GridTrackSizingAlgorithm::CacheBaselineAlignedItem(const LayoutBox& item,
-                                                        GridAxis axis) {
-  DCHECK(layout_grid_->IsBaselineAlignmentForChild(item, axis));
-  if (axis == kGridColumnAxis)
-    column_baseline_items_map_.insert(&item, true);
-  else
-    row_baseline_items_map_.insert(&item, true);
-}
-
-void GridTrackSizingAlgorithm::CopyBaselineItemsCache(
-    const GridTrackSizingAlgorithm* source,
-    GridAxis axis) {
-  if (axis == kGridColumnAxis)
-    column_baseline_items_map_ = source->column_baseline_items_map_;
-  else
-    row_baseline_items_map_ = source->row_baseline_items_map_;
-}
-
-LayoutUnit GridTrackSizingAlgorithmStrategy::ComputeTrackBasedSize() const {
-  return algorithm_->ComputeTrackBasedSize();
-}
-
-double GridTrackSizingAlgorithmStrategy::FindFrUnitSize(
-    const GridSpan& tracks_span,
-    LayoutUnit left_over_space) const {
-  return algorithm_->FindFrUnitSize(tracks_span, left_over_space);
-}
-
-void GridTrackSizingAlgorithmStrategy::DistributeSpaceToTracks(
-    Vector<GridTrack*>& tracks,
-    LayoutUnit& available_logical_space) const {
-  algorithm_->DistributeSpaceToTracks<kMaximizeTracks>(tracks, nullptr,
-                                                       available_logical_space);
-}
-
-LayoutUnit GridTrackSizingAlgorithmStrategy::MinLogicalSizeForChild(
-    LayoutBox& child,
-    const Length& child_min_size,
-    LayoutUnit available_size) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  bool is_row_axis = Direction() == child_inline_direction;
-
-  if (is_row_axis) {
-    return child.ComputeLogicalWidthUsing(kMinSize, child_min_size,
-                                          available_size, GetLayoutGrid()) +
-           GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(), child);
-  }
-
-  bool override_size_has_changed =
-      UpdateOverrideContainingBlockContentSizeForChild(
-          child, child_inline_direction, available_size);
-  LayoutGridItemForMinSizeComputation(child, override_size_has_changed);
-
-  return child.ComputeLogicalHeightUsing(kMinSize, child_min_size,
-                                         child.IntrinsicLogicalHeight()) +
-         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child);
-}
-
-LayoutUnit DefiniteSizeStrategy::MinLogicalSizeForChild(
-    LayoutBox& child,
-    const Length& child_min_size,
-    LayoutUnit available_size) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  LayoutUnit indefinite_size =
-      Direction() == child_inline_direction ? LayoutUnit() : LayoutUnit(-1);
-  if (HasRelativeMarginOrPaddingForChild(*GetLayoutGrid(), child,
-                                         Direction()) ||
-      (Direction() != child_inline_direction &&
-       HasRelativeOrIntrinsicSizeForChild(*GetLayoutGrid(), child,
-                                          Direction()))) {
-    SetOverrideContainingBlockContentSizeForChild(child, Direction(),
-                                                  indefinite_size);
-  }
-  return GridTrackSizingAlgorithmStrategy::MinLogicalSizeForChild(
-      child, child_min_size, available_size);
-}
-
-void DefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
-    LayoutBox& child,
-    bool override_size_has_changed) const {
-  if (override_size_has_changed) {
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-    child.LayoutIfNeeded();
-  }
-}
-
-void DefiniteSizeStrategy::MaximizeTracks(
-    Vector<GridTrack>& tracks,
-    absl::optional<LayoutUnit>& free_space) {
-  wtf_size_t tracks_size = tracks.size();
-  Vector<GridTrack*> tracks_for_distribution(tracks_size);
-  for (wtf_size_t i = 0; i < tracks_size; ++i) {
-    tracks_for_distribution[i] = tracks.data() + i;
-    tracks_for_distribution[i]->SetPlannedSize(
-        tracks_for_distribution[i]->BaseSize());
-  }
-
-  DCHECK(free_space);
-  DistributeSpaceToTracks(tracks_for_distribution, free_space.value());
-
-  for (auto* track : tracks_for_distribution)
-    track->SetBaseSize(track->PlannedSize());
-}
-
-double DefiniteSizeStrategy::FindUsedFlexFraction(
-    Vector<wtf_size_t>& flexible_sized_tracks_index,
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit> free_space) const {
-  GridSpan all_tracks_span = GridSpan::TranslatedDefiniteGridSpan(
-      0, algorithm_->Tracks(direction).size());
-  DCHECK(free_space);
-  return FindFrUnitSize(all_tracks_span, free_space.value());
-}
-
-LayoutUnit DefiniteSizeStrategy::FreeSpaceForStretchAutoTracksStep() const {
-  DCHECK(algorithm_->FreeSpace(Direction()));
-  return algorithm_->FreeSpace(Direction()).value();
-}
-
-DISABLE_CFI_PERF
-LayoutUnit DefiniteSizeStrategy::MinContentForChild(LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  if (Direction() == child_inline_direction && child.NeedsLayout() &&
-      ShouldClearOverrideContainingBlockContentSizeForChild(
-          *GetLayoutGrid(), child, child_inline_direction)) {
-    SetOverrideContainingBlockContentSizeForChild(child, child_inline_direction,
-                                                  LayoutUnit());
-  }
-
-  return GridTrackSizingAlgorithmStrategy::MinContentForChild(child);
-}
-
-void IndefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
-    LayoutBox& child,
-    bool override_size_has_changed) const {
-  if (override_size_has_changed && Direction() != kForColumns) {
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-    child.LayoutIfNeeded();
-  }
-}
-
-void IndefiniteSizeStrategy::MaximizeTracks(Vector<GridTrack>& tracks,
-                                            absl::optional<LayoutUnit>&) {
-  for (auto& track : tracks)
-    track.SetBaseSize(track.GrowthLimit());
-}
-
-static inline double NormalizedFlexFraction(const GridTrack& track) {
-  double flex_factor = track.CachedTrackSize().MaxTrackBreadth().Flex();
-  return track.BaseSize() / std::max<double>(1, flex_factor);
-}
-
-double IndefiniteSizeStrategy::FindUsedFlexFraction(
-    Vector<wtf_size_t>& flexible_sized_tracks_index,
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit>) const {
-  auto all_tracks = algorithm_->Tracks(direction);
-
-  double flex_fraction = 0;
-  for (const auto& track_index : flexible_sized_tracks_index) {
-    flex_fraction = std::max(flex_fraction,
-                             NormalizedFlexFraction(all_tracks[track_index]));
-  }
-
-  const Grid& grid = algorithm_->GetGrid();
-  if (!grid.HasGridItems())
-    return flex_fraction;
-
-  IterateGridItemsInTrackIndices(
-      grid, direction, flexible_sized_tracks_index,
-      [&](LayoutBox* grid_item, const GridSpan& span) {
-        // Removing gutters from the max-content contribution of the item,
-        // so they are not taken into account in FindFrUnitSize().
-        LayoutUnit left_over_space =
-            MaxContentForChild(*grid_item) -
-            GetLayoutGrid()->GuttersSize(algorithm_->GetGrid(), direction,
-                                         span.StartLine(), span.IntegerSpan(),
-                                         AvailableSpace());
-        flex_fraction =
-            std::max(flex_fraction, FindFrUnitSize(span, left_over_space));
-      });
-
-  return flex_fraction;
-}
-
-bool IndefiniteSizeStrategy::RecomputeUsedFlexFractionIfNeeded(
-    double& flex_fraction,
-    Vector<LayoutUnit>& increments,
-    LayoutUnit& total_growth) const {
-  if (Direction() == kForColumns)
-    return false;
-
-  const LayoutGrid* layout_grid = GetLayoutGrid();
-  LayoutUnit min_size = layout_grid->ComputeContentLogicalHeight(
-      kMinSize, layout_grid->StyleRef().LogicalMinHeight(), LayoutUnit(-1));
-  LayoutUnit max_size = layout_grid->ComputeContentLogicalHeight(
-      kMaxSize, layout_grid->StyleRef().LogicalMaxHeight(), LayoutUnit(-1));
-
-  // Redo the flex fraction computation using min|max-height as definite
-  // available space in case the total height is smaller than min-height or
-  // larger than max-height.
-  LayoutUnit rows_size = total_growth + ComputeTrackBasedSize();
-  bool check_min_size = min_size && rows_size < min_size;
-  bool check_max_size = max_size != -1 && rows_size > max_size;
-  if (!check_min_size && !check_max_size)
-    return false;
-
-  LayoutUnit free_space = check_max_size ? max_size : LayoutUnit(-1);
-  const Grid& grid = algorithm_->GetGrid();
-  free_space =
-      std::max(free_space, min_size) -
-      layout_grid->GuttersSize(grid, kForRows, 0, grid.NumTracks(kForRows),
-                               AvailableSpace());
-
-  wtf_size_t number_of_tracks = algorithm_->Tracks(Direction()).size();
-  flex_fraction = FindFrUnitSize(
-      GridSpan::TranslatedDefiniteGridSpan(0, number_of_tracks), free_space);
-  return true;
-}
-
-LayoutUnit IndefiniteSizeStrategy::FreeSpaceForStretchAutoTracksStep() const {
-  DCHECK(!algorithm_->FreeSpace(Direction()));
-  if (Direction() == kForColumns)
-    return LayoutUnit();
-
-  LayoutUnit min_size = GetLayoutGrid()->ComputeContentLogicalHeight(
-      kMinSize, GetLayoutGrid()->StyleRef().LogicalMinHeight(), LayoutUnit(-1));
-  return min_size - ComputeTrackBasedSize();
-}
-
-DISABLE_CFI_PERF
-LayoutUnit IndefiniteSizeStrategy::MinContentForChild(LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  if (Direction() == child_inline_direction || Direction() == kForRows)
-    return GridTrackSizingAlgorithmStrategy::MinContentForChild(child);
-
-  // This code is executed only when computing the grid's intrinsic
-  // width based on an orthogonal child. We rely on the pre-layout
-  // performed in LayoutGrid::LayoutOrthogonalWritingModeRoots.
-  DCHECK(GridLayoutUtils::IsOrthogonalChild(*GetLayoutGrid(), child));
-
-  return child.LogicalHeight() +
-         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child) +
-         algorithm_->BaselineOffsetForChild(child,
-                                            GridAxisForDirection(Direction()));
-}
-
-DISABLE_CFI_PERF
-LayoutUnit IndefiniteSizeStrategy::MaxContentForChild(LayoutBox& child) const {
-  GridTrackSizingDirection child_inline_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
-                                                  kForColumns);
-  if (Direction() == child_inline_direction || Direction() == kForRows)
-    return GridTrackSizingAlgorithmStrategy::MaxContentForChild(child);
-
-  // This code is executed only when computing the grid's intrinsic
-  // width based on an orthogonal child. We rely on the pre-layout
-  // performed in LayoutGrid::LayoutOrthogonalWritingModeRoots.
-  DCHECK(GridLayoutUtils::IsOrthogonalChild(*GetLayoutGrid(), child));
-
-  return child.LogicalHeight() +
-         GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child) +
-         algorithm_->BaselineOffsetForChild(child,
-                                            GridAxisForDirection(Direction()));
-}
-
-bool IndefiniteSizeStrategy::IsComputingSizeContainment() const {
-  return GetLayoutGrid()->ShouldApplySizeContainment();
-}
-
-absl::optional<LayoutUnit> GridTrackSizingAlgorithm::FreeSpace(
-    GridTrackSizingDirection direction) const {
-  return direction == kForRows ? free_space_rows_ : free_space_columns_;
-}
-
-absl::optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace(
-    GridTrackSizingDirection direction) const {
-  return direction == kForRows ? available_space_rows_
-                               : available_space_columns_;
-}
-
-absl::optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace() const {
-  DCHECK(WasSetup());
-  return AvailableSpace(direction_);
-}
-
-void GridTrackSizingAlgorithm::SetAvailableSpace(
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit> available_space) {
-  if (direction == kForColumns)
-    available_space_columns_ = available_space;
-  else
-    available_space_rows_ = available_space;
-}
-
-Vector<GridTrack>& GridTrackSizingAlgorithm::Tracks(
-    GridTrackSizingDirection direction) {
-  return direction == kForColumns ? columns_ : rows_;
-}
-
-const Vector<GridTrack>& GridTrackSizingAlgorithm::Tracks(
-    GridTrackSizingDirection direction) const {
-  return direction == kForColumns ? columns_ : rows_;
-}
-
-void GridTrackSizingAlgorithm::SetFreeSpace(
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit> free_space) {
-  if (direction == kForColumns)
-    free_space_columns_ = free_space;
-  else
-    free_space_rows_ = free_space;
-}
-
-const GridTrackSize& GridTrackSizingAlgorithm::RawGridTrackSize(
-    GridTrackSizingDirection direction,
-    wtf_size_t translated_index) const {
-  bool is_row_axis = direction == kForColumns;
-  const ComputedStyle& grid_container_style = layout_grid_->StyleRef();
-  const ComputedGridTrackList& computed_grid_track_list =
-      is_row_axis ? grid_container_style.GridTemplateColumns()
-                  : grid_container_style.GridTemplateRows();
-  const Vector<GridTrackSize, 1>& track_list_sizes =
-      computed_grid_track_list.track_sizes.LegacyTrackList();
-  const Vector<GridTrackSize, 1>& auto_repeat_track_sizes =
-      computed_grid_track_list.auto_repeat_track_sizes;
-  const Vector<GridTrackSize, 1>& auto_track_styles =
-      is_row_axis ? grid_container_style.GridAutoColumns().LegacyTrackList()
-                  : grid_container_style.GridAutoRows().LegacyTrackList();
-  wtf_size_t insertion_point =
-      computed_grid_track_list.auto_repeat_insertion_point;
-  wtf_size_t auto_repeat_tracks_count = grid_->AutoRepeatTracks(direction);
-
-  // We should not use GridPositionsResolver::explicitGridXXXCount() for this
-  // because the explicit grid might be larger than the number of tracks in
-  // grid-template-rows|columns (if grid-template-areas is specified for
-  // example).
-  wtf_size_t explicit_tracks_count =
-      track_list_sizes.size() + auto_repeat_tracks_count;
-
-  int untranslated_index_as_int =
-      static_cast<int>(translated_index - grid_->ExplicitGridStart(direction));
-  wtf_size_t auto_track_styles_size = auto_track_styles.size();
-  if (untranslated_index_as_int < 0) {
-    int index =
-        untranslated_index_as_int % static_cast<int>(auto_track_styles_size);
-    // We need to traspose the index because the first negative implicit line
-    // will get the last defined auto track and so on.
-    index += index ? auto_track_styles_size : 0;
-    return auto_track_styles[index];
-  }
-
-  wtf_size_t untranslated_index =
-      static_cast<wtf_size_t>(untranslated_index_as_int);
-  if (untranslated_index >= explicit_tracks_count) {
-    return auto_track_styles[(untranslated_index - explicit_tracks_count) %
-                             auto_track_styles_size];
-  }
-
-  if (LIKELY(!auto_repeat_tracks_count) || untranslated_index < insertion_point)
-    return track_list_sizes[untranslated_index];
-
-  if (untranslated_index < (insertion_point + auto_repeat_tracks_count)) {
-    wtf_size_t auto_repeat_local_index = untranslated_index - insertion_point;
-    return auto_repeat_track_sizes[auto_repeat_local_index %
-                                   auto_repeat_track_sizes.size()];
-  }
-
-  return track_list_sizes[untranslated_index - auto_repeat_tracks_count];
-}
-
-bool GridTrackSizingAlgorithm::IsRelativeGridLengthAsAuto(
-    const GridLength& length,
-    GridTrackSizingDirection direction) const {
-  return length.HasPercentage() && !AvailableSpace(direction);
-}
-
-bool GridTrackSizingAlgorithm::IsRelativeSizedTrackAsAuto(
-    const GridTrackSize& track_size,
-    GridTrackSizingDirection direction) const {
-  if (track_size.MinTrackBreadth().HasPercentage())
-    return IsRelativeGridLengthAsAuto(track_size.MinTrackBreadth(), direction);
-  if (track_size.MaxTrackBreadth().HasPercentage())
-    return IsRelativeGridLengthAsAuto(track_size.MaxTrackBreadth(), direction);
-  return false;
-}
-
-GridTrackSize GridTrackSizingAlgorithm::CalculateGridTrackSize(
-    GridTrackSizingDirection direction,
-    wtf_size_t translated_index) const {
-  DCHECK(WasSetup());
-  // Collapse empty auto repeat tracks if auto-fit.
-  if (grid_->HasAutoRepeatEmptyTracks(direction) &&
-      grid_->IsEmptyAutoRepeatTrack(direction, translated_index))
-    return {Length::Fixed(), kLengthTrackSizing};
-
-  const GridTrackSize& track_size =
-      RawGridTrackSize(direction, translated_index);
-  if (track_size.IsFitContent()) {
-    return IsRelativeGridLengthAsAuto(track_size.FitContentTrackBreadth(),
-                                      direction)
-               ? GridTrackSize(Length::Auto(), Length::MaxContent())
-               : track_size;
-  }
-
-  GridLength min_track_breadth = track_size.MinTrackBreadth();
-  GridLength max_track_breadth = track_size.MaxTrackBreadth();
-
-  // If the logical width/height of the grid container is indefinite, percentage
-  // values are treated as <auto>.
-  if (IsRelativeSizedTrackAsAuto(track_size, direction)) {
-    if (direction == kForRows) {
-      // We avoid counting the cases in which it doesn't matter if we resolve
-      // the percentages row tracks against the intrinsic height of the grid
-      // container or we treat them as auto. Basically if we have just one row,
-      // it has 100% size and the max-block-size is none.
-      if ((grid_->NumTracks(direction) != 1) || !min_track_breadth.IsLength() ||
-          !min_track_breadth.length().IsPercent() ||
-          (min_track_breadth.length().Percent() != 100.0f) ||
-          !max_track_breadth.IsLength() ||
-          !max_track_breadth.length().IsPercent() ||
-          (max_track_breadth.length().Percent() != 100.0f) ||
-          !layout_grid_->StyleRef().LogicalMaxHeight().IsNone()) {
-        UseCounter::Count(layout_grid_->GetDocument(),
-                          WebFeature::kGridRowTrackPercentIndefiniteHeight);
-      }
-    }
-    if (min_track_breadth.HasPercentage())
-      min_track_breadth = Length::Auto();
-    if (max_track_breadth.HasPercentage())
-      max_track_breadth = Length::Auto();
-  }
-
-  // Flex sizes are invalid as a min sizing function. However we still can have
-  // a flexible |minTrackBreadth| if the track had a flex size directly (e.g.
-  // "1fr"), the spec says that in this case it implies an automatic minimum.
-  // TODO(jfernandez): https://github.com/w3c/csswg-drafts/issues/2611
-  // TODO(jfernandez): We may have to change IsIntrinsicSizedGridArea too.
-  if (min_track_breadth.IsFlex())
-    min_track_breadth = Length::Auto();
-
-  return GridTrackSize(min_track_breadth, max_track_breadth);
-}
-
-LayoutUnit GridTrackSizingAlgorithm::InitialBaseSize(
-    const GridTrackSize& track_size) const {
-  const GridLength& grid_length = track_size.MinTrackBreadth();
-
-  // TODO(obrufau): https://github.com/w3c/csswg-drafts/issues/2611 may allow
-  // flexible lengths to be used as min track sizing functions.
-  DCHECK(!grid_length.IsFlex());
-
-  const Length& track_length = grid_length.length();
-  if (track_length.IsSpecified()) {
-    DCHECK(!grid_length.HasPercentage() || AvailableSpace());
-    return ValueForLength(track_length,
-                          AvailableSpace().value_or(LayoutUnit()));
-  }
-
-  DCHECK(track_length.IsMinContent() || track_length.IsAuto() ||
-         track_length.IsMaxContent());
-  return LayoutUnit();
-}
-
-LayoutUnit GridTrackSizingAlgorithm::InitialGrowthLimit(
-    const GridTrackSize& track_size,
-    LayoutUnit base_size) const {
-  const GridLength& grid_length = track_size.MaxTrackBreadth();
-  if (grid_length.IsFlex())
-    return base_size;
-
-  const Length& track_length = grid_length.length();
-  if (track_length.IsSpecified()) {
-    DCHECK(!grid_length.HasPercentage() || AvailableSpace());
-    return ValueForLength(track_length,
-                          AvailableSpace().value_or(LayoutUnit()));
-  }
-
-  DCHECK(track_length.IsMinContent() || track_length.IsAuto() ||
-         track_length.IsMaxContent());
-  return LayoutUnit(kInfinity);
-}
-
-void GridTrackSizingAlgorithm::InitializeTrackSizes() {
-  DCHECK(content_sized_tracks_index_.empty());
-  DCHECK(flexible_sized_tracks_index_.empty());
-  DCHECK(auto_sized_tracks_for_stretch_index_.empty());
-  DCHECK(!has_percent_sized_rows_indefinite_height_);
-  Vector<GridTrack>& track_list = Tracks(direction_);
-  bool indefinite_height =
-      direction_ == kForRows && !layout_grid_->CachedHasDefiniteLogicalHeight();
-  wtf_size_t num_tracks = track_list.size();
-  for (wtf_size_t i = 0; i < num_tracks; ++i) {
-    const GridTrackSize& track_size = CalculateGridTrackSize(direction_, i);
-    GridTrack& track = track_list[i];
-    track.SetCachedTrackSize(track_size);
-    track.SetBaseSize(InitialBaseSize(track_size));
-    track.SetGrowthLimit(InitialGrowthLimit(track_size, track.BaseSize()));
-    track.SetInfinitelyGrowable(false);
-
-    if (track_size.IsFitContent()) {
-      track.SetGrowthLimitCap(
-          ValueForLength(track_size.FitContentTrackBreadth().length(),
-                         AvailableSpace().value_or(LayoutUnit())));
-    }
-
-    if (track_size.IsContentSized())
-      content_sized_tracks_index_.push_back(i);
-    if (track_size.MaxTrackBreadth().IsFlex())
-      flexible_sized_tracks_index_.push_back(i);
-    if (track_size.HasAutoMaxTrackBreadth() && !track_size.IsFitContent())
-      auto_sized_tracks_for_stretch_index_.push_back(i);
-
-    if (!has_percent_sized_rows_indefinite_height_ && indefinite_height) {
-      const GridTrackSize& raw_track_size = RawGridTrackSize(direction_, i);
-      if (raw_track_size.MinTrackBreadth().HasPercentage() ||
-          raw_track_size.MaxTrackBreadth().HasPercentage())
-        has_percent_sized_rows_indefinite_height_ = true;
-    }
-  }
-}
-
-void GridTrackSizingAlgorithm::SizeTrackToFitNonSpanningItem(
-    const GridSpan& span,
-    LayoutBox& grid_item,
-    GridTrack& track) {
-  const wtf_size_t track_position = span.StartLine();
-  const GridTrackSize& track_size =
-      Tracks(direction_)[track_position].CachedTrackSize();
-
-  if (track_size.HasMinContentMinTrackBreadth()) {
-    track.SetBaseSize(
-        std::max(track.BaseSize(), strategy_->MinContentForChild(grid_item)));
-  } else if (track_size.HasMaxContentMinTrackBreadth()) {
-    track.SetBaseSize(
-        std::max(track.BaseSize(), strategy_->MaxContentForChild(grid_item)));
-  } else if (track_size.HasAutoMinTrackBreadth()) {
-    track.SetBaseSize(
-        std::max(track.BaseSize(), strategy_->MinSizeForChild(grid_item)));
-  }
-
-  if (track_size.HasMinContentMaxTrackBreadth()) {
-    track.SetGrowthLimit(std::max(track.GrowthLimit(),
-                                  strategy_->MinContentForChild(grid_item)));
-  } else if (track_size.HasMaxContentOrAutoMaxTrackBreadth()) {
-    LayoutUnit growth_limit = strategy_->MaxContentForChild(grid_item);
-    if (track_size.IsFitContent()) {
-      growth_limit =
-          std::min(growth_limit,
-                   ValueForLength(track_size.FitContentTrackBreadth().length(),
-                                  AvailableSpace().value_or(LayoutUnit())));
-    }
-    track.SetGrowthLimit(std::max(track.GrowthLimit(), growth_limit));
-  }
-}
-
-bool GridTrackSizingAlgorithm::SpanningItemCrossesFlexibleSizedTracks(
-    const GridSpan& span) const {
-  const Vector<GridTrack>& track_list = Tracks(direction_);
-  for (auto track_position : span) {
-    const GridTrackSize& track_size =
-        track_list[track_position].CachedTrackSize();
-    if (track_size.MinTrackBreadth().IsFlex() ||
-        track_size.MaxTrackBreadth().IsFlex())
-      return true;
-  }
-
-  return false;
-}
-
-// We're basically using a class instead of a std::pair because of accessing
-// gridItem() or getGridSpan() is much more self-explanatory that using .first
-// or .second members in the pair. Having a std::pair<LayoutBox*, size_t>
-// does not work either because we still need the GridSpan so we'd have to add
-// an extra hash lookup for each item.
-class GridItemWithSpan {
-  DISALLOW_NEW();
-
- public:
-  GridItemWithSpan(LayoutBox& grid_item, const GridSpan& grid_span)
-      : grid_item_(&grid_item), grid_span_(grid_span) {}
-
-  LayoutBox& GridItem() const { return *grid_item_; }
-  GridSpan GetGridSpan() const { return grid_span_; }
-
-  bool operator<(const GridItemWithSpan other) const {
-    return grid_span_.IntegerSpan() < other.grid_span_.IntegerSpan();
-  }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(grid_item_); }
-
- private:
-  Member<LayoutBox> grid_item_;
-  GridSpan grid_span_;
-};
-
-enum TrackSizeRestriction {
-  kAllowInfinity,
-  kForbidInfinity,
-};
-
-static LayoutUnit TrackSizeForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    const GridTrack& track,
-    TrackSizeRestriction restriction) {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-    case kResolveContentBasedMinimums:
-    case kResolveMaxContentMinimums:
-    case kMaximizeTracks:
-      return track.BaseSize();
-    case kResolveIntrinsicMaximums:
-    case kResolveMaxContentMaximums:
-      const LayoutUnit& growth_limit = track.GrowthLimit();
-      if (restriction == kAllowInfinity)
-        return growth_limit;
-      return growth_limit == kInfinity ? track.BaseSize() : growth_limit;
-  }
-
-  NOTREACHED();
-  return track.BaseSize();
-}
-
-static bool ShouldProcessTrackForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    const GridTrackSize& track_size) {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-      return track_size.HasIntrinsicMinTrackBreadth();
-    case kResolveContentBasedMinimums:
-      return track_size.HasMinOrMaxContentMinTrackBreadth();
-    case kResolveMaxContentMinimums:
-      return track_size.HasMaxContentMinTrackBreadth();
-    case kResolveIntrinsicMaximums:
-      return track_size.HasIntrinsicMaxTrackBreadth();
-    case kResolveMaxContentMaximums:
-      return track_size.HasMaxContentOrAutoMaxTrackBreadth();
-    case kMaximizeTracks:
-      NOTREACHED();
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-static bool TrackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    const GridTrackSize& track_size) {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-    case kResolveContentBasedMinimums:
-      return track_size
-          .HasAutoOrMinContentMinTrackBreadthAndIntrinsicMaxTrackBreadth();
-    case kResolveMaxContentMinimums:
-      return track_size
-          .HasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth();
-    case kResolveIntrinsicMaximums:
-    case kResolveMaxContentMaximums:
-      return true;
-    case kMaximizeTracks:
-      NOTREACHED();
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-static void MarkAsInfinitelyGrowableForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    GridTrack& track) {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-    case kResolveContentBasedMinimums:
-    case kResolveMaxContentMinimums:
-      return;
-    case kResolveIntrinsicMaximums:
-      if (TrackSizeForTrackSizeComputationPhase(phase, track, kAllowInfinity) ==
-              kInfinity &&
-          track.PlannedSize() != kInfinity)
-        track.SetInfinitelyGrowable(true);
-      return;
-    case kResolveMaxContentMaximums:
-      if (track.InfinitelyGrowable())
-        track.SetInfinitelyGrowable(false);
-      return;
-    case kMaximizeTracks:
-      NOTREACHED();
-      return;
-  }
-
-  NOTREACHED();
-}
-
-static void UpdateTrackSizeForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    GridTrack& track) {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-    case kResolveContentBasedMinimums:
-    case kResolveMaxContentMinimums:
-      track.SetBaseSize(track.PlannedSize());
-      return;
-    case kResolveIntrinsicMaximums:
-    case kResolveMaxContentMaximums:
-      track.SetGrowthLimit(track.PlannedSize());
-      return;
-    case kMaximizeTracks:
-      NOTREACHED();
-      return;
-  }
-
-  NOTREACHED();
-}
-
-LayoutUnit GridTrackSizingAlgorithm::ItemSizeForTrackSizeComputationPhase(
-    TrackSizeComputationPhase phase,
-    LayoutBox& grid_item) const {
-  switch (phase) {
-    case kResolveIntrinsicMinimums:
-      return strategy_->MinSizeForChild(grid_item);
-    case kResolveContentBasedMinimums:
-    case kResolveIntrinsicMaximums:
-      return strategy_->MinContentForChild(grid_item);
-    case kResolveMaxContentMinimums:
-    case kResolveMaxContentMaximums:
-      return strategy_->MaxContentForChild(grid_item);
-    case kMaximizeTracks:
-      NOTREACHED();
-      return LayoutUnit();
-  }
-
-  NOTREACHED();
-  return LayoutUnit();
-}
-
-static bool SortByGridTrackGrowthPotential(const GridTrack* track1,
-                                           const GridTrack* track2) {
-  // This check ensures that we respect the irreflexivity property of the strict
-  // weak ordering required by std::sort(forall x: NOT x < x).
-  bool track1_has_infinite_growth_potential_without_cap =
-      track1->InfiniteGrowthPotential() && !track1->GrowthLimitCap();
-  bool track2_has_infinite_growth_potential_without_cap =
-      track2->InfiniteGrowthPotential() && !track2->GrowthLimitCap();
-
-  if (track1_has_infinite_growth_potential_without_cap &&
-      track2_has_infinite_growth_potential_without_cap)
-    return false;
-
-  if (track1_has_infinite_growth_potential_without_cap ||
-      track2_has_infinite_growth_potential_without_cap)
-    return track2_has_infinite_growth_potential_without_cap;
-
-  LayoutUnit track1_limit =
-      track1->GrowthLimitCap().value_or(track1->GrowthLimit());
-  LayoutUnit track2_limit =
-      track2->GrowthLimitCap().value_or(track2->GrowthLimit());
-  return (track1_limit - track1->BaseSize()) <
-         (track2_limit - track2->BaseSize());
-}
-
-static void ClampGrowthShareIfNeeded(TrackSizeComputationPhase phase,
-                                     const GridTrack& track,
-                                     LayoutUnit& growth_share) {
-  if (phase != kResolveMaxContentMaximums || !track.GrowthLimitCap())
-    return;
-
-  LayoutUnit distance_to_cap =
-      track.GrowthLimitCap().value() - track.SizeDuringDistribution();
-  if (distance_to_cap <= 0)
-    return;
-
-  growth_share = std::min(growth_share, distance_to_cap);
-}
-
-template <TrackSizeComputationPhase phase>
-void GridTrackSizingAlgorithm::DistributeSpaceToTracks(
-    Vector<GridTrack*>& tracks,
-    Vector<GridTrack*>* grow_beyond_growth_limits_tracks,
-    LayoutUnit& available_logical_space) const {
-  DCHECK_GE(available_logical_space, 0);
-
-  for (auto* track : tracks) {
-    track->SetSizeDuringDistribution(
-        TrackSizeForTrackSizeComputationPhase(phase, *track, kForbidInfinity));
-  }
-
-  if (available_logical_space > 0) {
-    std::sort(tracks.begin(), tracks.end(), SortByGridTrackGrowthPotential);
-
-    wtf_size_t tracks_size = tracks.size();
-    for (wtf_size_t i = 0; i < tracks_size; ++i) {
-      GridTrack& track = *tracks[i];
-      LayoutUnit available_logical_space_share =
-          available_logical_space / (tracks_size - i);
-      const LayoutUnit& track_breadth =
-          TrackSizeForTrackSizeComputationPhase(phase, track, kForbidInfinity);
-      LayoutUnit growth_share =
-          track.InfiniteGrowthPotential()
-              ? available_logical_space_share
-              : std::min(available_logical_space_share,
-                         track.GrowthLimit() - track_breadth);
-      ClampGrowthShareIfNeeded(phase, track, growth_share);
-      DCHECK_GE(growth_share, 0) << "We must never shrink any grid track or "
-                                    "else we can't guarantee we abide by our "
-                                    "min-sizing function.";
-      track.GrowSizeDuringDistribution(growth_share);
-      available_logical_space -= growth_share;
-    }
-  }
-
-  if (available_logical_space > 0 && grow_beyond_growth_limits_tracks) {
-    // We need to sort them because there might be tracks with growth limit caps
-    // (like the ones with fit-content()) which cannot indefinitely grow over
-    // the limits.
-    if (phase == kResolveMaxContentMaximums) {
-      std::sort(grow_beyond_growth_limits_tracks->begin(),
-                grow_beyond_growth_limits_tracks->end(),
-                SortByGridTrackGrowthPotential);
-    }
-
-    wtf_size_t tracks_growing_above_max_breadth_size =
-        grow_beyond_growth_limits_tracks->size();
-    for (wtf_size_t i = 0; i < tracks_growing_above_max_breadth_size; ++i) {
-      GridTrack* track = grow_beyond_growth_limits_tracks->at(i);
-      LayoutUnit growth_share =
-          available_logical_space / (tracks_growing_above_max_breadth_size - i);
-      ClampGrowthShareIfNeeded(phase, *track, growth_share);
-      DCHECK_GE(growth_share, 0) << "We must never shrink any grid track or "
-                                    "else we can't guarantee we abide by our "
-                                    "min-sizing function.";
-      track->GrowSizeDuringDistribution(growth_share);
-      available_logical_space -= growth_share;
-    }
-  }
-
-  for (auto* track : tracks) {
-    track->SetPlannedSize(
-        track->PlannedSize() == kInfinity
-            ? track->SizeDuringDistribution()
-            : std::max(track->PlannedSize(), track->SizeDuringDistribution()));
-  }
-}
-
-template <TrackSizeComputationPhase phase>
-void GridTrackSizingAlgorithm::IncreaseSizesToAccommodateSpanningItems(
-    const HeapVector<GridItemWithSpan>::iterator& grid_items_with_span_begin,
-    const HeapVector<GridItemWithSpan>::iterator& grid_items_with_span_end) {
-  Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (const auto& track_index : content_sized_tracks_index_) {
-    GridTrack& track = all_tracks[track_index];
-    track.SetPlannedSize(
-        TrackSizeForTrackSizeComputationPhase(phase, track, kAllowInfinity));
-  }
-
-  Vector<GridTrack*> grow_beyond_growth_limits_tracks;
-  Vector<GridTrack*> filtered_tracks;
-  for (auto* it = grid_items_with_span_begin; it != grid_items_with_span_end;
-       ++it) {
-    const GridItemWithSpan& grid_item_with_span = *it;
-    DCHECK_GT(grid_item_with_span.GetGridSpan().IntegerSpan(), 1u);
-    const GridSpan& item_span = grid_item_with_span.GetGridSpan();
-
-    grow_beyond_growth_limits_tracks.Shrink(0);
-    filtered_tracks.Shrink(0);
-    LayoutUnit spanning_tracks_size;
-    for (auto track_position : item_span) {
-      GridTrack& track = all_tracks[track_position];
-      const GridTrackSize& track_size = track.CachedTrackSize();
-      spanning_tracks_size +=
-          TrackSizeForTrackSizeComputationPhase(phase, track, kForbidInfinity);
-      if (!ShouldProcessTrackForTrackSizeComputationPhase(phase, track_size))
-        continue;
-
-      filtered_tracks.push_back(&track);
-
-      if (TrackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(
-              phase, track_size))
-        grow_beyond_growth_limits_tracks.push_back(&track);
-    }
-
-    if (filtered_tracks.empty())
-      continue;
-
-    spanning_tracks_size +=
-        layout_grid_->GuttersSize(*grid_, direction_, item_span.StartLine(),
-                                  item_span.IntegerSpan(), AvailableSpace());
-
-    LayoutUnit extra_space = ItemSizeForTrackSizeComputationPhase(
-                                 phase, grid_item_with_span.GridItem()) -
-                             spanning_tracks_size;
-    extra_space = extra_space.ClampNegativeToZero();
-    auto& tracks_to_grow_beyond_growth_limits =
-        grow_beyond_growth_limits_tracks.empty()
-            ? filtered_tracks
-            : grow_beyond_growth_limits_tracks;
-    DistributeSpaceToTracks<phase>(
-        filtered_tracks, &tracks_to_grow_beyond_growth_limits, extra_space);
-  }
-
-  for (const auto& track_index : content_sized_tracks_index_) {
-    GridTrack& track = all_tracks[track_index];
-    MarkAsInfinitelyGrowableForTrackSizeComputationPhase(phase, track);
-    UpdateTrackSizeForTrackSizeComputationPhase(phase, track);
-  }
-}
-
-void GridTrackSizingAlgorithm::ResolveIntrinsicTrackSizes() {
-  Vector<GridTrack>& all_tracks = Tracks(direction_);
-  HeapVector<GridItemWithSpan> items_sorted_by_increasing_span;
-  if (grid_->HasGridItems()) {
-    IterateGridItemsInTrackIndices(
-        *grid_, direction_, content_sized_tracks_index_,
-        [&](LayoutBox* grid_item, const GridSpan& span) {
-          if (span.IntegerSpan() == 1) {
-            SizeTrackToFitNonSpanningItem(span, *grid_item,
-                                          all_tracks[span.StartLine()]);
-          } else if (!SpanningItemCrossesFlexibleSizedTracks(span)) {
-            items_sorted_by_increasing_span.push_back(
-                GridItemWithSpan(*grid_item, span));
-          }
-        });
-    std::sort(items_sorted_by_increasing_span.begin(),
-              items_sorted_by_increasing_span.end());
-  }
-
-  auto* it = items_sorted_by_increasing_span.begin();
-  auto* end = items_sorted_by_increasing_span.end();
-  while (it != end) {
-    auto* range_end = std::upper_bound(it, end, *it);
-    IncreaseSizesToAccommodateSpanningItems<kResolveIntrinsicMinimums>(
-        it, range_end);
-    IncreaseSizesToAccommodateSpanningItems<kResolveContentBasedMinimums>(
-        it, range_end);
-    IncreaseSizesToAccommodateSpanningItems<kResolveMaxContentMinimums>(
-        it, range_end);
-    IncreaseSizesToAccommodateSpanningItems<kResolveIntrinsicMaximums>(
-        it, range_end);
-    IncreaseSizesToAccommodateSpanningItems<kResolveMaxContentMaximums>(
-        it, range_end);
-    it = range_end;
-  }
-
-  for (const auto& track_index : content_sized_tracks_index_) {
-    GridTrack& track = all_tracks[track_index];
-    if (track.GrowthLimit() == kInfinity)
-      track.SetGrowthLimit(track.BaseSize());
-  }
-}
-
-void GridTrackSizingAlgorithm::ComputeGridContainerIntrinsicSizes() {
-  min_content_size_ = max_content_size_ = LayoutUnit();
-
-  Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (auto& track : all_tracks) {
-    DCHECK(strategy_->IsComputingSizeContainment() ||
-           !track.InfiniteGrowthPotential());
-    min_content_size_ += track.BaseSize();
-    max_content_size_ +=
-        track.GrowthLimitIsInfinite() ? track.BaseSize() : track.GrowthLimit();
-    // The growth limit caps must be cleared now in order to properly sort
-    // tracks by growth potential on an eventual "Maximize Tracks".
-    track.SetGrowthLimitCap(absl::nullopt);
-  }
-}
-
-LayoutUnit GridTrackSizingAlgorithm::ComputeTrackBasedSize() const {
-  LayoutUnit size;
-
-  const Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (auto& track : all_tracks) {
-    size +=
-        track.GrowthLimitIsInfinite() ? track.BaseSize() : track.GrowthLimit();
-  }
-
-  size += layout_grid_->GuttersSize(*grid_, direction_, 0, all_tracks.size(),
-                                    AvailableSpace());
-
-  return size;
-}
-
-double GridTrackSizingAlgorithm::FindFrUnitSize(
-    const GridSpan& tracks_span,
-    LayoutUnit left_over_space) const {
-  if (left_over_space <= 0)
-    return 0;
-
-  const Vector<GridTrack>& all_tracks = Tracks(direction_);
-  double flex_factor_sum = 0;
-  Vector<wtf_size_t, 8> flexible_tracks_indexes;
-  for (auto track_index : tracks_span) {
-    const GridTrackSize& track_size = all_tracks[track_index].CachedTrackSize();
-    if (!track_size.MaxTrackBreadth().IsFlex()) {
-      left_over_space -= all_tracks[track_index].BaseSize();
-    } else {
-      flexible_tracks_indexes.push_back(track_index);
-      flex_factor_sum += track_size.MaxTrackBreadth().Flex();
-    }
-  }
-  // We don't remove the gutters from left_over_space here, because that was
-  // already done before.
-
-  // The function is not called if we don't have <flex> grid tracks.
-  DCHECK(!flexible_tracks_indexes.empty());
-
-  return ComputeFlexFactorUnitSize(all_tracks, flex_factor_sum, left_over_space,
-                                   flexible_tracks_indexes);
-}
-
-double GridTrackSizingAlgorithm::ComputeFlexFactorUnitSize(
-    const Vector<GridTrack>& tracks,
-    double flex_factor_sum,
-    LayoutUnit& left_over_space,
-    const Vector<wtf_size_t, 8>& flexible_tracks_indexes,
-    std::unique_ptr<TrackIndexSet> tracks_to_treat_as_inflexible) const {
-  // We want to avoid the effect of flex factors sum below 1 making the factor
-  // unit size to grow exponentially.
-  double hypothetical_factor_unit_size =
-      left_over_space / std::max<double>(1, flex_factor_sum);
-
-  // product of the hypothetical "flex factor unit" and any flexible track's
-  // "flex factor" must be grater than such track's "base size".
-  std::unique_ptr<TrackIndexSet> additional_tracks_to_treat_as_inflexible =
-      std::move(tracks_to_treat_as_inflexible);
-  bool valid_flex_factor_unit = true;
-  for (auto index : flexible_tracks_indexes) {
-    if (additional_tracks_to_treat_as_inflexible &&
-        additional_tracks_to_treat_as_inflexible->Contains(index))
-      continue;
-    LayoutUnit base_size = tracks[index].BaseSize();
-    double flex_factor =
-        tracks[index].CachedTrackSize().MaxTrackBreadth().Flex();
-    // treating all such tracks as inflexible.
-    if (base_size > hypothetical_factor_unit_size * flex_factor) {
-      left_over_space -= base_size;
-      flex_factor_sum -= flex_factor;
-      if (!additional_tracks_to_treat_as_inflexible) {
-        additional_tracks_to_treat_as_inflexible =
-            std::make_unique<TrackIndexSet>();
-      }
-      additional_tracks_to_treat_as_inflexible->insert(index);
-      valid_flex_factor_unit = false;
-    }
-  }
-  if (!valid_flex_factor_unit) {
-    return ComputeFlexFactorUnitSize(
-        tracks, flex_factor_sum, left_over_space, flexible_tracks_indexes,
-        std::move(additional_tracks_to_treat_as_inflexible));
-  }
-  return hypothetical_factor_unit_size;
-}
-
-void GridTrackSizingAlgorithm::ComputeFlexSizedTracksGrowth(
-    double flex_fraction,
-    Vector<LayoutUnit>& increments,
-    LayoutUnit& total_growth) const {
-  wtf_size_t num_flex_tracks = flexible_sized_tracks_index_.size();
-  DCHECK_EQ(increments.size(), num_flex_tracks);
-  const Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (wtf_size_t i = 0; i < num_flex_tracks; ++i) {
-    wtf_size_t track_index = flexible_sized_tracks_index_[i];
-    const GridTrackSize& track_size = all_tracks[track_index].CachedTrackSize();
-    DCHECK(track_size.MaxTrackBreadth().IsFlex());
-    LayoutUnit old_base_size = all_tracks[track_index].BaseSize();
-    LayoutUnit new_base_size = std::max(
-        old_base_size,
-        LayoutUnit(flex_fraction * track_size.MaxTrackBreadth().Flex()));
-    increments[i] = new_base_size - old_base_size;
-    total_growth += increments[i];
-  }
-}
-
-void GridTrackSizingAlgorithm::StretchFlexibleTracks(
-    absl::optional<LayoutUnit> free_space) {
-  if (flexible_sized_tracks_index_.empty())
-    return;
-
-  double flex_fraction = strategy_->FindUsedFlexFraction(
-      flexible_sized_tracks_index_, direction_, free_space);
-
-  LayoutUnit total_growth;
-  Vector<LayoutUnit> increments;
-  increments.Grow(flexible_sized_tracks_index_.size());
-  ComputeFlexSizedTracksGrowth(flex_fraction, increments, total_growth);
-
-  if (strategy_->RecomputeUsedFlexFractionIfNeeded(flex_fraction, increments,
-                                                   total_growth)) {
-    total_growth = LayoutUnit(0);
-    ComputeFlexSizedTracksGrowth(flex_fraction, increments, total_growth);
-  }
-
-  wtf_size_t i = 0;
-  Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (auto track_index : flexible_sized_tracks_index_) {
-    auto& track = all_tracks[track_index];
-    if (LayoutUnit increment = increments[i++])
-      track.SetBaseSize(track.BaseSize() + increment);
-  }
-  if (FreeSpace(direction_)) {
-    SetFreeSpace(direction_, FreeSpace(direction_).value() - total_growth);
-  }
-  max_content_size_ += total_growth;
-}
-
-void GridTrackSizingAlgorithm::StretchAutoTracks() {
-  LayoutUnit free_space = strategy_->FreeSpaceForStretchAutoTracksStep();
-  if (auto_sized_tracks_for_stretch_index_.empty() || (free_space <= 0) ||
-      (layout_grid_->ContentAlignment(direction_).Distribution() !=
-       ContentDistributionType::kStretch))
-    return;
-
-  unsigned number_of_auto_sized_tracks =
-      auto_sized_tracks_for_stretch_index_.size();
-  LayoutUnit size_to_increase = free_space / number_of_auto_sized_tracks;
-  Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (const auto& track_index : auto_sized_tracks_for_stretch_index_) {
-    auto& track = all_tracks[track_index];
-    LayoutUnit base_size = track.BaseSize() + size_to_increase;
-    track.SetBaseSize(base_size);
-  }
-  SetFreeSpace(direction_, LayoutUnit());
-}
-
-void GridTrackSizingAlgorithm::AdvanceNextState() {
-  switch (sizing_state_) {
-    case kColumnSizingFirstIteration:
-      sizing_state_ = kRowSizingFirstIteration;
-      return;
-    case kRowSizingFirstIteration:
-      if (!strategy_->IsComputingSizeContainment())
-        sizing_state_ = kColumnSizingSecondIteration;
-      return;
-    case kColumnSizingSecondIteration:
-      sizing_state_ = kRowSizingSecondIteration;
-      return;
-    case kRowSizingSecondIteration:
-      sizing_state_ = kColumnSizingFirstIteration;
-      return;
-  }
-  NOTREACHED();
-  sizing_state_ = kColumnSizingFirstIteration;
-}
-
-bool GridTrackSizingAlgorithm::IsValidTransition() const {
-  switch (sizing_state_) {
-    case kColumnSizingFirstIteration:
-    case kColumnSizingSecondIteration:
-      return direction_ == kForColumns;
-    case kRowSizingFirstIteration:
-    case kRowSizingSecondIteration:
-      return direction_ == kForRows;
-  }
-  NOTREACHED();
-  return false;
-}
-
-void GridTrackSizingAlgorithm::Setup(
-    GridTrackSizingDirection direction,
-    wtf_size_t num_tracks,
-    absl::optional<LayoutUnit> available_space) {
-  DCHECK(needs_setup_);
-  direction_ = direction;
-  SetAvailableSpace(
-      direction, available_space ? available_space.value().ClampNegativeToZero()
-                                 : available_space);
-
-  if (available_space)
-    strategy_ = MakeGarbageCollected<DefiniteSizeStrategy>(*this);
-  else
-    strategy_ = MakeGarbageCollected<IndefiniteSizeStrategy>(*this);
-
-  content_sized_tracks_index_.Shrink(0);
-  flexible_sized_tracks_index_.Shrink(0);
-  auto_sized_tracks_for_stretch_index_.Shrink(0);
-  has_percent_sized_rows_indefinite_height_ = false;
-
-  if (available_space) {
-    LayoutUnit gutters_size = layout_grid_->GuttersSize(
-        *grid_, direction, 0, grid_->NumTracks(direction), available_space);
-    SetFreeSpace(direction, available_space.value() - gutters_size);
-  } else {
-    SetFreeSpace(direction, absl::nullopt);
-  }
-  Tracks(direction).resize(num_tracks);
-
-  ComputeBaselineAlignmentContext();
-
-  needs_setup_ = false;
-}
-
-void GridTrackSizingAlgorithm::ComputeBaselineAlignmentContext() {
-  GridAxis axis = GridAxisForDirection(direction_);
-  baseline_alignment_.Clear(axis);
-  baseline_alignment_.SetBlockFlow(layout_grid_->StyleRef().GetWritingMode());
-  BaselineItemsCache& baseline_items_cache = axis == kGridColumnAxis
-                                                 ? column_baseline_items_map_
-                                                 : row_baseline_items_map_;
-  for (auto& child : baseline_items_cache.Keys()) {
-    // TODO (jfernandez): We may have to get rid of the baseline participation
-    // flag (hence just using a HashSet) depending on the CSS WG resolution on
-    // https://github.com/w3c/csswg-drafts/issues/3046
-    if (CanParticipateInBaselineAlignment(*child, axis)) {
-      UpdateBaselineAlignmentContext(*child, axis);
-      baseline_items_cache.Set(child, true);
-    } else {
-      baseline_items_cache.Set(child, false);
-    }
-  }
-}
-
-// Described in https://drafts.csswg.org/css-grid/#algo-track-sizing
-void GridTrackSizingAlgorithm::Run() {
-  DCHECK(WasSetup());
-  StateMachine state_machine(*this);
-
-  // Step 1.
-  absl::optional<LayoutUnit> initial_free_space = FreeSpace(direction_);
-  InitializeTrackSizes();
-
-  if (strategy_->IsComputingSizeContainment()) {
-    ComputeGridContainerIntrinsicSizes();
-    return;
-  }
-
-  // Step 2.
-  if (!content_sized_tracks_index_.empty())
-    ResolveIntrinsicTrackSizes();
-
-  // This is not exactly a step of the track sizing algorithm, but we use the
-  // track sizes computed
-  // up to this moment (before maximization) to calculate the grid container
-  // intrinsic sizes.
-  ComputeGridContainerIntrinsicSizes();
-
-  if (FreeSpace(direction_)) {
-    LayoutUnit updated_free_space =
-        FreeSpace(direction_).value() - min_content_size_;
-    SetFreeSpace(direction_, updated_free_space);
-    if (updated_free_space <= 0)
-      return;
-  }
-
-  // Step 3.
-  strategy_->MaximizeTracks(Tracks(direction_), direction_ == kForColumns
-                                                    ? free_space_columns_
-                                                    : free_space_rows_);
-
-  // Step 4.
-  StretchFlexibleTracks(initial_free_space);
-
-  // Step 5.
-  StretchAutoTracks();
-}
-
-void GridTrackSizingAlgorithm::Reset() {
-  DCHECK(WasSetup());
-  sizing_state_ = kColumnSizingFirstIteration;
-  columns_.Shrink(0);
-  rows_.Shrink(0);
-  content_sized_tracks_index_.Shrink(0);
-  flexible_sized_tracks_index_.Shrink(0);
-  auto_sized_tracks_for_stretch_index_.Shrink(0);
-  has_percent_sized_rows_indefinite_height_ = false;
-  SetAvailableSpace(kForRows, absl::nullopt);
-  SetAvailableSpace(kForColumns, absl::nullopt);
-}
-
-#if DCHECK_IS_ON()
-bool GridTrackSizingAlgorithm::TracksAreWiderThanMinTrackBreadth() const {
-  const Vector<GridTrack>& all_tracks = Tracks(direction_);
-  for (const auto& all_track : all_tracks) {
-    const GridTrackSize& track_size = all_track.CachedTrackSize();
-    if (InitialBaseSize(track_size) > all_track.BaseSize())
-      return false;
-  }
-  return true;
-}
-#endif
-
-GridTrackSizingAlgorithm::StateMachine::StateMachine(
-    GridTrackSizingAlgorithm& algorithm)
-    : algorithm_(algorithm) {
-  DCHECK(algorithm_.IsValidTransition());
-  DCHECK(!algorithm_.needs_setup_);
-}
-
-GridTrackSizingAlgorithm::StateMachine::~StateMachine() {
-  algorithm_.AdvanceNextState();
-  algorithm_.needs_setup_ = true;
-}
-
-}  // namespace blink
-
-WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::GridItemWithSpan)
diff --git a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
deleted file mode 100644
index c41e4c1..0000000
--- a/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_TRACK_SIZING_ALGORITHM_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_TRACK_SIZING_ALGORITHM_H_
-
-#include <memory>
-
-#include "base/dcheck_is_on.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/blink/renderer/core/layout/grid_baseline_alignment.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
-#include "third_party/blink/renderer/core/style/grid_track_size.h"
-#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-
-namespace blink {
-
-static const int kInfinity = -1;
-
-class Grid;
-class GridTrackSizingAlgorithmStrategy;
-class LayoutGrid;
-
-enum TrackSizeComputationPhase {
-  kResolveIntrinsicMinimums,
-  kResolveContentBasedMinimums,
-  kResolveMaxContentMinimums,
-  kResolveIntrinsicMaximums,
-  kResolveMaxContentMaximums,
-  kMaximizeTracks,
-};
-
-class GridTrack {
-  DISALLOW_NEW();
-
- public:
-  LayoutUnit BaseSize() const;
-  void SetBaseSize(LayoutUnit);
-
-  LayoutUnit GrowthLimit() const;
-  bool GrowthLimitIsInfinite() const { return growth_limit_ == kInfinity; }
-  void SetGrowthLimit(LayoutUnit);
-
-  bool InfiniteGrowthPotential() const;
-
-  LayoutUnit PlannedSize() const { return planned_size_; }
-  void SetPlannedSize(LayoutUnit);
-
-  LayoutUnit SizeDuringDistribution() const {
-    return size_during_distribution_;
-  }
-  void SetSizeDuringDistribution(LayoutUnit);
-
-  void GrowSizeDuringDistribution(LayoutUnit);
-
-  bool InfinitelyGrowable() const { return infinitely_growable_; }
-  void SetInfinitelyGrowable(bool);
-
-  absl::optional<LayoutUnit> GrowthLimitCap() const {
-    return growth_limit_cap_;
-  }
-  void SetGrowthLimitCap(absl::optional<LayoutUnit>);
-
-  const GridTrackSize& CachedTrackSize() const {
-    DCHECK(cached_track_size_.has_value());
-    return cached_track_size_.value();
-  }
-  void SetCachedTrackSize(const GridTrackSize&);
-
- private:
-  bool IsGrowthLimitBiggerThanBaseSize() const;
-  void EnsureGrowthLimitIsBiggerThanBaseSize();
-
-  LayoutUnit base_size_;
-  LayoutUnit growth_limit_;
-  LayoutUnit planned_size_;
-  LayoutUnit size_during_distribution_;
-  absl::optional<LayoutUnit> growth_limit_cap_;
-  bool infinitely_growable_ = false;
-  absl::optional<GridTrackSize> cached_track_size_;
-};
-
-class GridTrackSizingAlgorithm final
-    : public GarbageCollected<GridTrackSizingAlgorithm> {
-  friend class GridTrackSizingAlgorithmStrategy;
-
- public:
-  GridTrackSizingAlgorithm(const LayoutGrid* layout_grid, Grid& grid)
-      : grid_(grid),
-        layout_grid_(layout_grid),
-        sizing_state_(kColumnSizingFirstIteration) {}
-
-  // Setup() must be run before calling Run() as it configures the behaviour of
-  // the algorithm.
-  void Setup(GridTrackSizingDirection,
-             wtf_size_t num_tracks,
-             absl::optional<LayoutUnit> available_space);
-  void Run();
-  void Reset();
-
-  // Required by LayoutGrid. Try to minimize the exposed surface.
-  const Grid& GetGrid() const { return *grid_; }
-  // TODO (jfernandez): We should remove any public getter for this attribute
-  // and encapsulate any access in the algorithm class.
-  Grid& GetMutableGrid() const { return *grid_; }
-  LayoutUnit MinContentSize() const { return min_content_size_; }
-  LayoutUnit MaxContentSize() const { return max_content_size_; }
-
-  LayoutUnit BaselineOffsetForChild(const LayoutBox&, GridAxis) const;
-
-  void CacheBaselineAlignedItem(const LayoutBox&, GridAxis);
-  void CopyBaselineItemsCache(const GridTrackSizingAlgorithm*, GridAxis);
-  void ClearBaselineItemsCache();
-
-  LayoutSize EstimatedGridAreaBreadthForChild(const LayoutBox& child) const;
-
-  Vector<GridTrack>& Tracks(GridTrackSizingDirection);
-  const Vector<GridTrack>& Tracks(GridTrackSizingDirection) const;
-
-  absl::optional<LayoutUnit> FreeSpace(GridTrackSizingDirection) const;
-  void SetFreeSpace(GridTrackSizingDirection, absl::optional<LayoutUnit>);
-
-  absl::optional<LayoutUnit> AvailableSpace(GridTrackSizingDirection) const;
-  void SetAvailableSpace(GridTrackSizingDirection, absl::optional<LayoutUnit>);
-
-#if DCHECK_IS_ON()
-  bool TracksAreWiderThanMinTrackBreadth() const;
-#endif
-
-  LayoutUnit ComputeTrackBasedSize() const;
-
-  bool HasAnyPercentSizedRowsIndefiniteHeight() const {
-    return has_percent_sized_rows_indefinite_height_;
-  }
-
-  void Trace(Visitor* visitor) const {
-    visitor->Trace(grid_);
-    visitor->Trace(layout_grid_);
-    visitor->Trace(strategy_);
-    visitor->Trace(baseline_alignment_);
-    visitor->Trace(column_baseline_items_map_);
-    visitor->Trace(row_baseline_items_map_);
-  }
-
- private:
-  absl::optional<LayoutUnit> AvailableSpace() const;
-  bool IsRelativeGridLengthAsAuto(const GridLength&,
-                                  GridTrackSizingDirection) const;
-  bool IsRelativeSizedTrackAsAuto(const GridTrackSize&,
-                                  GridTrackSizingDirection) const;
-  GridTrackSize CalculateGridTrackSize(GridTrackSizingDirection,
-                                       wtf_size_t translated_index) const;
-  const GridTrackSize& RawGridTrackSize(GridTrackSizingDirection,
-                                        wtf_size_t translated_index) const;
-
-  // Helper methods for step 1. initializeTrackSizes().
-  LayoutUnit InitialBaseSize(const GridTrackSize&) const;
-  LayoutUnit InitialGrowthLimit(const GridTrackSize&,
-                                LayoutUnit base_size) const;
-
-  // Helper methods for step 2. resolveIntrinsicTrackSizes().
-  void SizeTrackToFitNonSpanningItem(const GridSpan&,
-                                     LayoutBox& grid_item,
-                                     GridTrack&);
-  bool SpanningItemCrossesFlexibleSizedTracks(const GridSpan&) const;
-  typedef class GridItemWithSpan GridItemWithSpan;
-  template <TrackSizeComputationPhase phase>
-  void IncreaseSizesToAccommodateSpanningItems(
-      const HeapVector<GridItemWithSpan>::iterator& grid_items_with_span_begin,
-      const HeapVector<GridItemWithSpan>::iterator& grid_items_with_span_end);
-  LayoutUnit ItemSizeForTrackSizeComputationPhase(TrackSizeComputationPhase,
-                                                  LayoutBox&) const;
-  template <TrackSizeComputationPhase phase>
-  void DistributeSpaceToTracks(
-      Vector<GridTrack*>& tracks,
-      Vector<GridTrack*>* grow_beyond_growth_limits_tracks,
-      LayoutUnit& available_logical_space) const;
-  LayoutUnit EstimatedGridAreaBreadthForChild(const LayoutBox&,
-                                              GridTrackSizingDirection) const;
-  LayoutUnit GridAreaBreadthForChild(const LayoutBox&,
-                                     GridTrackSizingDirection) const;
-
-  void ComputeBaselineAlignmentContext();
-  void UpdateBaselineAlignmentContext(const LayoutBox&, GridAxis);
-  bool CanParticipateInBaselineAlignment(const LayoutBox&, GridAxis) const;
-  bool ParticipateInBaselineAlignment(const LayoutBox&, GridAxis) const;
-
-  bool IsIntrinsicSizedGridArea(const LayoutBox&, GridAxis) const;
-  void ComputeGridContainerIntrinsicSizes();
-
-  // Helper methods for step 4. Stretch flexible tracks.
-  typedef HashSet<size_t, IntWithZeroKeyHashTraits<size_t>> TrackIndexSet;
-  double ComputeFlexFactorUnitSize(
-      const Vector<GridTrack>& tracks,
-      double flex_factor_sum,
-      LayoutUnit& left_over_space,
-      const Vector<wtf_size_t, 8>& flexible_tracks_indexes,
-      std::unique_ptr<TrackIndexSet> tracks_to_treat_as_inflexible =
-          nullptr) const;
-  void ComputeFlexSizedTracksGrowth(double flex_fraction,
-                                    Vector<LayoutUnit>& increments,
-                                    LayoutUnit& total_growth) const;
-  double FindFrUnitSize(const GridSpan& tracks_span,
-                        LayoutUnit left_over_space) const;
-
-  // Track sizing algorithm steps. Note that the "Maximize Tracks" step is done
-  // entirely inside the strategies, that's why we don't need an additional
-  // method at thise level.
-  void InitializeTrackSizes();
-  void ResolveIntrinsicTrackSizes();
-  void StretchFlexibleTracks(absl::optional<LayoutUnit> free_space);
-  void StretchAutoTracks();
-
-  // State machine.
-  void AdvanceNextState();
-  bool IsValidTransition() const;
-
-  // Data.
-  bool WasSetup() const { return !!strategy_; }
-  bool needs_setup_{true};
-  bool has_percent_sized_rows_indefinite_height_{false};
-  absl::optional<LayoutUnit> available_space_columns_;
-  absl::optional<LayoutUnit> available_space_rows_;
-
-  absl::optional<LayoutUnit> free_space_columns_;
-  absl::optional<LayoutUnit> free_space_rows_;
-
-  // We need to keep both alive in order to properly size grids with orthogonal
-  // writing modes.
-  Vector<GridTrack> columns_;
-  Vector<GridTrack> rows_;
-  Vector<wtf_size_t> content_sized_tracks_index_;
-  Vector<wtf_size_t> flexible_sized_tracks_index_;
-  Vector<wtf_size_t> auto_sized_tracks_for_stretch_index_;
-
-  GridTrackSizingDirection direction_;
-
-  Member<Grid> grid_;
-  Member<const LayoutGrid> layout_grid_;
-  Member<GridTrackSizingAlgorithmStrategy> strategy_;
-
-  // The track sizing algorithm is used for both layout and intrinsic size
-  // computation. We're normally just interested in intrinsic inline sizes
-  // (a.k.a widths in most of the cases) for the computeIntrinsicLogicalWidths()
-  // computations. That's why we don't need to keep around different values for
-  // rows/columns.
-  LayoutUnit min_content_size_;
-  LayoutUnit max_content_size_;
-
-  enum SizingState {
-    kColumnSizingFirstIteration,
-    kRowSizingFirstIteration,
-    kColumnSizingSecondIteration,
-    kRowSizingSecondIteration
-  };
-  SizingState sizing_state_;
-
-  GridBaselineAlignment baseline_alignment_;
-
-  using BaselineItemsCache = HeapHashMap<Member<const LayoutBox>, bool>;
-  BaselineItemsCache column_baseline_items_map_;
-  BaselineItemsCache row_baseline_items_map_;
-
-  // This is a RAII class used to ensure that the track sizing algorithm is
-  // executed as it is suppossed to be, i.e., first resolve columns and then
-  // rows. Only if required a second iteration is run following the same order,
-  // first columns and then rows.
-  class StateMachine {
-    STACK_ALLOCATED();
-
-   public:
-    explicit StateMachine(GridTrackSizingAlgorithm&);
-    ~StateMachine();
-
-   private:
-    GridTrackSizingAlgorithm& algorithm_;
-  };
-};
-
-class GridTrackSizingAlgorithmStrategy
-    : public GarbageCollected<GridTrackSizingAlgorithmStrategy> {
- public:
-  GridTrackSizingAlgorithmStrategy(const GridTrackSizingAlgorithmStrategy&) =
-      delete;
-  GridTrackSizingAlgorithmStrategy& operator=(
-      const GridTrackSizingAlgorithmStrategy&) = delete;
-  virtual ~GridTrackSizingAlgorithmStrategy();
-
-  virtual LayoutUnit MinContentForChild(LayoutBox&) const;
-  virtual LayoutUnit MaxContentForChild(LayoutBox&) const;
-  LayoutUnit MinSizeForChild(LayoutBox&) const;
-
-  virtual void MaximizeTracks(Vector<GridTrack>&,
-                              absl::optional<LayoutUnit>& free_space) = 0;
-  virtual double FindUsedFlexFraction(
-      Vector<wtf_size_t>& flexible_sized_tracks_index,
-      GridTrackSizingDirection,
-      absl::optional<LayoutUnit> initial_free_space) const = 0;
-  virtual bool RecomputeUsedFlexFractionIfNeeded(
-      double& flex_fraction,
-      Vector<LayoutUnit>& increments,
-      LayoutUnit& total_growth) const = 0;
-  virtual LayoutUnit FreeSpaceForStretchAutoTracksStep() const = 0;
-  virtual bool IsComputingSizeContainment() const = 0;
-  virtual void Trace(Visitor* visitor) const { visitor->Trace(algorithm_); }
-
- protected:
-  explicit GridTrackSizingAlgorithmStrategy(GridTrackSizingAlgorithm& algorithm)
-      : algorithm_(algorithm) {}
-
-  virtual LayoutUnit MinLogicalSizeForChild(LayoutBox&,
-                                            const Length& child_min_size,
-                                            LayoutUnit available_size) const;
-  virtual void LayoutGridItemForMinSizeComputation(
-      LayoutBox&,
-      bool override_size_has_changed) const = 0;
-
-  LayoutUnit LogicalHeightForChild(LayoutBox&) const;
-
-  bool UpdateOverrideContainingBlockContentSizeForChild(
-      LayoutBox&,
-      GridTrackSizingDirection,
-      absl::optional<LayoutUnit> = absl::nullopt) const;
-  LayoutUnit ComputeTrackBasedSize() const;
-
-  GridTrackSizingDirection Direction() const { return algorithm_->direction_; }
-  double FindFrUnitSize(const GridSpan& tracks_span,
-                        LayoutUnit left_over_space) const;
-  void DistributeSpaceToTracks(Vector<GridTrack*>& tracks,
-                               LayoutUnit& available_logical_space) const;
-  const LayoutGrid* GetLayoutGrid() const { return algorithm_->layout_grid_; }
-  absl::optional<LayoutUnit> AvailableSpace() const {
-    return algorithm_->AvailableSpace();
-  }
-
-  // Helper functions
-  static bool HasRelativeMarginOrPaddingForChild(const LayoutGrid&,
-                                                 const LayoutBox& child,
-                                                 GridTrackSizingDirection);
-  static bool HasRelativeOrIntrinsicSizeForChild(const LayoutGrid&,
-                                                 const LayoutBox& child,
-                                                 GridTrackSizingDirection);
-  static bool ShouldClearOverrideContainingBlockContentSizeForChild(
-      const LayoutGrid&,
-      const LayoutBox& child,
-      GridTrackSizingDirection);
-  static void SetOverrideContainingBlockContentSizeForChild(
-      LayoutBox& child,
-      GridTrackSizingDirection,
-      LayoutUnit size);
-
-  Member<GridTrackSizingAlgorithm> algorithm_;
-};
-}
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_TRACK_SIZING_ALGORITHM_H_
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 360424a..3e61f93 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
@@ -330,7 +329,7 @@
     if (new_child->IsInline() ||
         (new_child->IsFloatingOrOutOfFlowPositioned() &&
          (StyleRef().IsDeprecatedFlexboxUsingFlexLayout() ||
-          (!IsFlexibleBoxIncludingNG() && !IsLayoutGridIncludingNG()))) ||
+          (!IsFlexibleBoxIncludingNG() && !IsLayoutNGGrid()))) ||
         before_descendant->Parent()->SlowFirstChild() != before_descendant) {
       before_descendant_container->AddChild(new_child, before_descendant);
     } else {
@@ -374,7 +373,7 @@
   if (new_child->IsInline() ||
       (new_child->IsFloatingOrOutOfFlowPositioned() &&
        (StyleRef().IsDeprecatedFlexboxUsingFlexLayout() ||
-        (!IsFlexibleBoxIncludingNG() && !IsLayoutGridIncludingNG())))) {
+        (!IsFlexibleBoxIncludingNG() && !IsLayoutNGGrid())))) {
     // If we're inserting an inline child but all of our children are blocks,
     // then we have to make sure it is put into an anomyous block box. We try to
     // use an existing anonymous box if possible, otherwise a new one is created
@@ -418,11 +417,6 @@
   // anonymous block.
   child->RemoveFromLayoutFlowThread();
 
-  // LayoutGrid keeps track of its children, we must notify it about changes in
-  // the tree.
-  if (child->Parent()->IsLayoutGrid())
-    To<LayoutGrid>(child->Parent())->DirtyGrid();
-
   // Now remove the leftover anonymous block from the tree, and destroy it.
   // We'll rip it out manually from the tree before destroying it, because we
   // don't want to trigger any tree adjustments with regards to anonymous blocks
@@ -1961,8 +1955,9 @@
 
   // Orthogonal grid items can participate in baseline alignment along column
   // axis.
-  if (IsWritingModeRoot() && !IsRubyRun() && !IsGridItem())
+  if (IsWritingModeRoot() && !IsRubyRun()) {
     return LayoutUnit(-1);
+  }
 
   return absl::nullopt;
 }
@@ -2292,8 +2287,7 @@
     layout_block = LayoutObjectFactory::CreateFlexibleBox(parent->GetDocument(),
                                                           *new_style, legacy);
   } else if (new_display == EDisplay::kGrid) {
-    layout_block = LayoutObjectFactory::CreateGrid(parent->GetDocument(),
-                                                   *new_style, legacy);
+    layout_block = MakeGarbageCollected<LayoutNGGrid>(/* element */ nullptr);
   } else if (new_display == EDisplay::kBlockMath) {
     layout_block = LayoutObjectFactory::CreateMath(parent->GetDocument(),
                                                    *new_style, legacy);
@@ -2506,8 +2500,6 @@
   }
   if (stretched_flex_height != LayoutUnit(-1)) {
     available_height = stretched_flex_height;
-  } else if (IsGridItem() && HasOverrideLogicalHeight()) {
-    available_height = OverrideContentLogicalHeight();
   } else if (style.LogicalHeight().IsFixed()) {
     LayoutUnit content_box_height = AdjustContentBoxLogicalHeightForBoxSizing(
         style.LogicalHeight().Value());
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 4ed1c5cc3..cbf2d36 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -69,7 +69,6 @@
 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
@@ -916,19 +915,6 @@
   LayoutObject* parent = Parent();
   const bool was_out_of_flow = old_style->HasOutOfFlowPosition();
   const bool is_out_of_flow = StyleRef().HasOutOfFlowPosition();
-  if (parent && parent->IsLayoutGrid() &&
-      GridStyleChanged(old_style, StyleRef())) {
-    // Positioned items don't participate on the layout of the grid,
-    // so we don't need to mark the grid as dirty if they change positions.
-    if (was_out_of_flow && is_out_of_flow)
-      return;
-
-    // It should be possible to not dirty the grid in some cases (like moving an
-    // explicitly placed grid item).
-    // For now, it's more simple to just always recompute the grid.
-    To<LayoutGrid>(Parent())->DirtyGrid();
-    return;
-  }
 
   LayoutBlock* containing_block = ContainingBlock();
   if ((containing_block && containing_block->IsLayoutNGGrid()) &&
@@ -4064,9 +4050,6 @@
   if (StyleRef().AspectRatio().IsAuto())
     return false;
 
-  if (IsGridItem() && HasStretchedLogicalWidth(StretchingMode::kExplicit))
-    return false;
-
   if (!HasOverrideLogicalHeight() &&
       !ShouldComputeLogicalWidthFromAspectRatioAndInsets() &&
       !StyleRef().LogicalHeight().IsFixed() &&
@@ -4141,7 +4124,7 @@
   // to any block.
   bool treat_as_replaced = ShouldComputeSizeAsReplaced() &&
                            (!in_vertical_box || !stretching) &&
-                           (!IsGridItem() || !HasStretchedLogicalWidth());
+                           !HasStretchedLogicalWidth();
   const ComputedStyle& style_to_use = StyleRef();
   LayoutUnit container_logical_width =
       std::max(LayoutUnit(), ContainingBlockLogicalWidthForContent());
@@ -4168,8 +4151,8 @@
     computed_values.extent_ =
         ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth();
   } else if (StyleRef().LogicalWidth().IsAuto() &&
-             (!IsGridItem() || !ShouldComputeSizeAsReplaced() ||
-              !HasStretchedLogicalWidth() || !HasStretchedLogicalHeight()) &&
+             (!ShouldComputeSizeAsReplaced() || !HasStretchedLogicalWidth() ||
+              !HasStretchedLogicalHeight()) &&
              ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
     /* we're good */
   } else {
@@ -4193,8 +4176,7 @@
           (computed_values.extent_ + computed_values.margins_.start_ +
            computed_values.margins_.end_) &&
       !IsFloating() && !IsInline() &&
-      !cb->IsFlexibleBoxIncludingDeprecatedAndNG() &&
-      !cb->IsLayoutGridIncludingNG()) {
+      !cb->IsFlexibleBoxIncludingDeprecatedAndNG() && !cb->IsLayoutNGGrid()) {
     LayoutUnit new_margin_total =
         container_logical_width - computed_values.extent_;
     bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() !=
@@ -4442,9 +4424,6 @@
       StyleRef().HasOutOfFlowPosition())
     return true;
 
-  if (IsGridItem())
-    return !HasStretchedLogicalWidth();
-
   // Flexible box items should shrink wrap, so we lay them out at their
   // intrinsic widths. In the case of columns that have a stretch alignment, we
   // go ahead and layout at the stretched size to avoid an extra layout when
@@ -4658,7 +4637,7 @@
       // added before calling ComputeLogicalHeight to avoid this hack.
       if (IsTextControlIncludingNG())
         SetIntrinsicContentLogicalHeight(default_height);
-    } else if (ShouldApplySizeContainment() && !IsLayoutGrid()) {
+    } else if (ShouldApplySizeContainment()) {
       height = BorderAndPaddingLogicalHeight() +
                ComputeLogicalScrollbars().BlockSum();
     } else {
@@ -4858,8 +4837,9 @@
       logical_height_length.IsMinIntrinsic() ||
       logical_height_length.IsFitContent()) {
     if (IsAtomicInlineLevel() && !IsFlexibleBoxIncludingNG() &&
-        !IsLayoutGridIncludingNG())
+        !IsLayoutNGGrid()) {
       return IntrinsicSize().Height();
+    }
     return intrinsic_content_height;
   }
   if (logical_height_length.IsFillAvailable()) {
@@ -4958,7 +4938,7 @@
   return !containing_block->IsTableCell() &&
          !containing_block->IsOutOfFlowPositioned() &&
          !containing_block->HasOverridePercentageResolutionBlockSize() &&
-         !containing_block->IsLayoutGridIncludingNG() &&
+         !containing_block->IsLayoutNGGrid() &&
          !containing_block->IsFlexibleBoxIncludingDeprecatedAndNG() &&
          !containing_block->IsLayoutNGCustom();
 }
@@ -5284,9 +5264,6 @@
           const auto* flex_box = To<LayoutFlexibleBox>(block->Parent());
           if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*block))
             stretched_height = block->OverrideContentLogicalHeight();
-        } else if (block->IsGridItem() && block->HasOverrideLogicalHeight() &&
-                   !has_perpendicular_containing_block) {
-          stretched_height = block->OverrideContentLogicalHeight();
         }
       }
 
@@ -5614,18 +5591,6 @@
   LayoutObject* parent = child->Parent();
   TextDirection parent_direction = parent->StyleRef().Direction();
 
-  // This method is using EnclosingBox() which is wrong for absolutely
-  // positioned grid items, as they rely on the grid area. So for grid items if
-  // both "left" and "right" properties are "auto", we can consider that one of
-  // them (depending on the direction) is simply "0".
-  if (parent->IsLayoutGrid() && parent == child->ContainingBlock()) {
-    if (parent_direction == TextDirection::kLtr)
-      logical_left = Length::Fixed(0);
-    else
-      logical_right = Length::Fixed(0);
-    return;
-  }
-
   // For multicol we also need to keep track of the block position, since that
   // determines which column we're in and thus affects the inline position.
   LayoutUnit static_block_position = child->Layer()->StaticBlockPosition();
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 47a1195..b4654f2b 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1754,13 +1754,10 @@
     return !IsInline() && !IsOutOfFlowPositioned() && Parent();
   }
 
-  bool IsGridItem() const {
-    NOT_DESTROYED();
-    return Parent() && Parent()->IsLayoutGrid();
-  }
+  // TODO(1229581): Rename this function.
   bool IsGridItemIncludingNG() const {
     NOT_DESTROYED();
-    return Parent() && Parent()->IsLayoutGridIncludingNG();
+    return Parent() && Parent()->IsLayoutNGGrid();
   }
 
   bool IsMathItem() const {
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 16b46f7..5472038 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -643,11 +643,6 @@
         return false;
     }
   }
-  if (this_box && this_box->IsGridItem() &&
-      this_box->HasOverrideContainingBlockContentLogicalHeight()) {
-    return this_box->OverrideContainingBlockContentLogicalHeight() ==
-           kIndefiniteSize;
-  }
   if (this_box && this_box->IsCustomItem() &&
       (this_box->HasOverrideContainingBlockContentLogicalHeight() ||
        this_box->HasOverridePercentageResolutionBlockSize()))
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc
deleted file mode 100644
index 930fd33..0000000
--- a/third_party/blink/renderer/core/layout/layout_grid.cc
+++ /dev/null
@@ -1,2709 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
-#include "third_party/blink/renderer/core/layout/layout_state.h"
-#include "third_party/blink/renderer/core/layout/text_autosizer.h"
-#include "third_party/blink/renderer/core/paint/block_painter.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/core/style/grid_area.h"
-#include "third_party/blink/renderer/platform/geometry/length_functions.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
-#include "third_party/blink/renderer/platform/text/writing_mode.h"
-
-namespace blink {
-
-LayoutGrid::LayoutGrid(Element* element)
-    : LayoutBlock(element),
-      grid_(Grid::Create(this)),
-      track_sizing_algorithm_(
-          MakeGarbageCollected<GridTrackSizingAlgorithm>(this, *grid_)) {
-  DCHECK(!ChildrenInline());
-}
-
-LayoutGrid::~LayoutGrid() = default;
-
-void LayoutGrid::Trace(Visitor* visitor) const {
-  visitor->Trace(grid_);
-  visitor->Trace(track_sizing_algorithm_);
-  visitor->Trace(column_of_positioned_item_);
-  visitor->Trace(row_of_positioned_item_);
-  LayoutBlock::Trace(visitor);
-}
-
-LayoutGrid* LayoutGrid::CreateAnonymous(Document* document) {
-  LayoutGrid* layout_grid = MakeGarbageCollected<LayoutGrid>(nullptr);
-  layout_grid->SetDocumentForAnonymous(document);
-  return layout_grid;
-}
-
-void LayoutGrid::AddChild(LayoutObject* new_child, LayoutObject* before_child) {
-  NOT_DESTROYED();
-  LayoutBlock::AddChild(new_child, before_child);
-
-  // Positioned grid items do not take up space or otherwise participate in the
-  // layout of the grid, for that reason we don't need to mark the grid as dirty
-  // when they are added.
-  if (new_child->IsOutOfFlowPositioned())
-    return;
-
-  // The grid needs to be recomputed as it might contain auto-placed items that
-  // will change their position.
-  DirtyGrid();
-}
-
-void LayoutGrid::RemoveChild(LayoutObject* child) {
-  NOT_DESTROYED();
-  LayoutBlock::RemoveChild(child);
-
-  // Positioned grid items do not take up space or otherwise participate in the
-  // layout of the grid, for that reason we don't need to mark the grid as dirty
-  // when they are removed.
-  if (child->IsOutOfFlowPositioned())
-    return;
-
-  // The grid needs to be recomputed as it might contain auto-placed items that
-  // will change their position.
-  DirtyGrid();
-}
-
-StyleSelfAlignmentData LayoutGrid::SelfAlignmentForChild(
-    GridAxis axis,
-    const LayoutBox& child,
-    const ComputedStyle* style) const {
-  NOT_DESTROYED();
-  return axis == kGridRowAxis ? JustifySelfForChild(child, style)
-                              : AlignSelfForChild(child, style);
-}
-
-StyleSelfAlignmentData LayoutGrid::DefaultAlignment(
-    GridAxis axis,
-    const ComputedStyle& style) const {
-  NOT_DESTROYED();
-  return axis == kGridRowAxis
-             ? style.ResolvedJustifyItems(ItemPosition::kNormal)
-             : style.ResolvedAlignItems(ItemPosition::kNormal);
-}
-
-bool LayoutGrid::DefaultAlignmentIsStretchOrNormal(
-    GridAxis axis,
-    const ComputedStyle& style) const {
-  NOT_DESTROYED();
-  ItemPosition alignment = DefaultAlignment(axis, style).GetPosition();
-  return alignment == ItemPosition::kStretch ||
-         alignment == ItemPosition::kNormal;
-}
-
-bool LayoutGrid::SelfAlignmentChangedSize(GridAxis axis,
-                                          const ComputedStyle& old_style,
-                                          const ComputedStyle& new_style,
-                                          const LayoutBox& child) const {
-  NOT_DESTROYED();
-  return SelfAlignmentForChild(axis, child, &old_style).GetPosition() ==
-                 ItemPosition::kStretch
-             ? SelfAlignmentForChild(axis, child, &new_style).GetPosition() !=
-                   ItemPosition::kStretch
-             : SelfAlignmentForChild(axis, child, &new_style).GetPosition() ==
-                   ItemPosition::kStretch;
-}
-
-bool LayoutGrid::DefaultAlignmentChangedSize(
-    GridAxis axis,
-    const ComputedStyle& old_style,
-    const ComputedStyle& new_style) const {
-  NOT_DESTROYED();
-  return DefaultAlignmentIsStretchOrNormal(axis, old_style)
-             ? DefaultAlignment(axis, old_style).GetPosition() !=
-                   DefaultAlignment(axis, new_style).GetPosition()
-             : DefaultAlignmentIsStretchOrNormal(axis, new_style);
-}
-
-void LayoutGrid::StyleDidChange(StyleDifference diff,
-                                const ComputedStyle* old_style) {
-  NOT_DESTROYED();
-  LayoutBlock::StyleDidChange(diff, old_style);
-  if (!old_style)
-    return;
-
-  const ComputedStyle& new_style = StyleRef();
-  if (diff.NeedsFullLayout() &&
-      (DefaultAlignmentChangedSize(kGridRowAxis, *old_style, new_style) ||
-       DefaultAlignmentChangedSize(kGridColumnAxis, *old_style, new_style))) {
-    // Style changes on the grid container implying stretching (to-stretch) or
-    // shrinking (from-stretch) require the affected items to be laid out again.
-    // These logic only applies to 'stretch' since the rest of the alignment
-    // values don't change the size of the box.
-    // In any case, the items' overrideSize will be cleared and recomputed (if
-    // necessary)  as part of the Grid layout logic, triggered by this style
-    // change.
-    for (LayoutBox* child = FirstInFlowChildBox(); child;
-         child = child->NextInFlowSiblingBox()) {
-      if (SelfAlignmentChangedSize(kGridRowAxis, *old_style, new_style,
-                                   *child) ||
-          SelfAlignmentChangedSize(kGridColumnAxis, *old_style, new_style,
-                                   *child)) {
-        child->SetNeedsLayout(layout_invalidation_reason::kGridChanged);
-      }
-    }
-  }
-
-  // FIXME: The following checks could be narrowed down if we kept track of
-  // which type of grid items we have:
-  // - explicit grid size changes impact negative explicitely positioned and
-  //   auto-placed grid items.
-  // - named grid lines only impact grid items with named grid lines.
-  // - auto-flow changes only impacts auto-placed children.
-
-  if (ExplicitGridDidResize(*old_style) ||
-      NamedGridLinesDefinitionDidChange(*old_style) ||
-      old_style->GetGridAutoFlow() != new_style.GetGridAutoFlow() ||
-      (diff.NeedsLayout() &&
-       (new_style.GridTemplateColumns().auto_repeat_track_sizes.size() ||
-        new_style.GridTemplateRows().auto_repeat_track_sizes.size()))) {
-    DirtyGrid();
-  }
-}
-
-bool LayoutGrid::ExplicitGridDidResize(const ComputedStyle& old_style) const {
-  NOT_DESTROYED();
-
-  const ComputedStyle& grid_container_style = StyleRef();
-  const ComputedGridTrackList& old_column_computed_grid_track_list =
-      old_style.GridTemplateColumns();
-  const ComputedGridTrackList& old_row_computed_grid_track_list =
-      old_style.GridTemplateRows();
-  const ComputedGridTrackList& column_computed_grid_track_list =
-      grid_container_style.GridTemplateColumns();
-  const ComputedGridTrackList& row_computed_grid_track_list =
-      grid_container_style.GridTemplateRows();
-
-  return old_column_computed_grid_track_list.track_sizes.LegacyTrackList()
-                 .size() !=
-             column_computed_grid_track_list.track_sizes.LegacyTrackList()
-                 .size() ||
-         old_row_computed_grid_track_list.track_sizes.LegacyTrackList()
-                 .size() !=
-             row_computed_grid_track_list.track_sizes.LegacyTrackList()
-                 .size() ||
-         old_style.NamedGridAreaColumnCount() !=
-             grid_container_style.NamedGridAreaColumnCount() ||
-         old_style.NamedGridAreaRowCount() !=
-             grid_container_style.NamedGridAreaRowCount() ||
-         old_column_computed_grid_track_list.auto_repeat_track_sizes.size() !=
-             column_computed_grid_track_list.auto_repeat_track_sizes.size() ||
-         old_row_computed_grid_track_list.auto_repeat_track_sizes.size() !=
-             row_computed_grid_track_list.auto_repeat_track_sizes.size();
-}
-
-bool LayoutGrid::NamedGridLinesDefinitionDidChange(
-    const ComputedStyle& old_style) const {
-  NOT_DESTROYED();
-
-  const ComputedStyle& grid_container_style = StyleRef();
-  return old_style.GridTemplateRows().named_grid_lines !=
-             grid_container_style.GridTemplateRows().named_grid_lines ||
-         old_style.GridTemplateColumns().named_grid_lines !=
-             grid_container_style.GridTemplateColumns().named_grid_lines ||
-         old_style.ImplicitNamedGridRowLines() !=
-             grid_container_style.ImplicitNamedGridRowLines() ||
-         old_style.ImplicitNamedGridColumnLines() !=
-             grid_container_style.ImplicitNamedGridColumnLines();
-}
-
-void LayoutGrid::ComputeTrackSizesForDefiniteSize(
-    GridTrackSizingDirection direction,
-    LayoutUnit available_space) {
-  NOT_DESTROYED();
-  track_sizing_algorithm_->Setup(direction, NumTracks(direction, *grid_),
-                                 available_space);
-  track_sizing_algorithm_->Run();
-
-#if DCHECK_IS_ON()
-  DCHECK(track_sizing_algorithm_->TracksAreWiderThanMinTrackBreadth());
-#endif
-}
-
-void LayoutGrid::RepeatTracksSizingIfNeeded(
-    LayoutUnit available_space_for_columns,
-    LayoutUnit available_space_for_rows) {
-  NOT_DESTROYED();
-  // In orthogonal flow cases column track's size is determined by using the
-  // computed row track's size, which it was estimated during the first cycle of
-  // the sizing algorithm.
-  // TODO (lajava): these are just some of the cases which may require
-  // a new cycle of the sizing algorithm; there may be more. In addition, not
-  // all the cases with orthogonal flows require this extra cycle; we need a
-  // more specific condition to detect whether child's min-content contribution
-  // has changed or not.
-  if (!has_any_orthogonal_item_ &&
-      !track_sizing_algorithm_->HasAnyPercentSizedRowsIndefiniteHeight())
-    return;
-
-  // TODO (lajava): Whenever the min-content contribution of a grid item changes
-  // we may need to update the grid container's intrinsic width. The new
-  // intrinsic width may also affect the extra Track Sizing algorithm cycles we
-  // are about to execute.
-  // https://crbug.com/704713
-  // https://github.com/w3c/csswg-drafts/issues/1039
-
-  // Hence we need to repeat computeUsedBreadthOfGridTracks for both, columns
-  // and rows, to determine the final values.
-  ComputeTrackSizesForDefiniteSize(kForColumns, available_space_for_columns);
-  ComputeContentPositionAndDistributionOffset(
-      kForColumns, track_sizing_algorithm_->FreeSpace(kForColumns).value(),
-      NonCollapsedTracks(kForColumns));
-  ComputeTrackSizesForDefiniteSize(kForRows, available_space_for_rows);
-  ComputeContentPositionAndDistributionOffset(
-      kForRows, track_sizing_algorithm_->FreeSpace(kForRows).value(),
-      NonCollapsedTracks(kForRows));
-}
-
-void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
-  NOT_DESTROYED();
-  DCHECK(NeedsLayout());
-
-  // We cannot perform a |SimplifiedLayout()| with a dirty grid.
-  if (!relayout_children && !grid_->NeedsItemsPlacement() && SimplifiedLayout())
-    return;
-
-  SubtreeLayoutScope layout_scope(*this);
-
-  PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
-
-  {
-    // LayoutState needs this deliberate scope to pop before updating scroll
-    // information (which may trigger relayout).
-    LayoutState state(*this);
-
-    LayoutSize previous_size = Size();
-    has_definite_logical_height_ = HasDefiniteLogicalHeight();
-
-    has_any_orthogonal_item_ = false;
-    for (auto* child = FirstInFlowChildBox(); child;
-         child = child->NextInFlowSiblingBox()) {
-      // Grid's layout logic controls the grid item's override height, hence
-      // we need to clear any override height set previously, so it doesn't
-      // interfere in current layout execution.
-      // Grid never uses the override width, that's why we don't need to clear
-      // it.
-      child->ClearOverrideLogicalHeight();
-
-      // We may need to repeat the track sizing in case of any grid item was
-      // orthogonal.
-      if (GridLayoutUtils::IsOrthogonalChild(*this, *child))
-        has_any_orthogonal_item_ = true;
-
-      // We keep a cache of items with baseline as alignment values so
-      // that we only compute the baseline shims for such items. This
-      // cache is needed for performance related reasons due to the
-      // cost of evaluating the item's participation in a baseline
-      // context during the track sizing algorithm.
-      if (IsBaselineAlignmentForChild(*child, kGridColumnAxis)) {
-        track_sizing_algorithm_->CacheBaselineAlignedItem(*child,
-                                                          kGridColumnAxis);
-      }
-      if (IsBaselineAlignmentForChild(*child, kGridRowAxis)) {
-        track_sizing_algorithm_->CacheBaselineAlignedItem(*child, kGridRowAxis);
-      }
-    }
-    baseline_items_cached_ = true;
-    UpdateLogicalWidth();
-
-    TextAutosizer::LayoutScope text_autosizer_layout_scope(this, &layout_scope);
-
-    LayoutUnit available_space_for_columns = AvailableLogicalWidth();
-    PlaceItemsOnGrid(track_sizing_algorithm_, available_space_for_columns);
-
-    track_sizing_algorithm_->SetAvailableSpace(kForColumns,
-                                               available_space_for_columns);
-    PerformGridItemsPreLayout(track_sizing_algorithm_);
-
-    // 1- First, the track sizing algorithm is used to resolve the sizes of the
-    // grid columns.
-    // At this point the logical width is always definite as the above call to
-    // updateLogicalWidth() properly resolves intrinsic sizes. We cannot do the
-    // same for heights though because many code paths inside
-    // updateLogicalHeight() require a previous call to setLogicalHeight() to
-    // resolve heights properly (like for positioned items for example).
-    ComputeTrackSizesForDefiniteSize(kForColumns, available_space_for_columns);
-
-    // 1.5- Compute Content Distribution offsets for column tracks
-    ComputeContentPositionAndDistributionOffset(
-        kForColumns, track_sizing_algorithm_->FreeSpace(kForColumns).value(),
-        NonCollapsedTracks(kForColumns));
-
-    // 2- Next, the track sizing algorithm resolves the sizes of the grid rows,
-    // using the grid column sizes calculated in the previous step.
-    bool recompute_with_track_based_height = false;
-    if (CachedHasDefiniteLogicalHeight()) {
-      ComputeTrackSizesForDefiniteSize(
-          kForRows, AvailableLogicalHeight(kExcludeMarginBorderPadding));
-    } else if (HasOverrideIntrinsicContentLogicalHeight()) {
-      ComputeTrackSizesForDefiniteSize(kForRows,
-                                       OverrideIntrinsicContentLogicalHeight());
-    } else {
-      ComputeTrackSizesForIndefiniteSize(track_sizing_algorithm_, kForRows);
-      if (ShouldApplySizeContainment())
-        recompute_with_track_based_height = true;
-    }
-    LayoutUnit track_based_logical_height =
-        track_sizing_algorithm_->ComputeTrackBasedSize() +
-        BorderAndPaddingLogicalHeight();
-    if (recompute_with_track_based_height)
-      ComputeTrackSizesForDefiniteSize(kForRows, track_based_logical_height);
-
-    // TODO(rego): We shouldn't need this once crbug.com/906530 is fixed.
-    // Right now we need this because
-    // LayoutBox::ComputeContentAndScrollbarLogicalHeightUsing() is adding the
-    // ScrollbarLogicalHeight() for the intrinsic height cases. But that's
-    // causing more problems as described in the bug linked before.
-    if (!StyleRef().LogicalHeight().IsContentOrIntrinsic())
-      track_based_logical_height += ComputeLogicalScrollbars().BlockSum();
-
-    SetLogicalHeight(track_based_logical_height);
-    UpdateLogicalHeight();
-
-    // Once grid's indefinite height is resolved, we can compute the
-    // available free space for Content Alignment.
-    if (!CachedHasDefiniteLogicalHeight()) {
-      track_sizing_algorithm_->SetFreeSpace(
-          kForRows, LogicalHeight() - track_based_logical_height);
-    }
-
-    // 2.5- Compute Content Distribution offsets for rows tracks
-    ComputeContentPositionAndDistributionOffset(
-        kForRows, track_sizing_algorithm_->FreeSpace(kForRows).value(),
-        NonCollapsedTracks(kForRows));
-
-    // 3- If the min-content contribution of any grid items have changed based
-    // on the row sizes calculated in step 2, steps 1 and 2 are repeated with
-    // the new min-content contribution (once only).
-    RepeatTracksSizingIfNeeded(available_space_for_columns,
-                               ContentLogicalHeight());
-
-    // Grid container should have the minimum height of a line if it's editable.
-    // That doesn't affect track sizing though.
-    if (HasLineIfEmpty())
-      SetLogicalHeight(
-          std::max(LogicalHeight(), MinimumLogicalHeightForEmptyLine()));
-
-    LayoutGridItems();
-    track_sizing_algorithm_->Reset();
-
-    if (NumTracks(kForRows, *grid_) > 1u && StyleRef().RowGap() &&
-        StyleRef().RowGap()->IsPercentOrCalc()) {
-      UseCounter::Count(GetDocument(), WebFeature::kGridRowGapPercent);
-      if (!CachedHasDefiniteLogicalHeight()) {
-        UseCounter::Count(GetDocument(),
-                          WebFeature::kGridRowGapPercentIndefinite);
-      }
-    }
-
-    if (Size() != previous_size)
-      relayout_children = true;
-
-    LayoutPositionedObjects(relayout_children || IsDocumentElement());
-
-    ComputeLayoutOverflow(ClientLogicalBottom());
-  }
-
-  UpdateAfterLayout();
-
-  ClearNeedsLayout();
-
-  track_sizing_algorithm_->ClearBaselineItemsCache();
-  baseline_items_cached_ = false;
-}
-
-LayoutUnit LayoutGrid::GridGap(
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit> available_size) const {
-  NOT_DESTROYED();
-  const absl::optional<Length>& gap =
-      direction == kForColumns ? StyleRef().ColumnGap() : StyleRef().RowGap();
-  if (!gap)
-    return LayoutUnit();
-
-  return ValueForLength(*gap, available_size.value_or(LayoutUnit()));
-}
-
-LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  LayoutUnit available_size;
-  bool is_row_axis = direction == kForColumns;
-
-  const absl::optional<Length>& gap =
-      is_row_axis ? StyleRef().ColumnGap() : StyleRef().RowGap();
-  if (!gap)
-    return LayoutUnit();
-
-  if (gap->IsPercentOrCalc()) {
-    available_size =
-        is_row_axis ? AvailableLogicalWidth() : ContentLogicalHeight();
-  }
-
-  // TODO(rego): Maybe we could cache the computed percentage as a performance
-  // improvement.
-  return ValueForLength(*gap, available_size);
-}
-
-LayoutUnit LayoutGrid::GuttersSize(
-    const Grid& grid,
-    GridTrackSizingDirection direction,
-    wtf_size_t start_line,
-    wtf_size_t span,
-    absl::optional<LayoutUnit> available_size) const {
-  NOT_DESTROYED();
-  if (span <= 1)
-    return LayoutUnit();
-
-  LayoutUnit gap = GridGap(direction, available_size);
-
-  // Fast path, no collapsing tracks.
-  if (!grid.HasAutoRepeatEmptyTracks(direction))
-    return gap * (span - 1);
-
-  // If there are collapsing tracks we need to be sure that gutters are properly
-  // collapsed. Apart from that, if we have a collapsed track in the edges of
-  // the span we're considering, we need to move forward (or backwards) in order
-  // to know whether the collapsed tracks reach the end of the grid (so the gap
-  // becomes 0) or there is a non empty track before that.
-
-  LayoutUnit gap_accumulator;
-  wtf_size_t end_line = start_line + span;
-
-  for (wtf_size_t line = start_line; line < end_line - 1; ++line) {
-    if (!grid.IsEmptyAutoRepeatTrack(direction, line))
-      gap_accumulator += gap;
-  }
-
-  // The above loop adds one extra gap for trailing collapsed tracks.
-  if (gap_accumulator && grid.IsEmptyAutoRepeatTrack(direction, end_line - 1)) {
-    DCHECK_GE(gap_accumulator, gap);
-    gap_accumulator -= gap;
-  }
-
-  // If the startLine is the start line of a collapsed track we need to go
-  // backwards till we reach a non collapsed track. If we find a non collapsed
-  // track we need to add that gap.
-  size_t non_empty_tracks_before_start_line = 0;
-  if (start_line && grid.IsEmptyAutoRepeatTrack(direction, start_line)) {
-    non_empty_tracks_before_start_line = start_line;
-    auto begin = grid.AutoRepeatEmptyTracks(direction)->begin();
-    for (auto it = begin; *it != start_line; ++it) {
-      DCHECK(non_empty_tracks_before_start_line);
-      --non_empty_tracks_before_start_line;
-    }
-    if (non_empty_tracks_before_start_line)
-      gap_accumulator += gap;
-  }
-
-  // If the endLine is the end line of a collapsed track we need to go forward
-  // till we reach a non collapsed track. If we find a non collapsed track we
-  // need to add that gap.
-  if (grid.IsEmptyAutoRepeatTrack(direction, end_line - 1)) {
-    size_t non_empty_tracks_after_end_line =
-        grid.NumTracks(direction) - end_line;
-    auto current_empty_track =
-        grid.AutoRepeatEmptyTracks(direction)->find(end_line - 1);
-    auto end_empty_track = grid.AutoRepeatEmptyTracks(direction)->end();
-    // HashSet iterators do not implement operator- so we have to manually
-    // iterate to know the number of remaining empty tracks.
-    for (auto it = ++current_empty_track; it != end_empty_track; ++it) {
-      DCHECK(non_empty_tracks_after_end_line);
-      --non_empty_tracks_after_end_line;
-    }
-    if (non_empty_tracks_after_end_line) {
-      // We shouldn't count the gap twice if the span starts and ends
-      // in a collapsed track bewtween two non-empty tracks.
-      if (!non_empty_tracks_before_start_line)
-        gap_accumulator += gap;
-    } else if (non_empty_tracks_before_start_line) {
-      // We shouldn't count the gap if the the span starts and ends in
-      // a collapsed but there isn't non-empty tracks afterwards (it's
-      // at the end of the grid).
-      gap_accumulator -= gap;
-    }
-  }
-
-  return gap_accumulator;
-}
-
-MinMaxSizes LayoutGrid::ComputeIntrinsicLogicalWidths() const {
-  NOT_DESTROYED();
-  MinMaxSizes sizes;
-  sizes +=
-      BorderAndPaddingLogicalWidth() + ComputeLogicalScrollbars().InlineSum();
-
-  if (HasOverrideIntrinsicContentLogicalWidth()) {
-    sizes += OverrideIntrinsicContentLogicalWidth();
-    return sizes;
-  }
-
-  Grid* grid = Grid::Create(this);
-  GridTrackSizingAlgorithm* algorithm =
-      MakeGarbageCollected<GridTrackSizingAlgorithm>(this, *grid);
-  PlaceItemsOnGrid(algorithm, absl::nullopt);
-
-  PerformGridItemsPreLayout(algorithm);
-
-  if (baseline_items_cached_) {
-    algorithm->CopyBaselineItemsCache(track_sizing_algorithm_, kGridRowAxis);
-  } else {
-    for (auto* child = FirstInFlowChildBox(); child;
-         child = child->NextInFlowSiblingBox()) {
-      if (IsBaselineAlignmentForChild(*child, kGridRowAxis)) {
-        algorithm->CacheBaselineAlignedItem(*child, kGridRowAxis);
-      }
-    }
-  }
-
-  ComputeTrackSizesForIndefiniteSize(algorithm, kForColumns);
-
-  wtf_size_t number_of_tracks = algorithm->Tracks(kForColumns).size();
-  LayoutUnit total_gutters_size = GuttersSize(
-      algorithm->GetGrid(), kForColumns, 0, number_of_tracks, absl::nullopt);
-
-  sizes.min_size += algorithm->MinContentSize() + total_gutters_size;
-  sizes.max_size += algorithm->MaxContentSize() + total_gutters_size;
-  return sizes;
-}
-
-void LayoutGrid::ComputeTrackSizesForIndefiniteSize(
-    GridTrackSizingAlgorithm* algo,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  const Grid& grid = algo->GetGrid();
-  algo->Setup(direction, NumTracks(direction, grid), absl::nullopt);
-  algo->Run();
-
-#if DCHECK_IS_ON()
-  DCHECK(algo->TracksAreWiderThanMinTrackBreadth());
-#endif
-}
-
-absl::optional<LayoutUnit> LayoutGrid::OverrideIntrinsicContentLogicalSize(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  if (direction == kForColumns && HasOverrideIntrinsicContentLogicalWidth())
-    return OverrideIntrinsicContentLogicalWidth();
-  if (direction == kForRows && HasOverrideIntrinsicContentLogicalHeight())
-    return OverrideIntrinsicContentLogicalHeight();
-  return absl::nullopt;
-}
-
-LayoutUnit LayoutGrid::OverrideContainingBlockContentSizeForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  return direction == kForColumns
-             ? child.OverrideContainingBlockContentLogicalWidth()
-             : child.OverrideContainingBlockContentLogicalHeight();
-}
-
-// Unfortunately there are still many layout methods that return -1 for
-// non-resolvable sizes. We prefer to represent them with absl::nullopt.
-static absl::optional<LayoutUnit> ConvertLayoutUnitToOptional(LayoutUnit size) {
-  if (size == -1)
-    return absl::nullopt;
-  return size;
-}
-
-wtf_size_t LayoutGrid::ComputeAutoRepeatTracksCount(
-    GridTrackSizingDirection direction,
-    absl::optional<LayoutUnit> available_size) const {
-  NOT_DESTROYED();
-  DCHECK(!available_size || available_size.value() != -1);
-
-  bool is_row_axis = direction == kForColumns;
-  const ComputedStyle& grid_container_style = StyleRef();
-  const ComputedGridTrackList& computed_grid_track_list =
-      is_row_axis ? grid_container_style.GridTemplateColumns()
-                  : grid_container_style.GridTemplateRows();
-
-  // Since auto-fit collapses empty tracks, and contain: size dictates that
-  // children should be ignored for the purposes of layout, we can conclude that
-  // if these conditions hold we have 0 repetitions.
-  if (ShouldApplySizeContainment() &&
-      (computed_grid_track_list.auto_repeat_type == AutoRepeatType::kAutoFit)) {
-    return 0;
-  }
-
-  wtf_size_t auto_repeat_track_list_length =
-      computed_grid_track_list.auto_repeat_track_sizes.size();
-  if (!auto_repeat_track_list_length)
-    return 0;
-
-  bool needs_to_fulfill_minimum_size = false;
-  if (!available_size) {
-    const Length& max_size = is_row_axis
-                                 ? grid_container_style.LogicalMaxWidth()
-                                 : grid_container_style.LogicalMaxHeight();
-    absl::optional<LayoutUnit> containing_block_available_size;
-    LayoutUnit available_max_size = LayoutUnit();
-    if (max_size.IsSpecified()) {
-      if (max_size.IsPercentOrCalc()) {
-        containing_block_available_size =
-            is_row_axis ? ContainingBlockLogicalWidthForContent()
-                        : ContainingBlockLogicalHeightForContent(
-                              kExcludeMarginBorderPadding);
-      }
-      LayoutUnit max_size_value = ValueForLength(
-          max_size, containing_block_available_size.value_or(LayoutUnit()));
-      available_max_size =
-          is_row_axis
-              ? AdjustContentBoxLogicalWidthForBoxSizing(max_size_value)
-              : AdjustContentBoxLogicalHeightForBoxSizing(max_size_value);
-    }
-
-    absl::optional<LayoutUnit> intrinsic_size_override =
-        OverrideIntrinsicContentLogicalSize(direction);
-
-    const Length& min_size = is_row_axis
-                                 ? grid_container_style.LogicalMinWidth()
-                                 : grid_container_style.LogicalMinHeight();
-    if (!available_max_size && !min_size.IsSpecified() &&
-        !intrinsic_size_override) {
-      return auto_repeat_track_list_length;
-    }
-
-    LayoutUnit available_min_size = LayoutUnit();
-    if (min_size.IsSpecified()) {
-      if (!containing_block_available_size && min_size.IsPercentOrCalc()) {
-        containing_block_available_size =
-            is_row_axis ? ContainingBlockLogicalWidthForContent()
-                        : ContainingBlockLogicalHeightForContent(
-                              kExcludeMarginBorderPadding);
-      }
-      LayoutUnit min_size_value = ValueForLength(
-          min_size, containing_block_available_size.value_or(LayoutUnit()));
-      available_min_size =
-          is_row_axis
-              ? AdjustContentBoxLogicalWidthForBoxSizing(min_size_value)
-              : AdjustContentBoxLogicalHeightForBoxSizing(min_size_value);
-    }
-
-    // See https://drafts.csswg.org/css-grid/#auto-repeat for explanation of why
-    // we use needs_to_fulfill_minimum_size. Note that we can treat the
-    // intrinsic-size similar to min-size when filling the remainder of space.
-    // That is, we should fill the intrinsic size fully.
-    if (!max_size.IsSpecified() &&
-        (min_size.IsSpecified() || intrinsic_size_override)) {
-      needs_to_fulfill_minimum_size = true;
-    }
-
-    // Now we need to determine the available size.
-    // We start with the maximum of all of the values. Then, we need to see if
-    // max-size is breached. If it is, then we can shrink the size back up to
-    // the max of min-size and max-size. This is because we can ignore
-    // intrinsic-size in this situation since the min- and max- sizes take
-    // priority.
-    auto available_intrinsic_size =
-        intrinsic_size_override.value_or(LayoutUnit());
-    available_size =
-        std::max(std::max(available_min_size, available_intrinsic_size),
-                 available_max_size);
-    if (max_size.IsSpecified() && available_max_size < available_size) {
-      available_size = std::max(available_min_size, available_max_size);
-    }
-  }
-
-  LayoutUnit auto_repeat_tracks_size;
-  for (auto auto_track_size :
-       computed_grid_track_list.auto_repeat_track_sizes) {
-    DCHECK(auto_track_size.MinTrackBreadth().IsLength());
-    DCHECK(!auto_track_size.MinTrackBreadth().IsFlex());
-    bool has_definite_max_track_sizing_function =
-        auto_track_size.MaxTrackBreadth().IsLength() &&
-        !auto_track_size.MaxTrackBreadth().IsContentSized();
-    const Length& track_length =
-        has_definite_max_track_sizing_function
-            ? auto_track_size.MaxTrackBreadth().length()
-            : auto_track_size.MinTrackBreadth().length();
-    auto_repeat_tracks_size +=
-        ValueForLength(track_length, available_size.value());
-  }
-  // For the purpose of finding the number of auto-repeated tracks, the UA must
-  // floor the track size to a UA-specified value to avoid division by zero. It
-  // is suggested that this floor be 1px.
-  auto_repeat_tracks_size =
-      std::max<LayoutUnit>(LayoutUnit(1), auto_repeat_tracks_size);
-
-  // There will be always at least 1 auto-repeat track, so take it already into
-  // account when computing the total track size.
-  LayoutUnit tracks_size = auto_repeat_tracks_size;
-  const Vector<GridTrackSize, 1>& track_sizes =
-      computed_grid_track_list.track_sizes.LegacyTrackList();
-
-  for (const auto& track : track_sizes) {
-    bool has_definite_max_track_breadth =
-        track.MaxTrackBreadth().IsLength() &&
-        !track.MaxTrackBreadth().IsContentSized();
-    DCHECK(has_definite_max_track_breadth ||
-           (track.MinTrackBreadth().IsLength() &&
-            !track.MinTrackBreadth().IsContentSized()));
-    tracks_size += ValueForLength(has_definite_max_track_breadth
-                                      ? track.MaxTrackBreadth().length()
-                                      : track.MinTrackBreadth().length(),
-                                  available_size.value());
-  }
-
-  // Add gutters as if there where only 1 auto repeat track. Gaps between auto
-  // repeat tracks will be added later when computing the repetitions.
-  LayoutUnit gap_size = GridGap(direction, available_size);
-  tracks_size +=
-      gap_size * (track_sizes.size() + auto_repeat_track_list_length - 1);
-
-  LayoutUnit free_space = available_size.value() - tracks_size;
-  if (free_space <= 0)
-    return auto_repeat_track_list_length;
-
-  LayoutUnit auto_repeat_size_with_gap =
-      auto_repeat_tracks_size + gap_size * auto_repeat_track_list_length;
-
-  int repetitions = 1 + (free_space / auto_repeat_size_with_gap).ToInt();
-  free_space -= auto_repeat_size_with_gap * (repetitions - 1);
-
-  // Provided the grid container does not have a definite size or max-size in
-  // the relevant axis, if the min size is definite then the number of
-  // repetitions is the smallest positive integer that fulfills that
-  // minimum requirement. If after determining the repetitions, we still have
-  // free space, then we need one more repetition to ensure we fill at least all
-  // of the space.
-  if (needs_to_fulfill_minimum_size && free_space)
-    ++repetitions;
-
-  return repetitions * auto_repeat_track_list_length;
-}
-
-std::unique_ptr<OrderedTrackIndexSet>
-LayoutGrid::ComputeEmptyTracksForAutoRepeat(
-    Grid& grid,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-
-  bool is_row_axis = direction == kForColumns;
-  const ComputedGridTrackList& computed_grid_track_list =
-      is_row_axis ? StyleRef().GridTemplateColumns()
-                  : StyleRef().GridTemplateRows();
-  if (computed_grid_track_list.auto_repeat_type != AutoRepeatType::kAutoFit) {
-    return nullptr;
-  }
-
-  std::unique_ptr<OrderedTrackIndexSet> empty_track_indexes;
-  wtf_size_t first_auto_repeat_track =
-      computed_grid_track_list.auto_repeat_insertion_point +
-      grid.ExplicitGridStart(direction);
-  wtf_size_t last_auto_repeat_track =
-      first_auto_repeat_track + grid.AutoRepeatTracks(direction);
-
-  if (!grid.HasGridItems()) {
-    empty_track_indexes = std::make_unique<OrderedTrackIndexSet>();
-    for (wtf_size_t track_index = first_auto_repeat_track;
-         track_index < last_auto_repeat_track; ++track_index)
-      empty_track_indexes->insert(track_index);
-  } else {
-    for (wtf_size_t track_index = first_auto_repeat_track;
-         track_index < last_auto_repeat_track; ++track_index) {
-      auto* iterator = grid.CreateIterator(direction, track_index);
-      if (!iterator->NextGridItem()) {
-        if (!empty_track_indexes)
-          empty_track_indexes = std::make_unique<OrderedTrackIndexSet>();
-        empty_track_indexes->insert(track_index);
-      }
-    }
-  }
-  return empty_track_indexes;
-}
-
-wtf_size_t LayoutGrid::ClampAutoRepeatTracks(
-    GridTrackSizingDirection direction,
-    wtf_size_t auto_repeat_tracks) const {
-  NOT_DESTROYED();
-
-  if (!auto_repeat_tracks)
-    return 0;
-
-  wtf_size_t insertion_point =
-      (direction == kForColumns)
-          ? StyleRef().GridTemplateColumns().auto_repeat_insertion_point
-          : StyleRef().GridTemplateRows().auto_repeat_insertion_point;
-
-  if (insertion_point == 0)
-    return std::min<wtf_size_t>(auto_repeat_tracks, kLegacyGridMaxTracks);
-
-  if (insertion_point >= kLegacyGridMaxTracks)
-    return 0;
-
-  return std::min(
-      auto_repeat_tracks,
-      static_cast<wtf_size_t>(kLegacyGridMaxTracks) - insertion_point);
-}
-
-// TODO(svillar): we shouldn't have to pass the available logical width as
-// argument. The problem is that availableLogicalWidth() does always return a
-// value even if we cannot resolve it like when computing the intrinsic size
-// (preferred widths). That's why we pass the responsibility to the caller who
-// does know whether the available logical width is indefinite or not.
-void LayoutGrid::PlaceItemsOnGrid(
-    GridTrackSizingAlgorithm* algorithm,
-    absl::optional<LayoutUnit> available_logical_width) const {
-  NOT_DESTROYED();
-  Grid& grid = algorithm->GetMutableGrid();
-  wtf_size_t auto_repeat_rows = ComputeAutoRepeatTracksCount(
-      kForRows, ConvertLayoutUnitToOptional(
-                    AvailableLogicalHeightForPercentageComputation()));
-  wtf_size_t auto_repeat_columns =
-      ComputeAutoRepeatTracksCount(kForColumns, available_logical_width);
-
-  auto_repeat_rows = ClampAutoRepeatTracks(kForRows, auto_repeat_rows);
-  auto_repeat_columns = ClampAutoRepeatTracks(kForColumns, auto_repeat_columns);
-
-  if (auto_repeat_rows != grid.AutoRepeatTracks(kForRows) ||
-      auto_repeat_columns != grid.AutoRepeatTracks(kForColumns)) {
-    grid.SetNeedsItemsPlacement(true);
-    grid.SetAutoRepeatTracks(auto_repeat_rows, auto_repeat_columns);
-  }
-
-  if (!grid.NeedsItemsPlacement())
-    return;
-
-  DCHECK(!grid.HasGridItems());
-  PopulateExplicitGridAndOrderIterator(grid);
-
-  HeapVector<Member<LayoutBox>> auto_major_axis_auto_grid_items;
-  HeapVector<Member<LayoutBox>> specified_major_axis_auto_grid_items;
-#if DCHECK_IS_ON()
-  DCHECK(!grid.HasAnyGridItemPaintOrder());
-#endif
-  wtf_size_t child_index = 0;
-  for (LayoutBox* child = grid.GetOrderIterator().First(); child;
-       child = grid.GetOrderIterator().Next()) {
-    if (child->IsOutOfFlowPositioned())
-      continue;
-
-    // Grid items should use the grid area sizes instead of the containing block
-    // (grid container) sizes, we initialize the overrides here if needed to
-    // ensure it.
-    if (!child->HasOverrideContainingBlockContentLogicalWidth())
-      child->SetOverrideContainingBlockContentLogicalWidth(LayoutUnit());
-    if (!child->HasOverrideContainingBlockContentLogicalHeight())
-      child->SetOverrideContainingBlockContentLogicalHeight(LayoutUnit(-1));
-
-    grid.SetGridItemPaintOrder(*child, child_index++);
-
-    GridArea area = grid.GridItemArea(*child);
-    if (!area.rows.IsIndefinite())
-      area.rows.Translate(grid.ExplicitGridStart(kForRows));
-    if (!area.columns.IsIndefinite())
-      area.columns.Translate(grid.ExplicitGridStart(kForColumns));
-
-    if (area.rows.IsIndefinite() || area.columns.IsIndefinite()) {
-      grid.SetGridItemArea(*child, area);
-      GridSpan major_axis_positions =
-          (AutoPlacementMajorAxisDirection() == kForColumns) ? area.columns
-                                                             : area.rows;
-      if (major_axis_positions.IsIndefinite())
-        auto_major_axis_auto_grid_items.push_back(child);
-      else
-        specified_major_axis_auto_grid_items.push_back(child);
-      continue;
-    }
-    grid.Insert(*child, area);
-  }
-
-#if DCHECK_IS_ON()
-  if (grid.HasGridItems()) {
-    DCHECK_GE(grid.NumTracks(kForRows),
-              GridPositionsResolver::ExplicitGridRowCount(
-                  StyleRef(), grid.AutoRepeatTracks(kForRows)));
-    DCHECK_GE(grid.NumTracks(kForColumns),
-              GridPositionsResolver::ExplicitGridColumnCount(
-                  StyleRef(), grid.AutoRepeatTracks(kForColumns)));
-  }
-#endif
-
-  PlaceSpecifiedMajorAxisItemsOnGrid(grid,
-                                     specified_major_axis_auto_grid_items);
-  PlaceAutoMajorAxisItemsOnGrid(grid, auto_major_axis_auto_grid_items);
-
-  // Compute collapsable tracks for auto-fit.
-  grid.SetAutoRepeatEmptyColumns(
-      ComputeEmptyTracksForAutoRepeat(grid, kForColumns));
-  grid.SetAutoRepeatEmptyRows(ComputeEmptyTracksForAutoRepeat(grid, kForRows));
-
-  grid.SetNeedsItemsPlacement(false);
-
-#if DCHECK_IS_ON()
-  for (LayoutBox* child = grid.GetOrderIterator().First(); child;
-       child = grid.GetOrderIterator().Next()) {
-    if (child->IsOutOfFlowPositioned())
-      continue;
-
-    GridArea area = grid.GridItemArea(*child);
-    DCHECK(area.rows.IsTranslatedDefinite());
-    DCHECK(area.columns.IsTranslatedDefinite());
-  }
-#endif
-}
-
-// TODO(lajava): Consider rafactoring this code with
-// LocalFrameView::PrepareOrthogonalWritingModeRootForLayout
-static bool PrepareOrthogonalWritingModeRootForLayout(LayoutObject& root) {
-  DCHECK(To<LayoutBox>(root).IsOrthogonalWritingModeRoot());
-  if (!root.NeedsLayout() || root.IsOutOfFlowPositioned() ||
-      root.IsColumnSpanAll() || root.IsTablePart())
-    return false;
-
-  return true;
-}
-
-void LayoutGrid::PerformGridItemsPreLayout(
-    const GridTrackSizingAlgorithm* algorithm) const {
-  NOT_DESTROYED();
-  DCHECK(!algorithm->GetGrid().NeedsItemsPlacement());
-  if (!GetDocument().View()->IsInPerformLayout())
-    return;
-  for (auto* child = FirstInFlowChildBox(); child;
-       child = child->NextInFlowSiblingBox()) {
-    // Blink does a pre-layout of all the orthogonal boxes in the layout
-    // tree (see how LocalFrameView::PerformLayout calls its
-    // LayoutOrthogonalWritingModeRoots function). However, grid items
-    // don't participate in this process (see the function
-    // PrepareOrthogonalWritingModeRootForLayout) because it's useless
-    // and even wrong if they don't have their corresponding Grid Area.
-    // TODO(jfernandez): Consider rafactoring this code with
-    // LocalFrameView::LayoutOrthogonalWritingModeRoots
-    if (GridLayoutUtils::IsOrthogonalChild(*this, *child)) {
-      if (PrepareOrthogonalWritingModeRootForLayout(*child)) {
-        UpdateGridAreaLogicalSize(
-            *child, algorithm->EstimatedGridAreaBreadthForChild(*child));
-        child->LayoutIfNeeded();
-        continue;
-      }
-    }
-    // We need to layout the item to know whether it must synthesize its
-    // baseline or not, which may imply a cyclic sizing dependency.
-    // TODO (jfernandez): Can we avoid it ?
-    if (IsBaselineAlignmentForChild(*child)) {
-      if (child->HasRelativeLogicalWidth() ||
-          child->HasRelativeLogicalHeight() ||
-          child->StyleRef().LogicalHeight().IsAuto()) {
-        UpdateGridAreaLogicalSize(
-            *child, algorithm->EstimatedGridAreaBreadthForChild(*child));
-      }
-      child->LayoutIfNeeded();
-    }
-  }
-}
-
-void LayoutGrid::PopulateExplicitGridAndOrderIterator(Grid& grid) const {
-  NOT_DESTROYED();
-  OrderIteratorPopulator populator(grid.GetOrderIterator());
-  wtf_size_t explicit_row_start = 0;
-  wtf_size_t explicit_column_start = 0;
-
-  wtf_size_t auto_repeat_rows = grid.AutoRepeatTracks(kForRows);
-  wtf_size_t auto_repeat_columns = grid.AutoRepeatTracks(kForColumns);
-  wtf_size_t maximum_row_index =
-      GridPositionsResolver::ExplicitGridRowCount(StyleRef(), auto_repeat_rows);
-  wtf_size_t maximum_column_index =
-      GridPositionsResolver::ExplicitGridColumnCount(StyleRef(),
-                                                     auto_repeat_columns);
-
-  for (LayoutBox* child = FirstInFlowChildBox(); child;
-       child = child->NextInFlowSiblingBox()) {
-    populator.CollectChild(child);
-
-    // This function bypasses the cache (gridItemArea()) as it is used to
-    // build it.
-    GridSpan row_positions =
-        GridPositionsResolver::ResolveGridPositionsFromStyle(
-            StyleRef(), child->StyleRef(), kForRows, auto_repeat_rows);
-    GridSpan column_positions =
-        GridPositionsResolver::ResolveGridPositionsFromStyle(
-            StyleRef(), child->StyleRef(), kForColumns, auto_repeat_columns);
-    grid.SetGridItemArea(*child, GridArea(row_positions, column_positions));
-
-    // |positions| is 0 if we need to run the auto-placement algorithm.
-    if (!row_positions.IsIndefinite()) {
-      explicit_row_start = std::max<int>(
-          explicit_row_start, -row_positions.UntranslatedStartLine());
-      maximum_row_index =
-          std::max<int>(maximum_row_index, row_positions.UntranslatedEndLine());
-    } else {
-      // Grow the grid for items with a definite row span, getting the largest
-      // such span.
-      wtf_size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
-          child->StyleRef(), kForRows);
-      maximum_row_index = std::max(maximum_row_index, span_size);
-    }
-
-    if (!column_positions.IsIndefinite()) {
-      explicit_column_start = std::max<int>(
-          explicit_column_start, -column_positions.UntranslatedStartLine());
-      maximum_column_index = std::max<int>(
-          maximum_column_index, column_positions.UntranslatedEndLine());
-    } else {
-      // Grow the grid for items with a definite column span, getting the
-      // largest such span.
-      wtf_size_t span_size = GridPositionsResolver::SpanSizeForAutoPlacedItem(
-          child->StyleRef(), kForColumns);
-      maximum_column_index = std::max(maximum_column_index, span_size);
-    }
-  }
-
-  grid.SetExplicitGridStart(explicit_row_start, explicit_column_start);
-  grid.EnsureGridSize(maximum_row_index + explicit_row_start,
-                      maximum_column_index + explicit_column_start);
-}
-
-std::unique_ptr<GridArea>
-LayoutGrid::CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
-    const Grid& grid,
-    const LayoutBox& grid_item,
-    GridTrackSizingDirection specified_direction,
-    const GridSpan& specified_positions) const {
-  NOT_DESTROYED();
-  GridTrackSizingDirection cross_direction =
-      specified_direction == kForColumns ? kForRows : kForColumns;
-  const wtf_size_t end_of_cross_direction = grid.NumTracks(cross_direction);
-  wtf_size_t cross_direction_span_size =
-      GridPositionsResolver::SpanSizeForAutoPlacedItem(grid_item.StyleRef(),
-                                                       cross_direction);
-  GridSpan cross_direction_positions = GridSpan::TranslatedDefiniteGridSpan(
-      end_of_cross_direction,
-      end_of_cross_direction + cross_direction_span_size);
-  return std::make_unique<GridArea>(
-      specified_direction == kForColumns ? cross_direction_positions
-                                         : specified_positions,
-      specified_direction == kForColumns ? specified_positions
-                                         : cross_direction_positions);
-}
-
-void LayoutGrid::PlaceSpecifiedMajorAxisItemsOnGrid(
-    Grid& grid,
-    const HeapVector<Member<LayoutBox>>& auto_grid_items) const {
-  NOT_DESTROYED();
-  bool is_for_columns = AutoPlacementMajorAxisDirection() == kForColumns;
-  bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
-
-  // Mapping between the major axis tracks (rows or columns) and the last
-  // auto-placed item's position inserted on that track. This is needed to
-  // implement "sparse" packing for items locked to a given track.
-  // See https://drafts.csswg.org/css-grid/#auto-placement-algo
-  HashMap<unsigned, unsigned, IntWithZeroKeyHashTraits<unsigned>>
-      minor_axis_cursors;
-
-  for (const auto& auto_grid_item : auto_grid_items) {
-    GridSpan major_axis_positions =
-        grid.GridItemSpan(*auto_grid_item, AutoPlacementMajorAxisDirection());
-    DCHECK(major_axis_positions.IsTranslatedDefinite());
-    DCHECK(
-        !grid.GridItemSpan(*auto_grid_item, AutoPlacementMinorAxisDirection())
-             .IsTranslatedDefinite());
-    wtf_size_t minor_axis_span_size =
-        GridPositionsResolver::SpanSizeForAutoPlacedItem(
-            auto_grid_item->StyleRef(), AutoPlacementMinorAxisDirection());
-    unsigned major_axis_initial_position = major_axis_positions.StartLine();
-    auto minor_access_cursor = 0;
-    if (!is_grid_auto_flow_dense) {
-      auto it = minor_axis_cursors.find(major_axis_initial_position);
-      if (it != minor_axis_cursors.end())
-        minor_access_cursor = it->value;
-    }
-    auto* iterator = grid.CreateIterator(AutoPlacementMajorAxisDirection(),
-                                         major_axis_positions.StartLine(),
-                                         minor_access_cursor);
-    std::unique_ptr<GridArea> empty_grid_area = iterator->NextEmptyGridArea(
-        major_axis_positions.IntegerSpan(), minor_axis_span_size);
-    DCHECK(empty_grid_area);
-
-    grid.Insert(*auto_grid_item, *empty_grid_area);
-
-    if (!is_grid_auto_flow_dense)
-      minor_axis_cursors.Set(major_axis_initial_position,
-                             is_for_columns
-                                 ? empty_grid_area->rows.StartLine()
-                                 : empty_grid_area->columns.StartLine());
-  }
-}
-
-void LayoutGrid::PlaceAutoMajorAxisItemsOnGrid(
-    Grid& grid,
-    const HeapVector<Member<LayoutBox>>& auto_grid_items) const {
-  NOT_DESTROYED();
-  std::pair<wtf_size_t, wtf_size_t> auto_placement_cursor =
-      std::make_pair(0, 0);
-  bool is_grid_auto_flow_dense = StyleRef().IsGridAutoFlowAlgorithmDense();
-
-  for (const auto& auto_grid_item : auto_grid_items) {
-    PlaceAutoMajorAxisItemOnGrid(grid, *auto_grid_item, auto_placement_cursor);
-
-    // If grid-auto-flow is dense, reset auto-placement cursor.
-    if (is_grid_auto_flow_dense) {
-      auto_placement_cursor.first = 0;
-      auto_placement_cursor.second = 0;
-    }
-  }
-}
-
-void LayoutGrid::PlaceAutoMajorAxisItemOnGrid(
-    Grid& grid,
-    LayoutBox& grid_item,
-    std::pair<wtf_size_t, wtf_size_t>& auto_placement_cursor) const {
-  NOT_DESTROYED();
-  GridSpan minor_axis_positions =
-      grid.GridItemSpan(grid_item, AutoPlacementMinorAxisDirection());
-  DCHECK(!grid.GridItemSpan(grid_item, AutoPlacementMajorAxisDirection())
-              .IsTranslatedDefinite());
-  wtf_size_t major_axis_span_size =
-      GridPositionsResolver::SpanSizeForAutoPlacedItem(
-          grid_item.StyleRef(), AutoPlacementMajorAxisDirection());
-
-  const wtf_size_t end_of_major_axis =
-      grid.NumTracks(AutoPlacementMajorAxisDirection());
-  wtf_size_t major_axis_auto_placement_cursor =
-      AutoPlacementMajorAxisDirection() == kForColumns
-          ? auto_placement_cursor.second
-          : auto_placement_cursor.first;
-  wtf_size_t minor_axis_auto_placement_cursor =
-      AutoPlacementMajorAxisDirection() == kForColumns
-          ? auto_placement_cursor.first
-          : auto_placement_cursor.second;
-
-  std::unique_ptr<GridArea> empty_grid_area;
-  if (minor_axis_positions.IsTranslatedDefinite()) {
-    // Move to the next track in major axis if initial position in minor axis is
-    // before auto-placement cursor.
-    if (minor_axis_positions.StartLine() < minor_axis_auto_placement_cursor)
-      major_axis_auto_placement_cursor++;
-
-    if (major_axis_auto_placement_cursor < end_of_major_axis) {
-      auto* iterator = grid.CreateIterator(AutoPlacementMinorAxisDirection(),
-                                           minor_axis_positions.StartLine(),
-                                           major_axis_auto_placement_cursor);
-      empty_grid_area = iterator->NextEmptyGridArea(
-          minor_axis_positions.IntegerSpan(), major_axis_span_size);
-    }
-
-    if (!empty_grid_area) {
-      empty_grid_area = CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
-          grid, grid_item, AutoPlacementMinorAxisDirection(),
-          minor_axis_positions);
-    }
-  } else {
-    wtf_size_t minor_axis_span_size =
-        GridPositionsResolver::SpanSizeForAutoPlacedItem(
-            grid_item.StyleRef(), AutoPlacementMinorAxisDirection());
-
-    for (wtf_size_t major_axis_index = major_axis_auto_placement_cursor;
-         major_axis_index < end_of_major_axis; ++major_axis_index) {
-      auto* iterator = grid.CreateIterator(AutoPlacementMajorAxisDirection(),
-                                           major_axis_index,
-                                           minor_axis_auto_placement_cursor);
-      empty_grid_area = iterator->NextEmptyGridArea(major_axis_span_size,
-                                                    minor_axis_span_size);
-      DCHECK(empty_grid_area);
-
-      // Check that it fits in the minor axis direction, as we shouldn't grow
-      // in that direction here (it was already managed in
-      // populateExplicitGridAndOrderIterator()).
-      size_t minor_axis_final_position_index =
-          AutoPlacementMinorAxisDirection() == kForColumns
-              ? empty_grid_area->columns.EndLine()
-              : empty_grid_area->rows.EndLine();
-      const wtf_size_t end_of_minor_axis =
-          grid.NumTracks(AutoPlacementMinorAxisDirection());
-      if (minor_axis_final_position_index <= end_of_minor_axis)
-        break;
-
-      // Discard empty grid area as it does not fit in the minor axis
-      // direction. We don't need to create a new empty grid area yet as we
-      // might find a valid one in the next iteration.
-      empty_grid_area.reset();
-
-      // As we're moving to the next track in the major axis we should reset the
-      // auto-placement cursor in the minor axis.
-      minor_axis_auto_placement_cursor = 0;
-    }
-
-    if (!empty_grid_area)
-      empty_grid_area = CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
-          grid, grid_item, AutoPlacementMinorAxisDirection(),
-          GridSpan::TranslatedDefiniteGridSpan(0, minor_axis_span_size));
-  }
-
-  grid.Insert(grid_item, *empty_grid_area);
-  // Move auto-placement cursor to the new position.
-  auto_placement_cursor.first = empty_grid_area->rows.StartLine();
-  auto_placement_cursor.second = empty_grid_area->columns.StartLine();
-}
-
-GridTrackSizingDirection LayoutGrid::AutoPlacementMajorAxisDirection() const {
-  NOT_DESTROYED();
-  return StyleRef().IsGridAutoFlowDirectionColumn() ? kForColumns : kForRows;
-}
-
-GridTrackSizingDirection LayoutGrid::AutoPlacementMinorAxisDirection() const {
-  NOT_DESTROYED();
-  return StyleRef().IsGridAutoFlowDirectionColumn() ? kForRows : kForColumns;
-}
-
-void LayoutGrid::DirtyGrid() {
-  NOT_DESTROYED();
-  if (grid_->NeedsItemsPlacement())
-    return;
-
-  grid_->SetNeedsItemsPlacement(true);
-}
-
-Vector<LayoutUnit, 1> LayoutGrid::TrackSizesForComputedStyle(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  bool is_row_axis = direction == kForColumns;
-  auto& positions = is_row_axis ? column_positions_ : row_positions_;
-  wtf_size_t num_positions = positions.size();
-  LayoutUnit offset_between_tracks =
-      is_row_axis ? offset_between_columns_.distribution_offset
-                  : offset_between_rows_.distribution_offset;
-
-  Vector<LayoutUnit, 1> tracks;
-  if (num_positions < 2)
-    return tracks;
-
-  DCHECK(!grid_->NeedsItemsPlacement());
-  bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
-  LayoutUnit gap = !has_collapsed_tracks ? GridGap(direction) : LayoutUnit();
-  tracks.reserve(num_positions - 1);
-  for (wtf_size_t i = 0; i < num_positions - 2; ++i)
-    tracks.push_back(positions[i + 1] - positions[i] - offset_between_tracks -
-                     gap);
-  tracks.push_back(positions[num_positions - 1] - positions[num_positions - 2]);
-
-  if (!has_collapsed_tracks)
-    return tracks;
-
-  wtf_size_t remaining_empty_tracks =
-      grid_->AutoRepeatEmptyTracks(direction)->size();
-  wtf_size_t last_line = tracks.size();
-  gap = GridGap(direction);
-  for (wtf_size_t i = 1; i < last_line; ++i) {
-    if (grid_->IsEmptyAutoRepeatTrack(direction, i - 1)) {
-      --remaining_empty_tracks;
-    } else {
-      // Remove the gap between consecutive non empty tracks. Remove it also
-      // just once for an arbitrary number of empty tracks between two non empty
-      // ones.
-      bool all_remaining_tracks_are_empty =
-          remaining_empty_tracks == (last_line - i);
-      if (!all_remaining_tracks_are_empty ||
-          !grid_->IsEmptyAutoRepeatTrack(direction, i))
-        tracks[i - 1] -= gap;
-    }
-  }
-
-  return tracks;
-}
-
-const StyleContentAlignmentData& LayoutGrid::ContentAlignmentNormalBehavior() {
-  static const StyleContentAlignmentData kNormalBehavior = {
-      ContentPosition::kNormal, ContentDistributionType::kStretch};
-  return kNormalBehavior;
-}
-
-static bool OverrideSizeChanged(const LayoutBox& child,
-                                GridTrackSizingDirection direction,
-                                LayoutSize size) {
-  if (direction == kForColumns) {
-    return !child.HasOverrideContainingBlockContentLogicalWidth() ||
-           child.OverrideContainingBlockContentLogicalWidth() != size.Width();
-  }
-  return !child.HasOverrideContainingBlockContentLogicalHeight() ||
-         child.OverrideContainingBlockContentLogicalHeight() != size.Height();
-}
-
-static bool HasRelativeBlockAxisSize(const LayoutGrid& grid,
-                                     const LayoutBox& child) {
-  return GridLayoutUtils::IsOrthogonalChild(grid, child)
-             ? child.HasRelativeLogicalWidth() ||
-                   child.StyleRef().LogicalWidth().IsAuto()
-             : child.HasRelativeLogicalHeight();
-}
-
-void LayoutGrid::UpdateGridAreaLogicalSize(
-    LayoutBox& child,
-    LayoutSize grid_area_logical_size) const {
-  NOT_DESTROYED();
-  // Because the grid area cannot be styled, we don't need to adjust
-  // the grid breadth to account for 'box-sizing'.
-  bool grid_area_width_changed =
-      OverrideSizeChanged(child, kForColumns, grid_area_logical_size);
-  bool grid_area_height_changed =
-      OverrideSizeChanged(child, kForRows, grid_area_logical_size);
-  if (grid_area_width_changed ||
-      (grid_area_height_changed && HasRelativeBlockAxisSize(*this, child))) {
-    child.SetSelfNeedsLayoutForAvailableSpace(true);
-  }
-
-  child.SetOverrideContainingBlockContentLogicalWidth(
-      grid_area_logical_size.Width());
-  child.SetOverrideContainingBlockContentLogicalHeight(
-      grid_area_logical_size.Height());
-}
-
-void LayoutGrid::LayoutGridItems() {
-  NOT_DESTROYED();
-  if (ChildLayoutBlockedByDisplayLock())
-    return;
-
-  PopulateGridPositionsForDirection(kForColumns);
-  PopulateGridPositionsForDirection(kForRows);
-
-  for (LayoutBox* child = FirstChildBox(); child;
-       child = child->NextSiblingBox()) {
-    if (child->IsOutOfFlowPositioned()) {
-      PrepareChildForPositionedLayout(*child);
-      continue;
-    }
-
-    // Setting the definite grid area's sizes. It may imply that the
-    // item must perform a layout if its area differs from the one
-    // used during the track sizing algorithm.
-    UpdateGridAreaLogicalSize(
-        *child, LayoutSize(GridAreaBreadthForChildIncludingAlignmentOffsets(
-                               *child, kForColumns),
-                           GridAreaBreadthForChildIncludingAlignmentOffsets(
-                               *child, kForRows)));
-
-    // Stretching logic might force a child layout, so we need to run it before
-    // the layoutIfNeeded call to avoid unnecessary relayouts. This might imply
-    // that child margins, needed to correctly determine the available space
-    // before stretching, are not set yet.
-    ApplyStretchAlignmentToChildIfNeeded(*child);
-
-    child->LayoutIfNeeded();
-
-    // We need pending layouts to be done in order to compute auto-margins
-    // properly.
-    UpdateAutoMarginsInColumnAxisIfNeeded(*child);
-    UpdateAutoMarginsInRowAxisIfNeeded(*child);
-
-#if DCHECK_IS_ON()
-    const GridArea& area = grid_->GridItemArea(*child);
-    DCHECK_LT(area.columns.StartLine(),
-              track_sizing_algorithm_->Tracks(kForColumns).size());
-    DCHECK_LT(area.rows.StartLine(),
-              track_sizing_algorithm_->Tracks(kForRows).size());
-#endif
-    SetLogicalPositionForChild(*child);
-  }
-}
-
-void LayoutGrid::PrepareChildForPositionedLayout(LayoutBox& child) {
-  NOT_DESTROYED();
-  DCHECK(child.IsOutOfFlowPositioned());
-  child.ContainingBlock()->InsertPositionedObject(&child);
-
-  PaintLayer* child_layer = child.Layer();
-  // Static position of a positioned child should use the content-box
-  // (https://drafts.csswg.org/css-grid/#static-position).
-  child_layer->SetStaticInlinePosition(BorderAndPaddingStart());
-  child_layer->SetStaticBlockPosition(BorderAndPaddingBefore());
-}
-
-bool LayoutGrid::HasStaticPositionForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  return direction == kForColumns ? child.StyleRef().HasStaticInlinePosition(
-                                        IsHorizontalWritingMode())
-                                  : child.StyleRef().HasStaticBlockPosition(
-                                        IsHorizontalWritingMode());
-}
-
-void LayoutGrid::LayoutPositionedObjects(bool relayout_children,
-                                         PositionedLayoutBehavior info) {
-  NOT_DESTROYED();
-  if (ChildLayoutBlockedByDisplayLock())
-    return;
-
-  column_of_positioned_item_.clear();
-  row_of_positioned_item_.clear();
-
-  TrackedLayoutBoxLinkedHashSet* positioned_descendants = PositionedObjects();
-  if (!positioned_descendants)
-    return;
-
-  // Cannot use |const auto&| here and need to get a raw pointer in advance
-  // because |positioned_descendants| may be modified in the loop, triggering
-  // reallocation, and making |child| a dangling pointer.
-  for (LayoutBox* child : *positioned_descendants) {
-    LayoutUnit column_breadth =
-        GridAreaBreadthForOutOfFlowChild(*child, kForColumns);
-    LayoutUnit row_breadth = GridAreaBreadthForOutOfFlowChild(*child, kForRows);
-
-    child->SetOverrideContainingBlockContentLogicalWidth(column_breadth);
-    child->SetOverrideContainingBlockContentLogicalHeight(row_breadth);
-
-    // Mark for layout as we're resetting the position before and we relay in
-    // generic layout logic for positioned items in order to get the offsets
-    // properly resolved.
-    child->SetNeedsLayout(layout_invalidation_reason::kGridChanged,
-                          kMarkOnlyThis);
-
-    LayoutPositionedObject(child, relayout_children, info);
-
-    SetLogicalOffsetForChild(*child, kForColumns);
-    SetLogicalOffsetForChild(*child, kForRows);
-  }
-}
-
-LayoutUnit LayoutGrid::GridAreaBreadthForChildIncludingAlignmentOffsets(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  // We need the cached value when available because Content Distribution
-  // alignment properties may have some influence in the final grid area
-  // breadth.
-  const Vector<GridTrack>& tracks = track_sizing_algorithm_->Tracks(direction);
-  const GridSpan& span =
-      track_sizing_algorithm_->GetGrid().GridItemSpan(child, direction);
-  const Vector<LayoutUnit>& line_positions =
-      (direction == kForColumns) ? column_positions_ : row_positions_;
-  LayoutUnit initial_track_position = line_positions[span.StartLine()];
-  LayoutUnit final_track_position = line_positions[span.EndLine() - 1];
-  // Track Positions vector stores the 'start' grid line of each track, so we
-  // have to add last track's baseSize.
-  return final_track_position - initial_track_position +
-         tracks[span.EndLine() - 1].BaseSize();
-}
-
-void LayoutGrid::PopulateGridPositionsForDirection(
-    GridTrackSizingDirection direction) {
-  NOT_DESTROYED();
-  // Since we add alignment offsets and track gutters, grid lines are not always
-  // adjacent. Hence we will have to assume from now on that we just store
-  // positions of the initial grid lines of each track, except the last one,
-  // which is the only one considered as a final grid line of a track.
-
-  // The grid container's frame elements (border, padding and <content-position>
-  // offset) are sensible to the inline-axis flow direction. However, column
-  // lines positions are 'direction' unaware. This simplification allows us to
-  // use the same indexes to identify the columns independently on the
-  // inline-axis direction.
-  bool is_row_axis = direction == kForColumns;
-  auto& tracks = track_sizing_algorithm_->Tracks(direction);
-  wtf_size_t number_of_tracks = tracks.size();
-  wtf_size_t number_of_lines = number_of_tracks + 1;
-  wtf_size_t last_line = number_of_lines - 1;
-  bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
-  wtf_size_t number_of_collapsed_tracks =
-      has_collapsed_tracks ? grid_->AutoRepeatEmptyTracks(direction)->size()
-                           : 0;
-  const auto& offset =
-      direction == kForColumns ? offset_between_columns_ : offset_between_rows_;
-  auto& positions = is_row_axis ? column_positions_ : row_positions_;
-  positions.resize(number_of_lines);
-
-  auto border_and_padding =
-      is_row_axis ? BorderAndPaddingLogicalLeft() : BorderAndPaddingBefore();
-  if (is_row_axis) {
-    if (StyleRef().IsHorizontalWritingMode() &&
-        !StyleRef().IsLeftToRightDirection())
-      border_and_padding += ComputeLogicalScrollbars().InlineSum();
-  } else {
-    if (StyleRef().GetWritingMode() == WritingMode::kVerticalRl)
-      border_and_padding += ComputeLogicalScrollbars().BlockSum();
-  }
-
-  positions[0] = border_and_padding + offset.position_offset;
-  if (number_of_lines > 1) {
-    // If we have collapsed tracks we just ignore gaps here and add them later
-    // as we might not compute the gap between two consecutive tracks without
-    // examining the surrounding ones.
-    LayoutUnit gap = !has_collapsed_tracks ? GridGap(direction) : LayoutUnit();
-    wtf_size_t next_to_last_line = number_of_lines - 2;
-    for (wtf_size_t i = 0; i < next_to_last_line; ++i)
-      positions[i + 1] = positions[i] + offset.distribution_offset +
-                         tracks[i].BaseSize() + gap;
-    positions[last_line] =
-        positions[next_to_last_line] + tracks[next_to_last_line].BaseSize();
-
-    // Adjust collapsed gaps. Collapsed tracks cause the surrounding gutters to
-    // collapse (they coincide exactly) except on the edges of the grid where
-    // they become 0.
-    if (has_collapsed_tracks) {
-      gap = GridGap(direction);
-      wtf_size_t remaining_empty_tracks = number_of_collapsed_tracks;
-      LayoutUnit offset_accumulator;
-      LayoutUnit gap_accumulator;
-      for (wtf_size_t i = 1; i < last_line; ++i) {
-        if (grid_->IsEmptyAutoRepeatTrack(direction, i - 1)) {
-          --remaining_empty_tracks;
-          offset_accumulator += offset.distribution_offset;
-        } else {
-          // Add gap between consecutive non empty tracks. Add it also just once
-          // for an arbitrary number of empty tracks between two non empty ones.
-          bool all_remaining_tracks_are_empty =
-              remaining_empty_tracks == (last_line - i);
-          if (!all_remaining_tracks_are_empty ||
-              !grid_->IsEmptyAutoRepeatTrack(direction, i))
-            gap_accumulator += gap;
-        }
-        positions[i] += gap_accumulator - offset_accumulator;
-      }
-      positions[last_line] += gap_accumulator - offset_accumulator;
-    }
-  }
-}
-
-static LayoutUnit ComputeOverflowAlignmentOffset(OverflowAlignment overflow,
-                                                 LayoutUnit track_size,
-                                                 LayoutUnit child_size) {
-  LayoutUnit offset = track_size - child_size;
-  switch (overflow) {
-    case OverflowAlignment::kSafe:
-      // If overflow is 'safe', we have to make sure we don't overflow the
-      // 'start' edge (potentially cause some data loss as the overflow is
-      // unreachable).
-      return offset.ClampNegativeToZero();
-    case OverflowAlignment::kUnsafe:
-    case OverflowAlignment::kDefault:
-      // If we overflow our alignment container and overflow is 'true'
-      // (default), we ignore the overflow and just return the value regardless
-      // (which may cause data loss as we overflow the 'start' edge).
-      return offset;
-  }
-
-  NOTREACHED();
-  return LayoutUnit();
-}
-
-LayoutUnit LayoutGrid::AvailableAlignmentSpaceForChildBeforeStretching(
-    LayoutUnit grid_area_breadth_for_child,
-    const LayoutBox& child) const {
-  NOT_DESTROYED();
-  // Because we want to avoid multiple layouts, stretching logic might be
-  // performed before children are laid out, so we can't use the child cached
-  // values. Hence, we may need to compute margins in order to determine the
-  // available height before stretching.
-  return grid_area_breadth_for_child -
-         GridLayoutUtils::MarginLogicalHeightForChild(*this, child);
-}
-
-StyleSelfAlignmentData LayoutGrid::AlignSelfForChild(
-    const LayoutBox& child,
-    const ComputedStyle* style) const {
-  NOT_DESTROYED();
-  if (!style)
-    style = Style();
-  return child.StyleRef().ResolvedAlignSelf(SelfAlignmentNormalBehavior(&child),
-                                            style);
-}
-
-StyleSelfAlignmentData LayoutGrid::JustifySelfForChild(
-    const LayoutBox& child,
-    const ComputedStyle* style) const {
-  NOT_DESTROYED();
-  if (!style)
-    style = Style();
-  return child.StyleRef().ResolvedJustifySelf(
-      SelfAlignmentNormalBehavior(&child), style);
-}
-
-bool LayoutGrid::AspectRatioPrefersInline(const LayoutBox& child,
-                                          bool block_flow_is_column_axis) {
-  if (child.StyleRef().AspectRatio().IsAuto())
-    return false;
-  // Not using AlignSelfForChild/JustifySelfForChild here since we are only
-  // interested in explicit stretch, not normal behavior.
-  bool has_explicit_inline_stretch =
-      child.StyleRef()
-          .ResolvedJustifySelf(ItemPosition::kNormal, Style())
-          .GetPosition() == ItemPosition::kStretch;
-  bool has_explicit_block_stretch =
-      child.StyleRef()
-          .ResolvedAlignSelf(ItemPosition::kNormal, Style())
-          .GetPosition() == ItemPosition::kStretch;
-  if (!block_flow_is_column_axis)
-    std::swap(has_explicit_inline_stretch, has_explicit_block_stretch);
-  if (has_explicit_inline_stretch && has_explicit_block_stretch)
-    return false;
-  if (has_explicit_inline_stretch)
-    return true;
-  return !has_explicit_block_stretch;
-}
-
-// FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to
-// LayoutBox.
-void LayoutGrid::ApplyStretchAlignmentToChildIfNeeded(LayoutBox& child) {
-  NOT_DESTROYED();
-  GridTrackSizingDirection child_block_direction =
-      GridLayoutUtils::FlowAwareDirectionForChild(*this, child, kForRows);
-  bool block_flow_is_column_axis = child_block_direction == kForRows;
-  bool allowed_to_stretch_child_block_size =
-      block_flow_is_column_axis ? AllowedToStretchChildAlongColumnAxis(child)
-                                : AllowedToStretchChildAlongRowAxis(child);
-  if (allowed_to_stretch_child_block_size &&
-      !AspectRatioPrefersInline(child, block_flow_is_column_axis)) {
-    LayoutUnit stretched_logical_height =
-        AvailableAlignmentSpaceForChildBeforeStretching(
-            OverrideContainingBlockContentSizeForChild(child,
-                                                       child_block_direction),
-            child);
-    LayoutUnit desired_logical_height = child.ConstrainLogicalHeightByMinMax(
-        stretched_logical_height, LayoutUnit(-1));
-    child.SetOverrideLogicalHeight(desired_logical_height);
-
-    // Checking the logical-height of a child isn't enough. Setting an override
-    // logical-height changes the definiteness, resulting in percentages to
-    // resolve differently.
-    // NG nodes have enough information to check for this case, and only layout
-    // if needed.
-    //
-    // TODO (lajava): Can avoid laying out here in some cases.
-    // See https://webkit.org/b/87905.
-    if (desired_logical_height != child.LogicalHeight() ||
-        child.MaybeHasPercentHeightDescendant()) {
-      // Never mess around with the logical-height of any NG children.
-      if (!child.IsLayoutNGObject())
-        child.SetLogicalHeight(LayoutUnit());
-      child.SetSelfNeedsLayoutForAvailableSpace(true);
-    }
-  }
-}
-
-bool LayoutGrid::HasAutoSizeInColumnAxis(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  if (!child.StyleRef().AspectRatio().IsAuto()) {
-    if (IsHorizontalWritingMode() == child.IsHorizontalWritingMode() &&
-        child.StyleRef().AlignSelf().GetPosition() != ItemPosition::kStretch) {
-      // If the used inline size is non-auto, we do have a non auto block size
-      // (column axis size) because of the aspect ratio.
-      if (!child.StyleRef().LogicalWidth().IsAuto())
-        return false;
-    } else if (child.StyleRef().JustifySelf().GetPosition() !=
-               ItemPosition::kStretch) {
-      const Length& logical_height = child.StyleRef().LogicalHeight();
-      if (logical_height.IsFixed() ||
-          (logical_height.IsPercentOrCalc() &&
-           child.ComputePercentageLogicalHeight(Length::Percent(0)) !=
-               kIndefiniteSize)) {
-        return false;
-      }
-    }
-  }
-  return IsHorizontalWritingMode() ? child.StyleRef().Height().IsAuto()
-                                   : child.StyleRef().Width().IsAuto();
-}
-
-bool LayoutGrid::HasAutoSizeInRowAxis(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  if (!child.StyleRef().AspectRatio().IsAuto()) {
-    if (IsHorizontalWritingMode() == child.IsHorizontalWritingMode() &&
-        child.StyleRef().JustifySelf().GetPosition() !=
-            ItemPosition::kStretch) {
-      // If the used block size is non-auto, we do have a non auto inline size
-      // (row axis size) because of the aspect ratio.
-      const Length& logical_height = child.StyleRef().LogicalHeight();
-      if (logical_height.IsFixed() ||
-          (logical_height.IsPercentOrCalc() &&
-           child.ComputePercentageLogicalHeight(Length::Percent(0)) !=
-               kIndefiniteSize)) {
-        return false;
-      }
-    } else if (child.StyleRef().AlignSelf().GetPosition() !=
-               ItemPosition::kStretch) {
-      if (!child.StyleRef().LogicalWidth().IsAuto())
-        return false;
-    }
-  }
-  return IsHorizontalWritingMode() ? child.StyleRef().Width().IsAuto()
-                                   : child.StyleRef().Height().IsAuto();
-}
-
-// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
-// moved to LayoutBox.
-bool LayoutGrid::HasAutoMarginsInColumnAxis(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  if (IsHorizontalWritingMode())
-    return child.StyleRef().MarginTop().IsAuto() ||
-           child.StyleRef().MarginBottom().IsAuto();
-  return child.StyleRef().MarginLeft().IsAuto() ||
-         child.StyleRef().MarginRight().IsAuto();
-}
-
-// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
-// moved to LayoutBox.
-bool LayoutGrid::HasAutoMarginsInRowAxis(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  if (IsHorizontalWritingMode())
-    return child.StyleRef().MarginLeft().IsAuto() ||
-           child.StyleRef().MarginRight().IsAuto();
-  return child.StyleRef().MarginTop().IsAuto() ||
-         child.StyleRef().MarginBottom().IsAuto();
-}
-
-// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
-// moved to LayoutBox.
-DISABLE_CFI_PERF
-void LayoutGrid::UpdateAutoMarginsInRowAxisIfNeeded(LayoutBox& child) {
-  NOT_DESTROYED();
-  DCHECK(!child.IsOutOfFlowPositioned());
-
-  const Length& margin_start = child.StyleRef().MarginStartUsing(StyleRef());
-  const Length& margin_end = child.StyleRef().MarginEndUsing(StyleRef());
-  LayoutUnit margin_logical_width;
-  // We should only consider computed margins if their specified value isn't
-  // 'auto', since such computed value may come from a previous layout and may
-  // be incorrect now.
-  if (!margin_start.IsAuto())
-    margin_logical_width += child.MarginStart();
-  if (!margin_end.IsAuto())
-    margin_logical_width += child.MarginEnd();
-  LayoutUnit available_alignment_space =
-      child.OverrideContainingBlockContentLogicalWidth() -
-      child.LogicalWidth() - margin_logical_width;
-  if (available_alignment_space <= 0)
-    return;
-
-  if (margin_start.IsAuto() && margin_end.IsAuto()) {
-    child.SetMarginStart(available_alignment_space / 2, Style());
-    child.SetMarginEnd(available_alignment_space / 2, Style());
-  } else if (margin_start.IsAuto()) {
-    child.SetMarginStart(available_alignment_space, Style());
-  } else if (margin_end.IsAuto()) {
-    child.SetMarginEnd(available_alignment_space, Style());
-  }
-}
-
-// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it should be
-// moved to LayoutBox.
-DISABLE_CFI_PERF
-void LayoutGrid::UpdateAutoMarginsInColumnAxisIfNeeded(LayoutBox& child) {
-  NOT_DESTROYED();
-  DCHECK(!child.IsOutOfFlowPositioned());
-
-  const Length& margin_before = child.StyleRef().MarginBeforeUsing(StyleRef());
-  const Length& margin_after = child.StyleRef().MarginAfterUsing(StyleRef());
-  LayoutUnit margin_logical_height;
-  // We should only consider computed margins if their specified value isn't
-  // 'auto', since such computed value may come from a previous layout and may
-  // be incorrect now.
-  if (!margin_before.IsAuto())
-    margin_logical_height += child.MarginBefore();
-  if (!margin_after.IsAuto())
-    margin_logical_height += child.MarginAfter();
-  LayoutUnit available_alignment_space =
-      child.OverrideContainingBlockContentLogicalHeight() -
-      child.LogicalHeight() - margin_logical_height;
-  if (available_alignment_space <= 0)
-    return;
-
-  if (margin_before.IsAuto() && margin_after.IsAuto()) {
-    child.SetMarginBefore(available_alignment_space / 2, Style());
-    child.SetMarginAfter(available_alignment_space / 2, Style());
-  } else if (margin_before.IsAuto()) {
-    child.SetMarginBefore(available_alignment_space, Style());
-  } else if (margin_after.IsAuto()) {
-    child.SetMarginAfter(available_alignment_space, Style());
-  }
-}
-
-// TODO(lajava): This logic is shared by LayoutFlexibleBox, so it might be
-// refactored somehow.
-LayoutUnit LayoutGrid::SynthesizedBaselineFromBorderBox(
-    const LayoutBox& box,
-    LineDirectionMode direction) {
-  return direction == kHorizontalLine ? box.Size().Height()
-                                      : box.Size().Width();
-}
-
-LayoutUnit LayoutGrid::BaselinePosition(FontBaseline,
-                                        bool,
-                                        LineDirectionMode direction,
-                                        LinePositionMode mode) const {
-  NOT_DESTROYED();
-  DCHECK_EQ(mode, kPositionOnContainingLine);
-  LayoutUnit baseline = FirstLineBoxBaseline();
-  // We take border-box's bottom if no valid baseline.
-  if (baseline == -1) {
-    return SynthesizedBaselineFromBorderBox(*this, direction) +
-           MarginLogicalHeight();
-  }
-
-  return baseline + BeforeMarginInLineDirection(direction);
-}
-
-LayoutUnit LayoutGrid::FirstLineBoxBaseline() const {
-  NOT_DESTROYED();
-  if (IsWritingModeRoot() || !grid_->HasGridItems() ||
-      ShouldApplyLayoutContainment())
-    return LayoutUnit(-1);
-  const LayoutBox* baseline_child = nullptr;
-  const LayoutBox* first_child = nullptr;
-  bool is_baseline_aligned = false;
-  // Finding the first grid item in grid order.
-  for (wtf_size_t column = 0;
-       !is_baseline_aligned && column < grid_->NumTracks(kForColumns);
-       column++) {
-    const GridItemList& cell = grid_->Cell(0, column);
-    for (wtf_size_t index = 0; index < cell.size(); index++) {
-      const LayoutBox* child = cell[index];
-      DCHECK(!child->IsOutOfFlowPositioned());
-      // If an item participates in baseline alignment, we select such item.
-      if (IsBaselineAlignmentForChild(*child, kGridColumnAxis)) {
-        // TODO (lajava): self-baseline and content-baseline alignment
-        // still not implemented.
-        baseline_child = child;
-        is_baseline_aligned = true;
-        break;
-      }
-      if (!baseline_child) {
-        // Use dom order for items in the same cell.
-        if (!first_child || (grid_->GridItemPaintOrder(*child) <
-                             grid_->GridItemPaintOrder(*first_child)))
-          first_child = child;
-      }
-    }
-    if (!baseline_child && first_child)
-      baseline_child = first_child;
-  }
-
-  if (!baseline_child)
-    return LayoutUnit(-1);
-
-  LayoutUnit baseline =
-      GridLayoutUtils::IsOrthogonalChild(*this, *baseline_child)
-          ? LayoutUnit(-1)
-          : baseline_child->FirstLineBoxBaseline();
-  // We take border-box's bottom if no valid baseline.
-  if (baseline == -1) {
-    // TODO (lajava): We should pass |direction| into
-    // firstLineBoxBaseline and stop bailing out if we're a writing
-    // mode root.  This would also fix some cases where the grid is
-    // orthogonal to its container.
-    LineDirectionMode direction =
-        IsHorizontalWritingMode() ? kHorizontalLine : kVerticalLine;
-    return SynthesizedBaselineFromBorderBox(*baseline_child, direction) +
-           LogicalTopForChild(*baseline_child);
-  }
-
-  return baseline + baseline_child->LogicalTop();
-}
-
-LayoutUnit LayoutGrid::InlineBlockBaseline(LineDirectionMode direction) const {
-  NOT_DESTROYED();
-  return FirstLineBoxBaseline();
-}
-
-bool LayoutGrid::IsBaselineAlignmentForChild(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  return IsBaselineAlignmentForChild(child, kGridRowAxis) ||
-         IsBaselineAlignmentForChild(child, kGridColumnAxis);
-}
-
-bool LayoutGrid::IsBaselineAlignmentForChild(const LayoutBox& child,
-                                             GridAxis baseline_axis) const {
-  NOT_DESTROYED();
-  if (child.IsOutOfFlowPositioned())
-    return false;
-  ItemPosition align =
-      SelfAlignmentForChild(baseline_axis, child).GetPosition();
-  bool has_auto_margins = baseline_axis == kGridColumnAxis
-                              ? HasAutoMarginsInColumnAxis(child)
-                              : HasAutoMarginsInRowAxis(child);
-  return IsBaselinePosition(align) && !has_auto_margins;
-}
-
-LayoutUnit LayoutGrid::ColumnAxisBaselineOffsetForChild(
-    const LayoutBox& child) const {
-  NOT_DESTROYED();
-  return track_sizing_algorithm_->BaselineOffsetForChild(child,
-                                                         kGridColumnAxis);
-}
-
-LayoutUnit LayoutGrid::RowAxisBaselineOffsetForChild(
-    const LayoutBox& child) const {
-  NOT_DESTROYED();
-  return track_sizing_algorithm_->BaselineOffsetForChild(child, kGridRowAxis);
-}
-
-GridAxisPosition LayoutGrid::ColumnAxisPositionForChild(
-    const LayoutBox& child) const {
-  NOT_DESTROYED();
-  bool has_same_writing_mode =
-      child.StyleRef().GetWritingMode() == StyleRef().GetWritingMode();
-  bool child_is_ltr = child.StyleRef().IsLeftToRightDirection();
-  if (child.IsOutOfFlowPositioned() &&
-      !HasStaticPositionForChild(child, kForRows))
-    return kGridAxisStart;
-
-  switch (AlignSelfForChild(child).GetPosition()) {
-    case ItemPosition::kSelfStart:
-      // TODO (lajava): Should we implement this logic in a generic utility
-      // function?
-      // Aligns the alignment subject to be flush with the edge of the alignment
-      // container corresponding to the alignment subject's 'start' side in the
-      // column axis.
-      if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
-        // If orthogonal writing-modes, self-start will be based on the child's
-        // inline-axis direction (inline-start), because it's the one parallel
-        // to the column axis.
-        if (StyleRef().IsFlippedBlocksWritingMode())
-          return child_is_ltr ? kGridAxisEnd : kGridAxisStart;
-        return child_is_ltr ? kGridAxisStart : kGridAxisEnd;
-      }
-      // self-start is based on the child's block-flow direction. That's why we
-      // need to check against the grid container's block-flow direction.
-      return has_same_writing_mode ? kGridAxisStart : kGridAxisEnd;
-    case ItemPosition::kSelfEnd:
-      // TODO (lajava): Should we implement this logic in a generic utility
-      // function?
-      // Aligns the alignment subject to be flush with the edge of the alignment
-      // container corresponding to the alignment subject's 'end' side in the
-      // column axis.
-      if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
-        // If orthogonal writing-modes, self-end will be based on the child's
-        // inline-axis direction, (inline-end) because it's the one parallel to
-        // the column axis.
-        if (StyleRef().IsFlippedBlocksWritingMode())
-          return child_is_ltr ? kGridAxisStart : kGridAxisEnd;
-        return child_is_ltr ? kGridAxisEnd : kGridAxisStart;
-      }
-      // self-end is based on the child's block-flow direction. That's why we
-      // need to check against the grid container's block-flow direction.
-      return has_same_writing_mode ? kGridAxisEnd : kGridAxisStart;
-    case ItemPosition::kCenter:
-      return kGridAxisCenter;
-    // Only used in flex layout, otherwise equivalent to 'start'.
-    case ItemPosition::kFlexStart:
-    // Aligns the alignment subject to be flush with the alignment container's
-    // 'start' edge (block-start) in the column axis.
-    case ItemPosition::kStart:
-      return kGridAxisStart;
-    // Only used in flex layout, otherwise equivalent to 'end'.
-    case ItemPosition::kFlexEnd:
-    // Aligns the alignment subject to be flush with the alignment container's
-    // 'end' edge (block-end) in the column axis.
-    case ItemPosition::kEnd:
-      return kGridAxisEnd;
-    case ItemPosition::kStretch:
-      return kGridAxisStart;
-    case ItemPosition::kBaseline:
-    case ItemPosition::kLastBaseline:
-      return kGridAxisStart;
-    case ItemPosition::kLegacy:
-    case ItemPosition::kAuto:
-    case ItemPosition::kNormal:
-    case ItemPosition::kLeft:
-    case ItemPosition::kRight:
-      break;
-  }
-
-  NOTREACHED();
-  return kGridAxisStart;
-}
-
-GridAxisPosition LayoutGrid::RowAxisPositionForChild(
-    const LayoutBox& child) const {
-  NOT_DESTROYED();
-  bool has_same_direction =
-      child.StyleRef().Direction() == StyleRef().Direction();
-  bool grid_is_ltr = StyleRef().IsLeftToRightDirection();
-  if (child.IsOutOfFlowPositioned() &&
-      !HasStaticPositionForChild(child, kForColumns))
-    return kGridAxisStart;
-
-  switch (JustifySelfForChild(child).GetPosition()) {
-    case ItemPosition::kSelfStart:
-      // TODO (lajava): Should we implement this logic in a generic utility
-      // function?
-      // Aligns the alignment subject to be flush with the edge of the alignment
-      // container corresponding to the alignment subject's 'start' side in the
-      // row axis.
-      if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
-        // If orthogonal writing-modes, self-start will be based on the child's
-        // block-axis direction, because it's the one parallel to the row axis.
-        if (child.StyleRef().IsFlippedBlocksWritingMode())
-          return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
-        return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
-      }
-      // self-start is based on the child's inline-flow direction. That's why we
-      // need to check against the grid container's direction.
-      return has_same_direction ? kGridAxisStart : kGridAxisEnd;
-    case ItemPosition::kSelfEnd:
-      // TODO (lajava): Should we implement this logic in a generic utility
-      // function?
-      // Aligns the alignment subject to be flush with the edge of the alignment
-      // container corresponding to the alignment subject's 'end' side in the
-      // row axis.
-      if (GridLayoutUtils::IsOrthogonalChild(*this, child)) {
-        // If orthogonal writing-modes, self-end will be based on the child's
-        // block-axis direction, because it's the one parallel to the row axis.
-        if (child.StyleRef().IsFlippedBlocksWritingMode())
-          return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
-        return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
-      }
-      // self-end is based on the child's inline-flow direction. That's why we
-      // need to check against the grid container's direction.
-      return has_same_direction ? kGridAxisEnd : kGridAxisStart;
-    case ItemPosition::kLeft:
-      // Aligns the alignment subject to be flush with the alignment container's
-      // 'line-left' edge. We want the physical 'left' side, so we have to take
-      // account, container's inline-flow direction.
-      return grid_is_ltr ? kGridAxisStart : kGridAxisEnd;
-    case ItemPosition::kRight:
-      // Aligns the alignment subject to be flush with the alignment container's
-      // 'line-right' edge. We want the physical 'right' side, so we have to
-      // take account, container's inline-flow direction.
-      return grid_is_ltr ? kGridAxisEnd : kGridAxisStart;
-    case ItemPosition::kCenter:
-      return kGridAxisCenter;
-    // Only used in flex layout, otherwise equivalent to 'start'.
-    case ItemPosition::kFlexStart:
-    // Aligns the alignment subject to be flush with the alignment container's
-    // 'start' edge (inline-start) in the row axis.
-    case ItemPosition::kStart:
-      return kGridAxisStart;
-    // Only used in flex layout, otherwise equivalent to 'end'.
-    case ItemPosition::kFlexEnd:
-    // Aligns the alignment subject to be flush with the alignment container's
-    // 'end' edge (inline-end) in the row axis.
-    case ItemPosition::kEnd:
-      return kGridAxisEnd;
-    case ItemPosition::kStretch:
-      return kGridAxisStart;
-    case ItemPosition::kBaseline:
-    case ItemPosition::kLastBaseline:
-      return kGridAxisStart;
-    case ItemPosition::kLegacy:
-    case ItemPosition::kAuto:
-    case ItemPosition::kNormal:
-      break;
-  }
-
-  NOTREACHED();
-  return kGridAxisStart;
-}
-
-LayoutUnit LayoutGrid::ColumnAxisOffsetForChild(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  LayoutUnit start_of_row;
-  LayoutUnit end_of_row;
-  GridAreaPositionForChild(child, kForRows, start_of_row, end_of_row);
-  LayoutUnit start_position = start_of_row + MarginBeforeForChild(child);
-  if (HasAutoMarginsInColumnAxis(child))
-    return start_position;
-  GridAxisPosition axis_position = ColumnAxisPositionForChild(child);
-  switch (axis_position) {
-    case kGridAxisStart:
-      return start_position + ColumnAxisBaselineOffsetForChild(child);
-    case kGridAxisEnd:
-    case kGridAxisCenter: {
-      LayoutUnit column_axis_child_size =
-          GridLayoutUtils::IsOrthogonalChild(*this, child)
-              ? child.LogicalWidth() + child.MarginLogicalWidth()
-              : child.LogicalHeight() + child.MarginLogicalHeight();
-      OverflowAlignment overflow = AlignSelfForChild(child).Overflow();
-      LayoutUnit offset_from_start_position = ComputeOverflowAlignmentOffset(
-          overflow, end_of_row - start_of_row, column_axis_child_size);
-      return start_position + (axis_position == kGridAxisEnd
-                                   ? offset_from_start_position
-                                   : offset_from_start_position / 2);
-    }
-  }
-
-  NOTREACHED();
-  return LayoutUnit();
-}
-
-LayoutUnit LayoutGrid::RowAxisOffsetForChild(const LayoutBox& child) const {
-  NOT_DESTROYED();
-  LayoutUnit start_of_column;
-  LayoutUnit end_of_column;
-  GridAreaPositionForChild(child, kForColumns, start_of_column, end_of_column);
-  LayoutUnit start_position = start_of_column + MarginStartForChild(child);
-  if (HasAutoMarginsInRowAxis(child))
-    return start_position;
-  GridAxisPosition axis_position = RowAxisPositionForChild(child);
-  switch (axis_position) {
-    case kGridAxisStart:
-      return start_position + RowAxisBaselineOffsetForChild(child);
-    case kGridAxisEnd:
-    case kGridAxisCenter: {
-      LayoutUnit row_axis_child_size =
-          GridLayoutUtils::IsOrthogonalChild(*this, child)
-              ? child.LogicalHeight() + child.MarginLogicalHeight()
-              : child.LogicalWidth() + child.MarginLogicalWidth();
-      OverflowAlignment overflow = JustifySelfForChild(child).Overflow();
-      LayoutUnit offset_from_start_position = ComputeOverflowAlignmentOffset(
-          overflow, end_of_column - start_of_column, row_axis_child_size);
-      return start_position + (axis_position == kGridAxisEnd
-                                   ? offset_from_start_position
-                                   : offset_from_start_position / 2);
-    }
-  }
-
-  NOTREACHED();
-  return LayoutUnit();
-}
-
-LayoutUnit LayoutGrid::ResolveAutoStartGridPosition(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  if (direction == kForRows || StyleRef().IsLeftToRightDirection())
-    return LayoutUnit();
-
-  wtf_size_t last_line = NumTracks(kForColumns, *grid_);
-  ContentPosition position = StyleRef().ResolvedJustifyContentPosition(
-      ContentAlignmentNormalBehavior());
-  if (position == ContentPosition::kEnd)
-    return column_positions_[last_line] - ClientLogicalWidth();
-  if (position == ContentPosition::kStart ||
-      StyleRef().ResolvedJustifyContentDistribution(
-          ContentAlignmentNormalBehavior()) ==
-          ContentDistributionType::kStretch)
-    return column_positions_[0] - BorderAndPaddingLogicalLeft();
-  return LayoutUnit();
-}
-
-LayoutUnit LayoutGrid::ResolveAutoEndGridPosition(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  if (direction == kForRows)
-    return ClientLogicalHeight();
-  if (StyleRef().IsLeftToRightDirection())
-    return ClientLogicalWidth();
-
-  wtf_size_t last_line = NumTracks(kForColumns, *grid_);
-  ContentPosition position = StyleRef().ResolvedJustifyContentPosition(
-      ContentAlignmentNormalBehavior());
-  if (position == ContentPosition::kEnd)
-    return column_positions_[last_line];
-  if (position == ContentPosition::kStart ||
-      StyleRef().ResolvedJustifyContentDistribution(
-          ContentAlignmentNormalBehavior()) ==
-          ContentDistributionType::kStretch) {
-    return column_positions_[0] - BorderAndPaddingLogicalLeft() +
-           ClientLogicalWidth();
-  }
-  return ClientLogicalWidth();
-}
-
-LayoutUnit LayoutGrid::GridAreaBreadthForOutOfFlowChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) {
-  NOT_DESTROYED();
-  DCHECK(child.IsOutOfFlowPositioned());
-  bool is_row_axis = direction == kForColumns;
-  GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
-      StyleRef(), child.StyleRef(), direction,
-      AutoRepeatCountForDirection(direction));
-  if (span.IsIndefinite())
-    return is_row_axis ? ClientLogicalWidth() : ClientLogicalHeight();
-
-  wtf_size_t explicit_start = grid_->ExplicitGridStart(direction);
-  wtf_size_t start_line = span.UntranslatedStartLine() + explicit_start;
-  wtf_size_t end_line = span.UntranslatedEndLine() + explicit_start;
-  wtf_size_t last_line = NumTracks(direction, *grid_);
-  GridPosition start_position = direction == kForColumns
-                                    ? child.StyleRef().GridColumnStart()
-                                    : child.StyleRef().GridRowStart();
-  GridPosition end_position = direction == kForColumns
-                                  ? child.StyleRef().GridColumnEnd()
-                                  : child.StyleRef().GridRowEnd();
-
-  bool start_is_auto =
-      start_position.IsAuto() || start_line < 0 || start_line > last_line;
-  bool end_is_auto =
-      end_position.IsAuto() || end_line < 0 || end_line > last_line;
-
-  if (start_is_auto && end_is_auto)
-    return is_row_axis ? ClientLogicalWidth() : ClientLogicalHeight();
-
-  LayoutUnit start;
-  LayoutUnit end;
-  auto& positions = is_row_axis ? column_positions_ : row_positions_;
-  auto& line_of_positioned_item =
-      is_row_axis ? column_of_positioned_item_ : row_of_positioned_item_;
-  LayoutUnit border_edge = is_row_axis ? BorderLogicalLeft() : BorderBefore();
-  if (start_is_auto) {
-    start = ResolveAutoStartGridPosition(direction) + border_edge;
-  } else {
-    line_of_positioned_item.Set(&child, start_line);
-    start = positions[start_line];
-  }
-  if (end_is_auto) {
-    end = ResolveAutoEndGridPosition(direction) + border_edge;
-  } else {
-    end = positions[end_line];
-    // These vectors store line positions including gaps, but we shouldn't
-    // consider them for the edges of the grid.
-    if (end_line > 0 && end_line < last_line) {
-      DCHECK(!grid_->NeedsItemsPlacement());
-      // TODO(rego): It would be more efficient to call GridGap(direction) and
-      // pass that value to GuttersSize(), so we could avoid the call to
-      // available size if the gutter doesn't use percentages.
-      end -= GuttersSize(
-          *grid_, direction, end_line - 1, 2,
-          is_row_axis ? AvailableLogicalWidth() : ContentLogicalHeight());
-      end -= is_row_axis ? offset_between_columns_.distribution_offset
-                         : offset_between_rows_.distribution_offset;
-    }
-  }
-  // TODO (lajava): Is expectable that in some cases 'end' is smaller than
-  // 'start' ?
-  return std::max(end - start, LayoutUnit());
-}
-
-LayoutUnit LayoutGrid::LogicalOffsetForOutOfFlowChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction,
-    LayoutUnit track_breadth) const {
-  NOT_DESTROYED();
-  DCHECK(child.IsOutOfFlowPositioned());
-  if (HasStaticPositionForChild(child, direction))
-    return LayoutUnit();
-
-  bool is_row_axis = direction == kForColumns;
-  bool is_flowaware_row_axis = GridLayoutUtils::FlowAwareDirectionForChild(
-                                   *this, child, direction) == kForColumns;
-  LayoutUnit child_position =
-      is_flowaware_row_axis ? child.LogicalLeft() : child.LogicalTop();
-  LayoutUnit grid_border = is_row_axis ? BorderLogicalLeft() : BorderBefore();
-  LayoutUnit child_margin =
-      is_row_axis ? child.MarginLineLeft(Style()) : child.MarginBefore(Style());
-  LayoutUnit offset = child_position - grid_border - child_margin;
-  if (!is_row_axis || StyleRef().IsLeftToRightDirection())
-    return offset;
-
-  LayoutUnit child_breadth =
-      is_flowaware_row_axis
-          ? child.LogicalWidth() + child.MarginLogicalWidth()
-          : child.LogicalHeight() + child.MarginLogicalHeight();
-  return track_breadth - offset - child_breadth;
-}
-
-void LayoutGrid::GridAreaPositionForOutOfFlowChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction,
-    LayoutUnit& start,
-    LayoutUnit& end) const {
-  NOT_DESTROYED();
-  DCHECK(child.IsOutOfFlowPositioned());
-  DCHECK(GridLayoutUtils::HasOverrideContainingBlockContentSizeForChild(
-      child, direction));
-  LayoutUnit track_breadth =
-      GridLayoutUtils::OverrideContainingBlockContentSizeForChild(child,
-                                                                  direction);
-  bool is_row_axis = direction == kForColumns;
-  auto& line_of_positioned_item =
-      is_row_axis ? column_of_positioned_item_ : row_of_positioned_item_;
-  start = is_row_axis ? BorderLogicalLeft() : BorderBefore();
-  auto it = line_of_positioned_item.find(&child);
-  if (it != line_of_positioned_item.end() && it->value) {
-    auto& positions = is_row_axis ? column_positions_ : row_positions_;
-    start = positions[it->value.value()];
-  }
-  start += LogicalOffsetForOutOfFlowChild(child, direction, track_breadth);
-  end = start + track_breadth;
-}
-
-void LayoutGrid::GridAreaPositionForInFlowChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction,
-    LayoutUnit& start,
-    LayoutUnit& end) const {
-  NOT_DESTROYED();
-  DCHECK(!child.IsOutOfFlowPositioned());
-  const Grid& grid = track_sizing_algorithm_->GetGrid();
-  const GridSpan& span = grid.GridItemSpan(child, direction);
-  // TODO (lajava): This is a common pattern, why not defining a function like
-  // positions(direction) ?
-  auto& positions =
-      direction == kForColumns ? column_positions_ : row_positions_;
-  start = positions[span.StartLine()];
-  end = positions[span.EndLine()];
-  // The 'positions' vector includes distribution offset (because of content
-  // alignment) and gutters so we need to subtract them to get the actual
-  // end position for a given track (this does not have to be done for the
-  // last track as there are no more positions's elements after it, nor for
-  // collapsed tracks).
-  if (span.EndLine() < positions.size() - 1 &&
-      !(grid.HasAutoRepeatEmptyTracks(direction) &&
-        grid.IsEmptyAutoRepeatTrack(direction, span.EndLine())))
-    end -= GridGap(direction) + GridItemOffset(direction);
-}
-
-void LayoutGrid::GridAreaPositionForChild(const LayoutBox& child,
-                                          GridTrackSizingDirection direction,
-                                          LayoutUnit& start,
-                                          LayoutUnit& end) const {
-  NOT_DESTROYED();
-  if (child.IsOutOfFlowPositioned())
-    GridAreaPositionForOutOfFlowChild(child, direction, start, end);
-  else
-    GridAreaPositionForInFlowChild(child, direction, start, end);
-}
-
-ContentPosition static ResolveContentDistributionFallback(
-    ContentDistributionType distribution) {
-  switch (distribution) {
-    case ContentDistributionType::kSpaceBetween:
-      return ContentPosition::kStart;
-    case ContentDistributionType::kSpaceAround:
-      return ContentPosition::kCenter;
-    case ContentDistributionType::kSpaceEvenly:
-      return ContentPosition::kCenter;
-    case ContentDistributionType::kStretch:
-      return ContentPosition::kStart;
-    case ContentDistributionType::kDefault:
-      return ContentPosition::kNormal;
-  }
-
-  NOTREACHED();
-  return ContentPosition::kNormal;
-}
-
-static void ComputeContentDistributionOffset(
-    ContentAlignmentData& offset,
-    const LayoutUnit& available_free_space,
-    ContentPosition& fallback_position,
-    ContentDistributionType distribution,
-    unsigned number_of_grid_tracks) {
-  if (distribution != ContentDistributionType::kDefault &&
-      fallback_position == ContentPosition::kNormal)
-    fallback_position = ResolveContentDistributionFallback(distribution);
-
-  // Initialize to an invalid offset.
-  offset.position_offset = LayoutUnit(-1);
-  offset.distribution_offset = LayoutUnit(-1);
-  if (available_free_space <= 0)
-    return;
-
-  LayoutUnit position_offset;
-  LayoutUnit distribution_offset;
-  switch (distribution) {
-    case ContentDistributionType::kSpaceBetween:
-      if (number_of_grid_tracks < 2)
-        return;
-      distribution_offset = available_free_space / (number_of_grid_tracks - 1);
-      position_offset = LayoutUnit();
-      break;
-    case ContentDistributionType::kSpaceAround:
-      if (number_of_grid_tracks < 1)
-        return;
-      distribution_offset = available_free_space / number_of_grid_tracks;
-      position_offset = distribution_offset / 2;
-      break;
-    case ContentDistributionType::kSpaceEvenly:
-      distribution_offset = available_free_space / (number_of_grid_tracks + 1);
-      position_offset = distribution_offset;
-      break;
-    case ContentDistributionType::kStretch:
-    case ContentDistributionType::kDefault:
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  offset.position_offset = position_offset;
-  offset.distribution_offset = distribution_offset;
-}
-
-StyleContentAlignmentData LayoutGrid::ContentAlignment(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  return direction == kForColumns ? StyleRef().ResolvedJustifyContent(
-                                        ContentAlignmentNormalBehavior())
-                                  : StyleRef().ResolvedAlignContent(
-                                        ContentAlignmentNormalBehavior());
-}
-
-void LayoutGrid::ComputeContentPositionAndDistributionOffset(
-    GridTrackSizingDirection direction,
-    const LayoutUnit& available_free_space,
-    unsigned number_of_grid_tracks) {
-  NOT_DESTROYED();
-  auto& offset =
-      direction == kForColumns ? offset_between_columns_ : offset_between_rows_;
-  StyleContentAlignmentData content_alignment_data =
-      ContentAlignment(direction);
-  ContentPosition position = content_alignment_data.GetPosition();
-  // If <content-distribution> value can't be applied, 'position' will become
-  // the associated <content-position> fallback value.
-  ComputeContentDistributionOffset(offset, available_free_space, position,
-                                   content_alignment_data.Distribution(),
-                                   number_of_grid_tracks);
-  if (offset.IsValid())
-    return;
-
-  // TODO (lajava): Default value for overflow isn't exaclty as 'unsafe'.
-  // https://drafts.csswg.org/css-align/#overflow-values
-  if (available_free_space == 0 ||
-      (available_free_space < 0 &&
-       content_alignment_data.Overflow() == OverflowAlignment::kSafe)) {
-    offset.position_offset = LayoutUnit();
-    offset.distribution_offset = LayoutUnit();
-    return;
-  }
-
-  LayoutUnit position_offset;
-  bool is_row_axis = direction == kForColumns;
-  switch (position) {
-    case ContentPosition::kLeft:
-      DCHECK(is_row_axis);
-      position_offset = LayoutUnit();
-      break;
-    case ContentPosition::kRight:
-      DCHECK(is_row_axis);
-      position_offset = available_free_space;
-      break;
-    case ContentPosition::kCenter:
-      position_offset = available_free_space / 2;
-      break;
-    // Only used in flex layout, for other layout, it's equivalent to 'End'.
-    case ContentPosition::kFlexEnd:
-      U_FALLTHROUGH;
-    case ContentPosition::kEnd:
-      if (is_row_axis) {
-        position_offset = StyleRef().IsLeftToRightDirection()
-                              ? available_free_space
-                              : LayoutUnit();
-      } else {
-        position_offset = available_free_space;
-      }
-      break;
-    // Only used in flex layout, for other layout, it's equivalent to 'Start'.
-    case ContentPosition::kFlexStart:
-      U_FALLTHROUGH;
-    case ContentPosition::kStart:
-      if (is_row_axis) {
-        position_offset = StyleRef().IsLeftToRightDirection()
-                              ? LayoutUnit()
-                              : available_free_space;
-      } else {
-        position_offset = LayoutUnit();
-      }
-      break;
-    case ContentPosition::kBaseline:
-      U_FALLTHROUGH;
-    case ContentPosition::kLastBaseline:
-      // FIXME: These two require implementing Baseline Alignment. For now, we
-      // always 'start' align the child. crbug.com/234191
-      if (is_row_axis) {
-        position_offset = StyleRef().IsLeftToRightDirection()
-                              ? LayoutUnit()
-                              : available_free_space;
-      } else {
-        position_offset = LayoutUnit();
-      }
-      break;
-    case ContentPosition::kNormal:
-      U_FALLTHROUGH;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  offset.position_offset = position_offset;
-  offset.distribution_offset = LayoutUnit();
-}
-
-LayoutUnit LayoutGrid::TranslateOutOfFlowRTLCoordinate(
-    const LayoutBox& child,
-    LayoutUnit coordinate) const {
-  NOT_DESTROYED();
-  DCHECK(child.IsOutOfFlowPositioned());
-  DCHECK(!StyleRef().IsLeftToRightDirection());
-
-  auto it = column_of_positioned_item_.find(&child);
-  if (it != column_of_positioned_item_.end() && it->value)
-    return TranslateRTLCoordinate(coordinate);
-
-  return BorderLogicalLeft() + BorderLogicalRight() + ClientLogicalWidth() -
-         coordinate;
-}
-
-LayoutUnit LayoutGrid::TranslateRTLCoordinate(LayoutUnit coordinate) const {
-  NOT_DESTROYED();
-  DCHECK(!StyleRef().IsLeftToRightDirection());
-
-  LayoutUnit alignment_offset = column_positions_[0];
-  LayoutUnit right_grid_edge_position =
-      column_positions_[column_positions_.size() - 1];
-  return right_grid_edge_position + alignment_offset - coordinate;
-}
-
-// TODO: SetLogicalPositionForChild has only one caller, consider its
-// refactoring in the future.
-void LayoutGrid::SetLogicalPositionForChild(LayoutBox& child) const {
-  NOT_DESTROYED();
-  // "In the positioning phase [...] calculations are performed according to the
-  // writing mode of the containing block of the box establishing the orthogonal
-  // flow." However, 'setLogicalPosition' will only take into account the
-  // child's writing-mode, so the position may need to be transposed.
-  LayoutPoint child_location(LogicalOffsetForChild(child, kForColumns),
-                             LogicalOffsetForChild(child, kForRows));
-  child.SetLogicalLocation(GridLayoutUtils::IsOrthogonalChild(*this, child)
-                               ? child_location.TransposedPoint()
-                               : child_location);
-}
-
-void LayoutGrid::SetLogicalOffsetForChild(
-    LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  if (!child.IsGridItem() && HasStaticPositionForChild(child, direction))
-    return;
-  // 'SetLogicalLeft' and 'SetLogicalTop' only take into account the child's
-  // writing-mode, that's why 'FlowAwareDirectionForChild' is needed.
-  if (GridLayoutUtils::FlowAwareDirectionForChild(*this, child, direction) ==
-      kForColumns)
-    child.SetLogicalLeft(LogicalOffsetForChild(child, direction));
-  else
-    child.SetLogicalTop(LogicalOffsetForChild(child, direction));
-}
-
-LayoutUnit LayoutGrid::LogicalOffsetForChild(
-    const LayoutBox& child,
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  if (direction == kForRows) {
-    return ColumnAxisOffsetForChild(child);
-  }
-  LayoutUnit row_axis_offset = RowAxisOffsetForChild(child);
-  // We stored column_position_'s data ignoring the direction, hence we might
-  // need now to translate positions from RTL to LTR, as it's more convenient
-  // for painting.
-  if (!StyleRef().IsLeftToRightDirection()) {
-    row_axis_offset =
-        (child.IsOutOfFlowPositioned()
-             ? TranslateOutOfFlowRTLCoordinate(child, row_axis_offset)
-             : TranslateRTLCoordinate(row_axis_offset)) -
-        (GridLayoutUtils::IsOrthogonalChild(*this, child)
-             ? child.LogicalHeight()
-             : child.LogicalWidth());
-  }
-  return row_axis_offset;
-}
-
-LayoutPoint LayoutGrid::GridAreaLogicalPosition(const GridArea& area) const {
-  NOT_DESTROYED();
-  LayoutUnit column_axis_offset = row_positions_[area.rows.StartLine()];
-  LayoutUnit row_axis_offset = column_positions_[area.columns.StartLine()];
-
-  // See comment in findChildLogicalPosition() about why we need sometimes to
-  // translate from RTL to LTR the rowAxisOffset coordinate.
-  return LayoutPoint(StyleRef().IsLeftToRightDirection()
-                         ? row_axis_offset
-                         : TranslateRTLCoordinate(row_axis_offset),
-                     column_axis_offset);
-}
-
-void LayoutGrid::PaintChildren(const PaintInfo& paint_info,
-                               const PhysicalOffset& paint_offset) const {
-  NOT_DESTROYED();
-  DCHECK(!grid_->NeedsItemsPlacement());
-  if (grid_->HasGridItems()) {
-    BlockPainter(*this).PaintChildrenAtomically(grid_->GetOrderIterator(),
-                                                paint_info);
-  }
-}
-
-bool LayoutGrid::CachedHasDefiniteLogicalHeight() const {
-  NOT_DESTROYED();
-  SECURITY_DCHECK(has_definite_logical_height_);
-  return has_definite_logical_height_.value();
-}
-
-wtf_size_t LayoutGrid::NonCollapsedTracks(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  auto& tracks = track_sizing_algorithm_->Tracks(direction);
-  wtf_size_t number_of_tracks = tracks.size();
-  bool has_collapsed_tracks = grid_->HasAutoRepeatEmptyTracks(direction);
-  wtf_size_t number_of_collapsed_tracks =
-      has_collapsed_tracks ? grid_->AutoRepeatEmptyTracks(direction)->size()
-                           : 0;
-  return number_of_tracks - number_of_collapsed_tracks;
-}
-
-wtf_size_t LayoutGrid::NumTracks(GridTrackSizingDirection direction,
-                                 const Grid& grid) const {
-  NOT_DESTROYED();
-  // Due to limitations in our internal representation, we cannot know the
-  // number of columns from m_grid *if* there is no row (because m_grid would be
-  // empty). That's why in that case we need to get it from the style. Note that
-  // we know for sure that there are't any implicit tracks, because not having
-  // rows implies that there are no "normal" children (out-of-flow children are
-  // not stored in m_grid).
-  DCHECK(!grid.NeedsItemsPlacement());
-  if (direction == kForRows)
-    return grid.NumTracks(kForRows);
-
-  return grid.NumTracks(kForRows)
-             ? grid.NumTracks(kForColumns)
-             : GridPositionsResolver::ExplicitGridColumnCount(
-                   StyleRef(), grid.AutoRepeatTracks(kForColumns));
-}
-
-wtf_size_t LayoutGrid::ExplicitGridEndForDirection(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  wtf_size_t leading = ExplicitGridStartForDirection(direction);
-
-  if (direction == kForRows) {
-    return base::checked_cast<wtf_size_t>(
-        leading + GridPositionsResolver::ExplicitGridRowCount(
-                      StyleRef(), grid_->AutoRepeatTracks(direction)));
-  }
-
-  return base::checked_cast<wtf_size_t>(
-      leading + GridPositionsResolver::ExplicitGridColumnCount(
-                    StyleRef(), grid_->AutoRepeatTracks(direction)));
-}
-
-LayoutUnit LayoutGrid::GridItemOffset(
-    GridTrackSizingDirection direction) const {
-  NOT_DESTROYED();
-  return direction == kForRows ? offset_between_rows_.distribution_offset
-                               : offset_between_columns_.distribution_offset;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_grid.h b/third_party/blink/renderer/core/layout/layout_grid.h
deleted file mode 100644
index 93d47d3a..0000000
--- a/third_party/blink/renderer/core/layout/layout_grid.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_GRID_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_GRID_H_
-
-#include <memory>
-
-#include "third_party/blink/renderer/core/layout/grid.h"
-#include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
-#include "third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h"
-#include "third_party/blink/renderer/core/layout/layout_block.h"
-#include "third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h"
-#include "third_party/blink/renderer/core/layout/order_iterator.h"
-#include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
-
-namespace blink {
-
-struct GridArea;
-struct GridSpan;
-
-struct ContentAlignmentData {
- public:
-  ContentAlignmentData() = default;
-  ContentAlignmentData(const ContentAlignmentData&) = delete;
-  ContentAlignmentData& operator=(const ContentAlignmentData&) = delete;
-  bool IsValid() { return position_offset >= 0 && distribution_offset >= 0; }
-
-  LayoutUnit position_offset = LayoutUnit(-1);
-  LayoutUnit distribution_offset = LayoutUnit(-1);
-};
-
-enum GridAxisPosition { kGridAxisStart, kGridAxisEnd, kGridAxisCenter };
-
-class LayoutGrid final : public LayoutBlock, public LayoutNGGridInterface {
- public:
-  explicit LayoutGrid(Element*);
-  ~LayoutGrid() override;
-  void Trace(Visitor*) const override;
-
-  static LayoutGrid* CreateAnonymous(Document*);
-  const char* GetName() const override {
-    NOT_DESTROYED();
-    return "LayoutGrid";
-  }
-
-  void UpdateBlockLayout(bool relayout_children) override;
-
-  void DirtyGrid();
-
-  const LayoutNGGridInterface* ToLayoutNGGridInterface() const final {
-    NOT_DESTROYED();
-    return this;
-  }
-
-  Vector<LayoutUnit, 1> TrackSizesForComputedStyle(
-      GridTrackSizingDirection) const final;
-
-  Vector<LayoutUnit> ColumnPositions() const final {
-    NOT_DESTROYED();
-    DCHECK(!grid_->NeedsItemsPlacement());
-    return column_positions_;
-  }
-
-  Vector<LayoutUnit> RowPositions() const final {
-    NOT_DESTROYED();
-    DCHECK(!grid_->NeedsItemsPlacement());
-    return row_positions_;
-  }
-
-  // TODO(svillar): rename this method as this does not return a
-  // GridCell but its contents.
-  const GridItemList& GetGridCell(int row, int column) const {
-    NOT_DESTROYED();
-    SECURITY_DCHECK(!grid_->NeedsItemsPlacement());
-    return grid_->Cell(row, column);
-  }
-
-  wtf_size_t AutoRepeatCountForDirection(
-      GridTrackSizingDirection direction) const final {
-    NOT_DESTROYED();
-    return base::checked_cast<wtf_size_t>(grid_->AutoRepeatTracks(direction));
-  }
-
-  wtf_size_t ExplicitGridStartForDirection(
-      GridTrackSizingDirection direction) const final {
-    NOT_DESTROYED();
-    return base::checked_cast<wtf_size_t>(grid_->ExplicitGridStart(direction));
-  }
-
-  LayoutUnit TranslateRTLCoordinate(LayoutUnit) const;
-
-  LayoutUnit TranslateOutOfFlowRTLCoordinate(const LayoutBox&,
-                                             LayoutUnit) const;
-
-  // TODO(svillar): We need these for the GridTrackSizingAlgorithm. Let's figure
-  // it out how to remove this dependency.
-  LayoutUnit GuttersSize(const Grid&,
-                         GridTrackSizingDirection,
-                         wtf_size_t start_line,
-                         wtf_size_t span,
-                         absl::optional<LayoutUnit> available_size) const;
-  bool CachedHasDefiniteLogicalHeight() const;
-  bool IsBaselineAlignmentForChild(const LayoutBox& child) const;
-  bool IsBaselineAlignmentForChild(const LayoutBox& child, GridAxis) const;
-
-  StyleSelfAlignmentData SelfAlignmentForChild(
-      GridAxis,
-      const LayoutBox& child,
-      const ComputedStyle* = nullptr) const;
-
-  LayoutUnit GridGap(GridTrackSizingDirection) const final;
-  LayoutUnit GridItemOffset(GridTrackSizingDirection) const final;
-
-  void UpdateGridAreaLogicalSize(LayoutBox&, LayoutSize) const;
-
-  StyleContentAlignmentData ContentAlignment(GridTrackSizingDirection) const;
-
-  wtf_size_t ExplicitGridEndForDirection(GridTrackSizingDirection) const final;
-
-  // Exposed for testing *ONLY*.
-  Grid* InternalGrid() const {
-    NOT_DESTROYED();
-    return grid_;
-  }
-
- protected:
-  ItemPosition SelfAlignmentNormalBehavior(
-      const LayoutBox* child = nullptr) const override {
-    NOT_DESTROYED();
-    DCHECK(child);
-    return child->IsLayoutReplaced() ? ItemPosition::kStart
-                                     : ItemPosition::kStretch;
-  }
-
- private:
-  bool IsOfType(LayoutObjectType type) const override {
-    NOT_DESTROYED();
-    return type == kLayoutObjectGrid || LayoutBlock::IsOfType(type);
-  }
-  MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
-
-  void AddChild(LayoutObject* new_child,
-                LayoutObject* before_child = nullptr) override;
-  void RemoveChild(LayoutObject*) override;
-
-  bool SelfAlignmentChangedSize(GridAxis,
-                                const ComputedStyle& old_style,
-                                const ComputedStyle& new_style,
-                                const LayoutBox&) const;
-  bool DefaultAlignmentChangedSize(GridAxis,
-                                   const ComputedStyle& old_style,
-                                   const ComputedStyle& new_style) const;
-  void StyleDidChange(StyleDifference, const ComputedStyle*) override;
-
-  bool ExplicitGridDidResize(const ComputedStyle&) const;
-  bool NamedGridLinesDefinitionDidChange(const ComputedStyle&) const;
-
-  wtf_size_t ComputeAutoRepeatTracksCount(
-      GridTrackSizingDirection,
-      absl::optional<LayoutUnit> available_size) const;
-  wtf_size_t ClampAutoRepeatTracks(GridTrackSizingDirection,
-                                   wtf_size_t auto_repeat_tracks) const;
-
-  std::unique_ptr<OrderedTrackIndexSet> ComputeEmptyTracksForAutoRepeat(
-      Grid&,
-      GridTrackSizingDirection) const;
-
-  void PerformGridItemsPreLayout(const GridTrackSizingAlgorithm*) const;
-
-  void PlaceItemsOnGrid(
-      GridTrackSizingAlgorithm*,
-      absl::optional<LayoutUnit> available_logical_width) const;
-  void PopulateExplicitGridAndOrderIterator(Grid&) const;
-  std::unique_ptr<GridArea> CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
-      const Grid&,
-      const LayoutBox&,
-      GridTrackSizingDirection,
-      const GridSpan& specified_positions) const;
-  void PlaceSpecifiedMajorAxisItemsOnGrid(
-      Grid&,
-      const HeapVector<Member<LayoutBox>>&) const;
-  void PlaceAutoMajorAxisItemsOnGrid(
-      Grid&,
-      const HeapVector<Member<LayoutBox>>&) const;
-  void PlaceAutoMajorAxisItemOnGrid(
-      Grid&,
-      LayoutBox&,
-      std::pair<wtf_size_t, wtf_size_t>& auto_placement_cursor) const;
-  GridTrackSizingDirection AutoPlacementMajorAxisDirection() const;
-  GridTrackSizingDirection AutoPlacementMinorAxisDirection() const;
-
-  absl::optional<LayoutUnit> OverrideIntrinsicContentLogicalSize(
-      GridTrackSizingDirection) const;
-
-  void ComputeTrackSizesForIndefiniteSize(GridTrackSizingAlgorithm*,
-                                          GridTrackSizingDirection) const;
-  void ComputeTrackSizesForDefiniteSize(GridTrackSizingDirection,
-                                        LayoutUnit free_space);
-
-  void RepeatTracksSizingIfNeeded(LayoutUnit available_space_for_columns,
-                                  LayoutUnit available_space_for_rows);
-
-  void LayoutGridItems();
-  void PrepareChildForPositionedLayout(LayoutBox&);
-  bool HasStaticPositionForChild(const LayoutBox&,
-                                 GridTrackSizingDirection) const;
-  void LayoutPositionedObjects(
-      bool relayout_children,
-      PositionedLayoutBehavior = kDefaultLayout) override;
-  void PopulateGridPositionsForDirection(GridTrackSizingDirection);
-
-  LayoutUnit ResolveAutoStartGridPosition(GridTrackSizingDirection) const;
-  LayoutUnit ResolveAutoEndGridPosition(GridTrackSizingDirection) const;
-  LayoutUnit LogicalOffsetForOutOfFlowChild(const LayoutBox&,
-                                            GridTrackSizingDirection,
-                                            LayoutUnit) const;
-  LayoutUnit GridAreaBreadthForOutOfFlowChild(const LayoutBox&,
-                                              GridTrackSizingDirection);
-  void GridAreaPositionForOutOfFlowChild(const LayoutBox&,
-                                         GridTrackSizingDirection,
-                                         LayoutUnit& start,
-                                         LayoutUnit& end) const;
-  void GridAreaPositionForInFlowChild(const LayoutBox&,
-                                      GridTrackSizingDirection,
-                                      LayoutUnit& start,
-                                      LayoutUnit& end) const;
-  void GridAreaPositionForChild(const LayoutBox&,
-                                GridTrackSizingDirection,
-                                LayoutUnit& start,
-                                LayoutUnit& end) const;
-
-  GridAxisPosition ColumnAxisPositionForChild(const LayoutBox&) const;
-  GridAxisPosition RowAxisPositionForChild(const LayoutBox&) const;
-  LayoutUnit RowAxisOffsetForChild(const LayoutBox&) const;
-  LayoutUnit ColumnAxisOffsetForChild(const LayoutBox&) const;
-  void ComputeContentPositionAndDistributionOffset(
-      GridTrackSizingDirection,
-      const LayoutUnit& available_free_space,
-      unsigned number_of_grid_tracks);
-  LayoutPoint GridAreaLogicalPosition(const GridArea&) const;
-  void SetLogicalPositionForChild(LayoutBox&) const;
-  void SetLogicalOffsetForChild(LayoutBox&, GridTrackSizingDirection) const;
-  LayoutUnit LogicalOffsetForChild(const LayoutBox&,
-                                   GridTrackSizingDirection) const;
-
-  LayoutUnit GridAreaBreadthForChildIncludingAlignmentOffsets(
-      const LayoutBox&,
-      GridTrackSizingDirection) const;
-
-  void PaintChildren(const PaintInfo&,
-                     const PhysicalOffset& paint_offset) const override;
-
-  LayoutUnit AvailableAlignmentSpaceForChildBeforeStretching(
-      LayoutUnit grid_area_breadth_for_child,
-      const LayoutBox&) const;
-  StyleSelfAlignmentData JustifySelfForChild(
-      const LayoutBox&,
-      const ComputedStyle* = nullptr) const;
-  StyleSelfAlignmentData AlignSelfForChild(
-      const LayoutBox&,
-      const ComputedStyle* = nullptr) const;
-  StyleSelfAlignmentData DefaultAlignment(GridAxis, const ComputedStyle&) const;
-  bool DefaultAlignmentIsStretchOrNormal(GridAxis, const ComputedStyle&) const;
-  void ApplyStretchAlignmentToChildIfNeeded(LayoutBox&);
-  bool HasAutoSizeInColumnAxis(const LayoutBox& child) const;
-  bool HasAutoSizeInRowAxis(const LayoutBox& child) const;
-  bool AllowedToStretchChildAlongColumnAxis(const LayoutBox& child) const {
-    NOT_DESTROYED();
-    return AlignSelfForChild(child).GetPosition() == ItemPosition::kStretch &&
-           HasAutoSizeInColumnAxis(child) && !HasAutoMarginsInColumnAxis(child);
-  }
-  bool AllowedToStretchChildAlongRowAxis(const LayoutBox& child) const {
-    NOT_DESTROYED();
-    return JustifySelfForChild(child).GetPosition() == ItemPosition::kStretch &&
-           HasAutoSizeInRowAxis(child) && !HasAutoMarginsInRowAxis(child);
-  }
-  bool HasAutoMarginsInColumnAxis(const LayoutBox&) const;
-  bool HasAutoMarginsInRowAxis(const LayoutBox&) const;
-  void UpdateAutoMarginsInColumnAxisIfNeeded(LayoutBox&);
-  void UpdateAutoMarginsInRowAxisIfNeeded(LayoutBox&);
-
-  LayoutUnit BaselinePosition(
-      FontBaseline,
-      bool first_line,
-      LineDirectionMode,
-      LinePositionMode = kPositionOnContainingLine) const override;
-  LayoutUnit FirstLineBoxBaseline() const override;
-  LayoutUnit InlineBlockBaseline(LineDirectionMode) const override;
-
-  LayoutUnit ColumnAxisBaselineOffsetForChild(const LayoutBox&) const;
-  LayoutUnit RowAxisBaselineOffsetForChild(const LayoutBox&) const;
-
-  LayoutUnit GridGap(GridTrackSizingDirection,
-                     absl::optional<LayoutUnit> available_size) const;
-
-  size_t GridItemSpan(const LayoutBox&, GridTrackSizingDirection);
-
-  wtf_size_t NonCollapsedTracks(GridTrackSizingDirection) const;
-  wtf_size_t NumTracks(GridTrackSizingDirection, const Grid&) const;
-
-  static LayoutUnit OverrideContainingBlockContentSizeForChild(
-      const LayoutBox& child,
-      GridTrackSizingDirection);
-  static LayoutUnit SynthesizedBaselineFromBorderBox(const LayoutBox&,
-                                                     LineDirectionMode);
-  static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
-
-  bool AspectRatioPrefersInline(const LayoutBox& child,
-                                bool block_flow_is_column_axis);
-
-  Member<Grid> grid_;
-  Member<GridTrackSizingAlgorithm> track_sizing_algorithm_;
-
-  Vector<LayoutUnit> row_positions_;
-  Vector<LayoutUnit> column_positions_;
-  ContentAlignmentData offset_between_columns_;
-  ContentAlignmentData offset_between_rows_;
-
-  typedef HeapHashMap<Member<const LayoutBox>, absl::optional<wtf_size_t>>
-      OutOfFlowPositionsMap;
-  OutOfFlowPositionsMap column_of_positioned_item_;
-  OutOfFlowPositionsMap row_of_positioned_item_;
-
-  bool has_any_orthogonal_item_{false};
-  bool baseline_items_cached_{false};
-  absl::optional<bool> has_definite_logical_height_;
-};
-
-template <>
-struct DowncastTraits<LayoutGrid> {
-  static bool AllowFrom(const LayoutObject& object) {
-    return object.IsLayoutGrid();
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_GRID_H_
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index d507d13..923fad5 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -79,7 +79,6 @@
 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_image.h"
 #include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
@@ -404,7 +403,7 @@
     case EDisplay::kGrid:
     case EDisplay::kInlineGrid:
       UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout);
-      return LayoutObjectFactory::CreateGrid(*element, style, legacy);
+      return MakeGarbageCollected<LayoutNGGrid>(element);
     case EDisplay::kMath:
     case EDisplay::kBlockMath:
       return LayoutObjectFactory::CreateMath(*element, style, legacy);
@@ -1302,8 +1301,9 @@
     // its container. This also applies to out of flow items of the grid, as we
     // need the cached information of the grid to recompute the out of flow
     // item's containing block rect.
-    if (layout_box->ContainingBlock()->IsLayoutGridIncludingNG())
+    if (layout_box->ContainingBlock()->IsLayoutNGGrid()) {
       return false;
+    }
 
     if (const NGLayoutResult* layout_result =
             layout_box->GetCachedLayoutResult(nullptr)) {
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 9ac7552..c9816cd 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -924,10 +924,6 @@
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectNGFlexibleBox);
   }
-  bool IsLayoutNGGrid() const {
-    NOT_DESTROYED();
-    return IsOfType(kLayoutObjectNGGrid);
-  }
   bool IsLayoutNGListItem() const {
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectNGListItem);
@@ -1008,13 +1004,9 @@
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectNGCustom);
   }
-  bool IsLayoutGrid() const {
+  bool IsLayoutNGGrid() const {
     NOT_DESTROYED();
-    return IsOfType(kLayoutObjectGrid);
-  }
-  bool IsLayoutGridIncludingNG() const {
-    NOT_DESTROYED();
-    return IsOfType(kLayoutObjectGrid) || IsOfType(kLayoutObjectNGGrid);
+    return IsOfType(kLayoutObjectNGGrid);
   }
   bool IsLayoutIFrame() const {
     NOT_DESTROYED();
@@ -3766,7 +3758,6 @@
     kLayoutObjectFileUploadControl,
     kLayoutObjectFrame,
     kLayoutObjectFrameSet,
-    kLayoutObjectGrid,
     kLayoutObjectIFrame,
     kLayoutObjectImage,
     kLayoutObjectInsideListMarker,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc
index 46815815..28d8c74 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_frame_set.h"
-#include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_inside_list_marker.h"
 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
@@ -153,12 +152,6 @@
       node, legacy);
 }
 
-LayoutBlock* LayoutObjectFactory::CreateGrid(Node& node,
-                                             const ComputedStyle& style,
-                                             LegacyLayout legacy) {
-  return CreateObject<LayoutBlock, LayoutNGGrid, LayoutGrid>(node, legacy);
-}
-
 LayoutBlock* LayoutObjectFactory::CreateMath(Node& node,
                                              const ComputedStyle& style,
                                              LegacyLayout legacy) {
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h
index b9704d8b..ee9d4ce9 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -52,7 +52,6 @@
   static LayoutBlock* CreateFlexibleBox(Node&,
                                         const ComputedStyle&,
                                         LegacyLayout);
-  static LayoutBlock* CreateGrid(Node&, const ComputedStyle&, LegacyLayout);
   static LayoutBlock* CreateMath(Node&, const ComputedStyle&, LegacyLayout);
   static LayoutBlock* CreateCustom(Node&, const ComputedStyle&, LegacyLayout);
   static LayoutObject* CreateListMarker(Node&,
diff --git a/third_party/blink/renderer/core/layout/layout_table.cc b/third_party/blink/renderer/core/layout/layout_table.cc
index fd2575b4..a528dc615 100644
--- a/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/third_party/blink/renderer/core/layout/layout_table.cc
@@ -375,14 +375,6 @@
   // might not even get there.
   UpdateCachedIntrinsicLogicalWidthsIfNeeded();
 
-  if (IsGridItem()) {
-    // TODO(jfernandez): Investigate whether the grid layout algorithm provides
-    // all the logic needed and that we're not skipping anything essential due
-    // to the early return here.
-    LayoutBlock::UpdateLogicalWidth();
-    return;
-  }
-
   if (IsOutOfFlowPositioned()) {
     LogicalExtentComputedValues computed_values;
     ComputePositionedLogicalWidth(computed_values);
diff --git a/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h b/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h
index acf2d3a7..dbd10ec6fc 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid_interface.h
@@ -36,7 +36,7 @@
 template <>
 struct InterfaceDowncastTraits<LayoutNGGridInterface> {
   static bool AllowFrom(const LayoutObject& object) {
-    return object.IsLayoutGridIncludingNG();
+    return object.IsLayoutNGGrid();
   }
   static const LayoutNGGridInterface& ConvertFrom(const LayoutObject& object) {
     return *object.ToLayoutNGGridInterface();
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 5684536d..5dfe062b 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -267,7 +267,7 @@
   // should get laid out by the actual containing block.
   NGOutOfFlowLayoutPart(css_container->CanContainAbsolutePositionObjects(),
                         css_container->CanContainFixedPositionObjects(),
-                        css_container->IsLayoutGrid(), constraint_space,
+                        /* is_grid_container */ false, constraint_space,
                         &container_builder, initial_containing_block_fixed_size)
       .Run(/* only_layout */ this);
   const NGLayoutResult* result = container_builder.ToBoxFragment();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index f4c982b9..4472e206 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -96,7 +96,7 @@
   NGConstraintSpaceBuilder builder(writing_mode, style.GetWritingDirection(),
                                    is_new_fc, adjust_inline_size_if_needed);
 
-  if (!block.IsWritingModeRoot() || block.IsGridItem()) {
+  if (!block.IsWritingModeRoot()) {
     // We don't know if the parent layout will require our baseline, so always
     // request it.
     builder.SetBaselineAlgorithmType(block.IsInline() &&
@@ -105,9 +105,9 @@
                                          : NGBaselineAlgorithmType::kDefault);
   }
 
-  if (block.IsAtomicInlineLevel() || block.IsFlexItem() || block.IsGridItem() ||
-      block.IsFloating())
+  if (block.IsAtomicInlineLevel() || block.IsFlexItem() || block.IsFloating()) {
     builder.SetIsPaintedAtomically(true);
+  }
 
   builder.SetAvailableSize(available_size);
   builder.SetPercentageResolutionSize(percentage_size);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index e64acf15..1ea0dbc8 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -103,7 +103,7 @@
   bool IsFlexibleBox() const {
     return IsBlock() && box_->IsFlexibleBoxIncludingNG();
   }
-  bool IsGrid() const { return IsBlock() && box_->IsLayoutGridIncludingNG(); }
+  bool IsGrid() const { return IsBlock() && box_->IsLayoutNGGrid(); }
   bool ShouldBeConsideredAsReplaced() const {
     return box_->ShouldBeConsideredAsReplaced();
   }
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
index 57a010e..7f10027 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_node.cc
@@ -74,8 +74,9 @@
   const LayoutBlock* block = box_->ContainingBlock();
   while (!block->IsLayoutView()) {
     if (block->IsTableCell() || block->IsFlexibleBoxIncludingNG() ||
-        block->IsLayoutGridIncludingNG())
+        block->IsLayoutNGGrid()) {
       return false;
+    }
 
     block = block->ContainingBlock();
   }
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index 1a4a06a4..584c5e80 100644
--- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -241,7 +241,7 @@
     const bool is_deprecated_webkit_box =
         cb->StyleRef().IsDeprecatedWebkitBox();
     if ((!is_deprecated_webkit_box && cb->IsFlexibleBoxIncludingNG()) ||
-        cb->IsLayoutGridIncludingNG()) {
+        cb->IsLayoutNGGrid()) {
       return false;
     }
     cb = cb->ContainingBlock();
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
index 08eb2f9..3e72e38 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_controller.cc
@@ -286,8 +286,9 @@
     return false;
 
   // Do not implicitly promote things that are partially or fully invisible.
-  if (style->HasOpacity() || style->Visibility() != EVisibility::kVisible)
+  if (style->HasOpacity() || !style->VisibleToHitTesting()) {
     return false;
+  }
 
   PaintLayerScrollableArea* scrollable_area = GetScrollableArea(element);
   if (!scrollable_area)
diff --git a/third_party/blink/renderer/core/paint/box_painter.cc b/third_party/blink/renderer/core/paint/box_painter.cc
index f946241..caaeb264 100644
--- a/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_painter.cc
@@ -302,8 +302,10 @@
     return;
 
   // If an object is not visible, it does not scroll.
-  if (layout_box_.StyleRef().Visibility() != EVisibility::kVisible)
+  const ComputedStyle& style = layout_box_.StyleRef();
+  if (style.Visibility() != EVisibility::kVisible) {
     return;
+  }
 
   if (!layout_box_.GetScrollableArea())
     return;
@@ -312,6 +314,23 @@
   if (!fragment)
     return;
 
+  // If an object does scroll overflow, but it is not itself visible to
+  // hit testing (e.g., because it has pointer-events: none), it may
+  // have descendants that *are* visible to hit testing.  In that case,
+  // we need to record hit test data with a null scroll_translation
+  // (which marks a region where composited scroll is not allowed) so
+  // that we fall back to main thread hit testing for the entire box.
+  //
+  // Note that if it is visibility: hidden, then the style.Visibility()
+  // check above will fail and we will already have returned.
+  if (!style.VisibleToHitTesting()) {
+    auto& paint_controller = paint_info.context.GetPaintController();
+    paint_controller.RecordScrollHitTestData(
+        background_client, DisplayItem::kScrollHitTest, nullptr,
+        VisualRect(fragment->PaintOffset()));
+    return;
+  }
+
   // If there is an associated scroll node, emit scroll hit test data.
   const auto* properties = fragment->PaintProperties();
   if (properties && properties->Scroll()) {
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 7e5d54ff..0bb8e14 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
@@ -2380,8 +2380,8 @@
     frame_view->RemoveScrollAnchoringScrollableArea(this);
   }
 
-  bool is_visible_to_hit_test =
-      GetLayoutBox()->StyleRef().VisibleToHitTesting();
+  bool is_visible =
+      GetLayoutBox()->StyleRef().Visibility() == EVisibility::kVisible;
   bool did_scroll_overflow = scrolls_overflow_;
   if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
     mojom::blink::ScrollbarMode h_mode;
@@ -2392,7 +2392,7 @@
       has_overflow = false;
   }
 
-  scrolls_overflow_ = has_overflow && is_visible_to_hit_test;
+  scrolls_overflow_ = has_overflow && is_visible;
   if (did_scroll_overflow == ScrollsOverflow())
     return;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index ad9d445..5b5dd5b 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -445,9 +445,12 @@
       const PhysicalRect&,
       const mojom::blink::ScrollIntoViewParamsPtr&) override;
 
-  // Returns true if the scrollable area is user-scrollable, visible to hit
-  // testing, and it does in fact overflow. This means this method will return
-  // false for 'overflow: hidden' and 'pointer-events: none'.
+  // Returns true if the scrollable area is user-scrollable and it does
+  // in fact overflow. This means this method will return false for
+  // 'overflow: hidden' (which is programmatically scrollable but not
+  // user-scrollable).  Note that being user-scrollable may mean being
+  // scrollable with the keyboard but not (due to pointer-events:none)
+  // with the mouse or touch.
   bool ScrollsOverflow() const { return scrolls_overflow_; }
 
   // Rectangle encompassing the scroll corner and resizer rect.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 1a8cb0c..6cc11540 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -295,10 +295,16 @@
   Element* scroller = GetDocument().getElementById("scroller");
   EXPECT_TRUE(UsesCompositedScrolling(scroller->GetLayoutObject()));
 
-  // pointer-events: none causes the scoller to be invisible for hit testing,
+  // pointer-events: none does not affect whether composited scrolling is
+  // present.
+  scroller->setAttribute(html_names::kStyleAttr, "pointer-events: none");
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_TRUE(UsesCompositedScrolling(scroller->GetLayoutObject()));
+
+  // visibility: hidden causes the scroller to be invisible for hit testing,
   // so ScrollsOverflow becomes false on the PaintLayerScrollableArea, and hence
   // composited scrolling is not present.
-  scroller->setAttribute(html_names::kStyleAttr, "pointer-events: none");
+  scroller->setAttribute(html_names::kStyleAttr, "visibility: hidden");
   UpdateAllLifecyclePhasesForTest();
   EXPECT_FALSE(UsesCompositedScrolling(scroller->GetLayoutObject()));
 
diff --git a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
index eb3ad77c..1f93e13 100644
--- a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
+++ b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
@@ -77,7 +77,7 @@
     GraphicsContext& context,
     const PhysicalOffset& paint_offset) {
   const auto* box = GetScrollableArea().GetLayoutBox();
-  DCHECK_EQ(box->StyleRef().Visibility(), EVisibility::kVisible);
+  DCHECK(box->StyleRef().VisibleToHitTesting());
   if (!box->CanResize())
     return;
 
@@ -276,7 +276,8 @@
   // cc::ScrollbarController can only handle interactions with composited native
   // scrollbars. For any other scrollbar, prevent the composited-scroll hit test
   // from succeeding, and send touch events to the main thread for thumb drags.
-  if (!GetScrollableArea().ShouldDirectlyCompositeScrollbar(scrollbar)) {
+  if (!GetScrollableArea().ShouldDirectlyCompositeScrollbar(scrollbar) &&
+      GetScrollableArea().GetLayoutBox()->StyleRef().VisibleToHitTesting()) {
     context.GetPaintController().RecordScrollHitTestData(
         scrollbar, DisplayItem::kScrollbarHitTest, nullptr, visual_rect);
   }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 364ef1a..ca0e5f9 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -420,6 +420,15 @@
   // O(p) due to copying the chunk list. Subtotal: O((qd + p)d) = O(qd^2 + pd)
   // Assuming p > d, the total complexity would be O(pqd + qd^2 + pd) = O(pqd)
   while (chunk_cursor != artifact->PaintChunks().end()) {
+    // Track painted ScrollTranslation nodes. with ScrollUnification enabled,
+    // PaintArtifactCompositor::Update uses this to know which
+    // ScrollTranslation nodes we need to create composited Transform nodes
+    // for.
+    if (chunk_cursor->hit_test_data &&
+        chunk_cursor->hit_test_data->scroll_translation) {
+      scroll_translation_nodes_.insert(
+          chunk_cursor->hit_test_data->scroll_translation.get());
+    }
     // Look at the effect node of the next chunk. There are 3 possible cases:
     // A. The next chunk belongs to the current group but no subgroup.
     // B. The next chunk does not belong to the current group.
@@ -680,6 +689,7 @@
   wtf_size_t old_size = pending_layers_.size();
   OldPendingLayerMatcher old_pending_layer_matcher(std::move(pending_layers_));
   pending_layers_.reserve(old_size);
+  scroll_translation_nodes_.clear();
 
   // Make compositing decisions, storing the result in |pending_layers_|.
   CollectPendingLayers(std::move(artifact));
@@ -693,11 +703,6 @@
   UpdateCompositorViewportProperties(viewport_properties, property_tree_manager,
                                      host);
 
-  // With ScrollUnification, we ensure a cc::ScrollNode for all
-  // |scroll_translation_nodes|.
-  if (unification_enabled)
-    property_tree_manager.EnsureCompositorScrollNodes(scroll_translation_nodes);
-
   for (auto& entry : synthesized_clip_cache_)
     entry.in_use = false;
 
@@ -737,7 +742,8 @@
     const auto& scroll_translation =
         NearestScrollTranslationForLayer(pending_layer);
     int scroll_id =
-        property_tree_manager.EnsureCompositorScrollNode(scroll_translation);
+        property_tree_manager.EnsureCompositorScrollAndTransformNode(
+            scroll_translation);
 
     layer_list_builder.Add(&layer);
 
@@ -761,6 +767,35 @@
     }
   }
 
+  if (unification_enabled) {
+    // We want to create a cc::TransformNode only if the scroller is painted.
+    // This avoids violating an assumption in CompositorAnimations that an
+    // element has property nodes for either all or none of its animating
+    // properties (see crbug.com/1385575).
+    // However, we want to create a cc::ScrollNode regardless of whether the
+    // scroller is painted. This ensures that scroll offset animations aren't
+    // affected by becoming unpainted."
+    Vector<const TransformPaintPropertyNode*> scroll_node_only;
+    for (auto* node : scroll_translation_nodes) {
+      if (scroll_translation_nodes_.Contains(node)) {
+        property_tree_manager.EnsureCompositorScrollAndTransformNode(*node);
+      } else {
+        // We can't ensure ScrollNode-only scroll translation nodes yet because
+        // we don't have a guarantee about the order of
+        // |scroll_translation_nodes|. If an unpainted child is encountered
+        // before its parent, EnsureCompositorScrollNode will create its parent
+        // node with invalid transform_id.
+        scroll_node_only.push_back(node);
+      }
+    }
+
+    // Ensure ScrollNode-only scroll translation nodes.
+    for (auto* node : scroll_node_only) {
+      property_tree_manager.EnsureCompositorScrollNode(*node->ScrollNode(),
+                                                       *node);
+    }
+  }
+
   root_layer_->layer_tree_host()->RegisterSelection(layer_selection);
 
   property_tree_manager.Finalize();
@@ -786,6 +821,7 @@
   host->property_trees()->ResetCachedData();
   previous_update_for_testing_ = PreviousUpdateType::kFull;
   needs_update_ = false;
+  scroll_translation_nodes_.clear();
 
   UpdateDebugInfo();
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index d25921c5..d75ddd1e 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -22,6 +22,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -340,6 +341,10 @@
   class OldPendingLayerMatcher;
   PendingLayers pending_layers_;
 
+  // ScrollTranslationNodes of the PaintArtifact which are painted.
+  // This member variable is only used in PaintArtifactCompositor::Update.
+  HashSet<const TransformPaintPropertyNode*> scroll_translation_nodes_;
+
   friend class StubChromeClientForCAP;
   friend class PaintArtifactCompositorTest;
 };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 318f04f..32e97cb 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -20,6 +20,7 @@
 #include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
+#include "cc/trees/property_tree.h"
 #include "cc/trees/scroll_node.h"
 #include "cc/trees/transform_node.h"
 #include "cc/view_transition/view_transition_request.h"
@@ -4652,6 +4653,36 @@
   WTF::Vector<const TransformPaintPropertyNode*> scroll_translation_nodes;
   scroll_translation_nodes.push_back(&scroll_state.Transform());
 
+  Update(TestPaintArtifact()
+             .Chunk(1)
+             .Properties(scroll_state.Transform(), c0(), e0())
+             .Build(),
+         ViewportProperties(), scroll_translation_nodes);
+
+  const auto& scroll_tree = GetPropertyTrees().scroll_tree();
+  auto* scroll_node = scroll_tree.FindNodeFromElementId(
+      scroll_state.Transform().ScrollNode()->GetCompositorElementId());
+  EXPECT_TRUE(scroll_node);
+  EXPECT_FALSE(scroll_node->is_composited);
+}
+
+TEST_P(PaintArtifactCompositorTest, AddUnpaintedNonCompositedScrollNodes) {
+  // This test requires scroll unification.
+  if (!base::FeatureList::IsEnabled(::features::kScrollUnification)) {
+    return;
+  }
+
+  const uint32_t main_thread_scrolling_reason =
+      cc::MainThreadScrollingReason::kNotOpaqueForTextAndLCDText;
+  ASSERT_TRUE(cc::MainThreadScrollingReason::HasNonCompositedScrollReasons(
+      main_thread_scrolling_reason));
+  auto scroll_state =
+      ScrollState1(PropertyTreeState::Root(), CompositingReason::kNone,
+                   main_thread_scrolling_reason);
+
+  WTF::Vector<const TransformPaintPropertyNode*> scroll_translation_nodes;
+  scroll_translation_nodes.push_back(&scroll_state.Transform());
+
   TestPaintArtifact artifact;
   Update(artifact.Build(), ViewportProperties(), scroll_translation_nodes);
 
@@ -4660,6 +4691,7 @@
       scroll_state.Transform().ScrollNode()->GetCompositorElementId());
   EXPECT_TRUE(scroll_node);
   EXPECT_FALSE(scroll_node->is_composited);
+  EXPECT_EQ(scroll_node->transform_id, cc::kInvalidPropertyNodeId);
 }
 
 TEST_P(PaintArtifactCompositorTest, RepaintIndirectScrollHitTest) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 3145fdbc..669b600 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -214,12 +214,12 @@
   }
 }
 
-void PropertyTreeManager::EnsureCompositorScrollNodes(
+void PropertyTreeManager::EnsureCompositorScrollTranslationNodes(
     const Vector<const TransformPaintPropertyNode*>& scroll_translation_nodes) {
   DCHECK(base::FeatureList::IsEnabled(features::kScrollUnification));
 
   for (auto* node : scroll_translation_nodes)
-    EnsureCompositorScrollNode(*node);
+    EnsureCompositorScrollAndTransformNode(*node);
 }
 
 void PropertyTreeManager::SetupRootTransformNode() {
@@ -425,7 +425,8 @@
         transform_tree_.EnsureStickyPositionData(id);
     sticky_data.constraints = *sticky_constraint;
     const auto& scroll_ancestor = transform_node.NearestScrollTranslationNode();
-    sticky_data.scroll_ancestor = EnsureCompositorScrollNode(scroll_ancestor);
+    sticky_data.scroll_ancestor =
+        EnsureCompositorScrollAndTransformNode(scroll_ancestor);
     const auto& scroll_ancestor_compositor_node =
         *scroll_tree_.Node(sticky_data.scroll_ancestor);
     if (scroll_ancestor_compositor_node.scrolls_outer_viewport)
@@ -458,6 +459,7 @@
     compositor_node.element_id = compositor_element_id;
   }
 
+  transform_node.SetCcNodeId(new_sequence_number_, id);
   // If this transform is a scroll offset translation, create the associated
   // compositor scroll property node and adjust the compositor transform node's
   // scroll offset.
@@ -465,8 +467,7 @@
   if (auto* scroll_node = transform_node.ScrollNode()) {
     compositor_node.scrolls = true;
     compositor_node.should_be_snapped = true;
-    CreateCompositorScrollNode(*scroll_node, compositor_node,
-                               transform_node.HasDirectCompositingReasons());
+    EnsureCompositorScrollNode(*scroll_node, transform_node);
   }
 
   compositor_node.visible_frame_element_id =
@@ -485,7 +486,6 @@
   }
   compositor_node.parent_frame_id = parent_frame_id;
 
-  transform_node.SetCcNodeId(new_sequence_number_, id);
   transform_tree_.set_needs_update(true);
 
   return id;
@@ -530,11 +530,48 @@
   return id;
 }
 
-void PropertyTreeManager::CreateCompositorScrollNode(
+static const TransformPaintPropertyNode* GetScrollTranslationNodeForParent(
     const ScrollPaintPropertyNode& scroll_node,
-    const cc::TransformNode& scroll_offset_translation,
-    bool is_composited) {
-  DCHECK(!scroll_tree_.Node(scroll_node.CcNodeId(new_sequence_number_)));
+    const TransformPaintPropertyNode& scroll_translation_node) {
+  const ScrollPaintPropertyNode* parent_scroll_node = scroll_node.Parent();
+  const TransformPaintPropertyNode* parent_scroll_translation =
+      &scroll_translation_node.UnaliasedParent()
+           ->NearestScrollTranslationNode();
+
+  if (parent_scroll_node != parent_scroll_translation->ScrollNode()) {
+    // The transform tree and the scroll tree have different hierarchies
+    // because of fixed-position elements.
+    parent_scroll_translation = scroll_translation_node.UnaliasedParent();
+    while (parent_scroll_translation) {
+      const auto* scroll_translation_for_fixed =
+          parent_scroll_translation->ScrollTranslationForFixed();
+      if (scroll_translation_for_fixed &&
+          scroll_translation_for_fixed->ScrollNode() == parent_scroll_node) {
+        parent_scroll_translation = scroll_translation_for_fixed;
+        break;
+      }
+      parent_scroll_translation = parent_scroll_translation->UnaliasedParent();
+    }
+  }
+  return parent_scroll_translation;
+}
+
+void PropertyTreeManager::EnsureCompositorScrollNode(
+    const ScrollPaintPropertyNode& scroll_node,
+    const TransformPaintPropertyNode& scroll_translation_node) {
+  if (scroll_tree_.Node(scroll_node.CcNodeId(new_sequence_number_))) {
+    return;
+  }
+
+  const ScrollPaintPropertyNode* parent_scroll_node = scroll_node.Parent();
+  // Look for the ScrollTranslation node corresponding to its parent scroll
+  // node.
+  const auto* parent_scroll_translation =
+      GetScrollTranslationNodeForParent(scroll_node, scroll_translation_node);
+
+  DCHECK(parent_scroll_translation);
+  DCHECK_EQ(parent_scroll_node, parent_scroll_translation->ScrollNode());
+  EnsureCompositorScrollNode(*parent_scroll_node, *parent_scroll_translation);
 
   int parent_id = scroll_node.Parent()->CcNodeId(new_sequence_number_);
   // Compositor transform nodes up to scroll_offset_translation must exist.
@@ -572,16 +609,19 @@
     scroll_tree_.SetElementIdForNodeId(id, compositor_element_id);
   }
 
-  compositor_node.transform_id = scroll_offset_translation.id;
-  compositor_node.is_composited = is_composited;
+  compositor_node.transform_id =
+      scroll_translation_node.CcNodeId(new_sequence_number_);
+  compositor_node.is_composited =
+      scroll_translation_node.HasDirectCompositingReasons();
 
   scroll_node.SetCcNodeId(new_sequence_number_, id);
 
-  scroll_tree_.SetScrollOffset(compositor_element_id,
-                               scroll_offset_translation.scroll_offset);
+  scroll_tree_.SetScrollOffset(
+      compositor_element_id, gfx::PointAtOffsetFromOrigin(
+                                 -scroll_translation_node.Get2dTranslation()));
 }
 
-int PropertyTreeManager::EnsureCompositorScrollNode(
+int PropertyTreeManager::EnsureCompositorScrollAndTransformNode(
     const TransformPaintPropertyNode& scroll_offset_translation) {
   // TODO(ScrollUnification): Remove this function and let
   // EnsureCompositorScrollNodes() call EnsureCompositorTransformNode() and
@@ -596,14 +636,16 @@
 
 int PropertyTreeManager::EnsureCompositorInnerScrollNode(
     const TransformPaintPropertyNode& scroll_offset_translation) {
-  int node_id = EnsureCompositorScrollNode(scroll_offset_translation);
+  int node_id =
+      EnsureCompositorScrollAndTransformNode(scroll_offset_translation);
   scroll_tree_.Node(node_id)->scrolls_inner_viewport = true;
   return node_id;
 }
 
 int PropertyTreeManager::EnsureCompositorOuterScrollNode(
     const TransformPaintPropertyNode& scroll_offset_translation) {
-  int node_id = EnsureCompositorScrollNode(scroll_offset_translation);
+  int node_id =
+      EnsureCompositorScrollAndTransformNode(scroll_offset_translation);
   scroll_tree_.Node(node_id)->scrolls_outer_viewport = true;
   return node_id;
 }
@@ -645,7 +687,7 @@
       root_layer_.property_tree_sequence_number());
   mask_layer->SetTransformTreeIndex(
       EnsureCompositorTransformNode(*current_.transform));
-  int scroll_id = EnsureCompositorScrollNode(
+  int scroll_id = EnsureCompositorScrollAndTransformNode(
       current_.transform->NearestScrollTranslationNode());
   mask_layer->SetScrollTreeIndex(scroll_id);
   mask_layer->SetClipTreeIndex(mask_effect.clip_id);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index 4f294c6..596c398 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -102,7 +102,7 @@
   int EnsureCompositorClipNode(const ClipPaintPropertyNode&);
   // Ensure the compositor scroll node using the associated scroll offset
   // translation.
-  int EnsureCompositorScrollNode(
+  int EnsureCompositorScrollAndTransformNode(
       const TransformPaintPropertyNode& scroll_offset_translation);
 
   // Same as above but marks the scroll nodes as being the viewport.
@@ -151,11 +151,15 @@
                                       CompositorElementId,
                                       const gfx::PointF&);
 
-  // Ensures a cc::ScrollNode for all scroll translations.
-  void EnsureCompositorScrollNodes(
+  // Ensures cc::ScrollNodes and cc::TransformNodes for all scroll translations.
+  void EnsureCompositorScrollTranslationNodes(
       const Vector<const TransformPaintPropertyNode*>&
           scroll_translation_nodes);
 
+  // Ensures a cc::ScrollNode for a scroll translation transform node.
+  void EnsureCompositorScrollNode(const ScrollPaintPropertyNode&,
+                                  const TransformPaintPropertyNode&);
+
   // Updates conditional render surface reasons for all effect nodes in
   // |GetEffectTree|. Every effect is supposed to have render surface enabled
   // for grouping, but we can omit a conditional render surface if it controls
@@ -290,13 +294,6 @@
                              const ClipPaintPropertyNode&,
                              const TransformPaintPropertyNode&);
 
-  // Should only be called from EnsureCompositorTransformNode as part of
-  // creating the associated scroll offset transform node.
-  void CreateCompositorScrollNode(
-      const ScrollPaintPropertyNode&,
-      const cc::TransformNode& scroll_offset_translation,
-      bool is_composited);
-
   void UpdatePixelMovingFilterClipExpanders();
 
   PropertyTreeManagerClient& client_;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
index cbf1a86..bd05b7b 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_chunker.cc
@@ -248,9 +248,13 @@
     // composited scrolling and should not have a scroll offset node.
     DCHECK(!scroll_translation);
   } else if (id.type == DisplayItem::Type::kScrollHitTest) {
-    DCHECK(scroll_translation);
-    // The scroll offset transform node should have an associated scroll node.
-    DCHECK(scroll_translation->ScrollNode());
+    // We might not have a scroll_translation node.  This indicates that
+    // (due to complex pointer-events cases) we need to do main thread
+    // scroll hit testing for this scroller.
+    if (scroll_translation) {
+      // The scroll offset transform node should have an associated scroll node.
+      DCHECK(scroll_translation->ScrollNode());
+    }
   } else {
     NOTREACHED();
   }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index a2e959db..f250093 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2225,12 +2225,6 @@
       base_feature: "none",
     },
     {
-      // When enabled, iframes are not capturing mouse events by default.
-      name: "MouseSubframeNoImplicitCapture",
-      base_feature: "none",
-      public: true,
-    },
-    {
       name: "NavigateEventCancelableTraversals",
       status: "stable",
     },
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink.py b/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink.py
index b7c7f81..a9022525 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink.py
@@ -18,6 +18,7 @@
 import requests
 
 from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
+from blinkpy.web_tests.models import test_failures
 from blinkpy.web_tests.models.typ_types import ResultType
 
 logging.getLogger("urllib3").setLevel(logging.WARNING)
@@ -129,6 +130,14 @@
             pair('web_tests_base_timeout',
                  str(int(self._port.timeout_ms() / 1000))),
         ]
+
+        # The hash allows `rebaseline-cl` to determine whether baselines are
+        # equal without needing to download the files.
+        if result.actual_image_hash:
+            tags.append(
+                pair(test_failures.FailureImage.ACTUAL_HASH_RDB_TAG,
+                     result.actual_image_hash))
+
         if (result.image_diff_stats and result.image_diff_stats.keys() >=
             {'maxDifference', 'totalPixels'}):
             tags.append(
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink_unittest.py b/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink_unittest.py
index 0e42097..a370549 100644
--- a/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/controllers/test_result_sink_unittest.py
@@ -13,8 +13,9 @@
 from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
 from blinkpy.web_tests.controllers.test_result_sink import CreateTestResultSink
 from blinkpy.web_tests.controllers.test_result_sink import TestResultSink
-from blinkpy.web_tests.models import test_results, failure_reason
+from blinkpy.web_tests.models import test_failures, test_results, failure_reason
 from blinkpy.web_tests.models.typ_types import ResultType
+from blinkpy.web_tests.port.driver import DriverOutput
 from blinkpy.web_tests.port.test import add_manifest_to_mock_filesystem
 from blinkpy.web_tests.port.test import TestPort
 from blinkpy.web_tests.port.test import MOCK_WEB_TESTS
@@ -218,10 +219,14 @@
         sent_data = self.sink(True, tr)
         self.assertEqual(sent_data['tags'], expected_tags)
 
-    def test_sink_with_image_diff_stats(self):
+    def test_sink_with_image_diff(self):
         actual_image_diff_stats = {'maxDifference': 20, 'totalPixels': 50}
+        failure = test_failures.FailureImageHashMismatch(
+            DriverOutput('', '', '321ea39', ''),
+            DriverOutput('', '', '42215dd', ''))
         tr = test_results.TestResult(test_name='test-name',
-                                     image_diff_stats=actual_image_diff_stats)
+                                     image_diff_stats=actual_image_diff_stats,
+                                     failures=[failure])
         tr.type = ResultType.Crash
         expected_tags = [
             {
@@ -245,6 +250,10 @@
                 'value': '6'
             },
             {
+                'key': 'web_tests_actual_image_hash',
+                'value': '321ea39',
+            },
+            {
                 'key': 'web_tests_image_diff_max_difference',
                 'value': '20'
             },
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_failures.py b/third_party/blink/tools/blinkpy/web_tests/models/test_failures.py
index 1e9a181..071224e 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/test_failures.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/test_failures.py
@@ -28,6 +28,7 @@
 import re
 import six
 from six.moves import cPickle
+from typing import ClassVar
 
 from blinkpy.web_tests.controllers import repaint_overlay
 from blinkpy.web_tests.models.typ_types import ResultType
@@ -535,6 +536,9 @@
 
 
 class FailureImage(ActualAndBaselineArtifacts):
+    # Tag key used to report the actual image's hash to ResultDB.
+    ACTUAL_HASH_RDB_TAG: ClassVar[str] = 'web_tests_actual_image_hash'
+
     def __init__(self, actual_driver_output, expected_driver_output):
         super(FailureImage, self).__init__(actual_driver_output,
                                            expected_driver_output)
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_results.py b/third_party/blink/tools/blinkpy/web_tests/models/test_results.py
index 9a4ca16..a3d885b3 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/test_results.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/test_results.py
@@ -26,6 +26,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+from typing import Optional
+
 from blinkpy.web_tests.models import test_failures
 from blinkpy.web_tests.models.typ_types import (
     Artifacts,
@@ -123,6 +125,13 @@
                                    ARTIFACTS_SUB_DIR,
                                    repeat_tests=self.repeat_tests)
 
+    @property
+    def actual_image_hash(self) -> Optional[str]:
+        for failure in self.failures:
+            if isinstance(failure, test_failures.FailureImage):
+                return failure.actual_driver_output.image_hash
+        return None
+
     def create_artifacts(self):
         for failure in self.failures:
             failure.create_artifacts(self.artifacts)
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 16e55f3..4b7c2be 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6687,3 +6687,5 @@
 # https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/4370249
 crbug.com/1427397 http/tests/devtools/persistence/persistence-navigator-unique-names.js [ Failure Pass ]
 
+# Sheriff 2023-02-24 Flaky
+crbug.com/1427576 external/wpt/soft-navigation-heuristics/navigation-api-view-transition.tentative.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 93ee71e..0c35f3f8 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -805,12 +805,15 @@
     "args": ["--disable-blink-features=ImportMaps"],
     "expires": "Jul 1, 2023"
   },
+  "The overlay-scrollbar virtual suite is testing a feature that is enabled",
+  "or not based on platform and settings, so it should not expire.",
   {
     "prefix": "overlay-scrollbar",
     "platforms": ["Linux", "Mac", "Win"],
-    "bases": [],
+    "bases": [ "external/wpt/css/css-ui/pointer-events-no-scrollbars-001.html",
+               "external/wpt/css/css-ui/pointer-events-no-scrollbars-002.html"],
     "args": ["--enable-features=OverlayScrollbar"],
-    "expires": "Jul 1, 2023"
+    "expires": "never"
   },
   {
     "prefix": "elastic-overscroll",
@@ -821,12 +824,14 @@
              "--enable-threaded-compositing"],
     "expires": "Jul 1, 2023"
   },
+  "The non-overlay-scrollbar virtual suite is testing a feature that is",
+  "enabled or not based on platform and settings, so it should not expire.",
   {
     "prefix": "non-overlay-scrollbar",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [],
     "args": ["--disable-features=OverlayScrollbar"],
-    "expires": "Jul 1, 2023"
+    "expires": "never"
   },
   {
     "prefix": "fluent-non-overlay-scrollbar",
diff --git a/third_party/blink/web_tests/WebDriverExpectations b/third_party/blink/web_tests/WebDriverExpectations
index e558b22d..791f0880 100644
--- a/third_party/blink/web_tests/WebDriverExpectations
+++ b/third_party/blink/web_tests/WebDriverExpectations
@@ -169,6 +169,9 @@
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/take_element_screenshot/screenshot.py>>test_no_such_element_from_other_window_handle[open] [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/print/orientation.py>>test_orientation[default] [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/print/orientation.py>>test_orientation[landscape] [ Failure ]
+crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/print/orientation.py>>test_orientation[portrait] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/maximize_window/stress.py>>test_stress[0] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/print/background.py>>test_background[False-iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2P4DwQACfsD/Z8fLAAAAAAASUVORK5CYII=] [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/webdriver/tests/print/background.py>>test_background[None-iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2P4DwQACfsD/Z8fLAAAAAAASUVORK5CYII=] [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/url/multi-global-origin-serialization.sub.html.ini b/third_party/blink/web_tests/external/wpt/FileAPI/url/multi-global-origin-serialization.sub.html.ini
index 2170a036..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/FileAPI/url/multi-global-origin-serialization.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/url/multi-global-origin-serialization.sub.html.ini
@@ -1,3 +1,2 @@
-[multi-global-origin-serialization.sub.html]
-  [Blob URL serialization (specifically the origin) in multi-global situations]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/__dir__.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/browsing-topics/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-default.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-default.tentative.https.sub.html.ini
deleted file mode 100644
index 30461eb..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-default.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[browsing-topics-permissions-policy-default.tentative.https.sub.html]
-  expected: TIMEOUT
-  [Default permissions policy allows document.browsingTopics() in cross-origin iframes.]
-    expected: TIMEOUT
-
-  [Default permissions policy allows document.browsingTopics() in same-origin iframes.]
-    expected: TIMEOUT
-
-  [Default permissions policy allows document.browsingTopics() in the current page.]
-    expected: FAIL
-
-  [Default permissions policyallows the 'Sec-Browsing-Topics' header to be sent for the cross-origin topics fetch request.]
-    expected: FAIL
-
-  [Default permissions policyallows the 'Sec-Browsing-Topics' header to be sent for the same-origin topics fetch request.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-none.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-none.tentative.https.sub.html.ini
deleted file mode 100644
index a8ba62cde..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-none.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[browsing-topics-permissions-policy-none.tentative.https.sub.html]
-  expected: TIMEOUT
-  [permissions policy header browsing-topics=() disallows document.browsingTopics() in cross-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header browsing-topics=() disallows document.browsingTopics() in same-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header browsing-topics=() disallows document.browsingTopics() in the current page.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-self.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-self.tentative.https.sub.html.ini
deleted file mode 100644
index a057cad..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/browsing-topics-permissions-policy-self.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[browsing-topics-permissions-policy-self.tentative.https.sub.html]
-  expected: TIMEOUT
-  [permissions policy header browsing-topics=(self) allows document.browsingTopics() in same-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header browsing-topics=(self) allows document.browsingTopics() in the current page.]
-    expected: FAIL
-
-  [permissions policy header browsing-topics=(self) disallows document.browsingTopics() in cross-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header browsing-topics=(self)allows the 'Sec-Browsing-Topics' header to be sent for the redirect of a topics fetch request, where the redirect has a same-origin URL.]
-    expected: FAIL
-
-  [permissions policy header browsing-topics=(self)allows the 'Sec-Browsing-Topics' header to be sent for the same-origin topics fetch request.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/document-api.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/document-api.tentative.https.html.ini
deleted file mode 100644
index 5c5c567..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/document-api.tentative.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[document-api.tentative.https.html]
-  [test document.browsingTopics()]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics-insecure-context.tentative.http.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics-insecure-context.tentative.http.html.ini
deleted file mode 100644
index c68eda5f..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics-insecure-context.tentative.http.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[fetch-topics-insecure-context.tentative.http.html]
-  [test fetch(<url>, {browsingTopics: true}) in insecure context]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics.tentative.https.html.ini
deleted file mode 100644
index c6db0c46..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/fetch-topics.tentative.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[fetch-topics.tentative.https.html]
-  [test fetch(<url>, {browsingTopics: true})]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/browsing-topics/xhr-topics.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/browsing-topics/xhr-topics.tentative.https.html.ini
deleted file mode 100644
index fa8ed1a..0000000
--- a/third_party/blink/web_tests/external/wpt/browsing-topics/xhr-topics.tentative.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[xhr-topics.tentative.https.html]
-  expected:
-    if product == "chrome": ERROR
-    TIMEOUT
-  [test XHR that sets the deprecatedBrowsingTopics attribtue]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/__dir__.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/compute-pressure/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_basic.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_basic.tentative.https.window.js.ini
deleted file mode 100644
index 5e812c1..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_basic.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_basic.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_cross_origin_focus_control.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_cross_origin_focus_control.tentative.https.window.js.ini
deleted file mode 100644
index ec03acb..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_cross_origin_focus_control.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_cross_origin_focus_control.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_detached_iframe.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_detached_iframe.tentative.https.html.ini
deleted file mode 100644
index 3543264..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_detached_iframe.tentative.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_detached_iframe.tentative.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect.tentative.https.window.js.ini
deleted file mode 100644
index 9dac40e..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_disconnect.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js.ini
deleted file mode 100644
index d5551cba..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_disconnect_idempotent.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js.ini
deleted file mode 100644
index be8007f0..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_disconnect_immediately.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple.tentative.https.window.js.ini
deleted file mode 100644
index 65aefe07c..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_multiple.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js.ini
deleted file mode 100644
index 56316afb..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_multiple_across_iframes.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js.ini
deleted file mode 100644
index e8b7158..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_observe_idempotent.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js.ini
deleted file mode 100644
index 5970aeaff..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_privacy_test.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_same_origin_focus_control.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_same_origin_focus_control.tentative.https.window.js.ini
deleted file mode 100644
index dc7f8d7..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_same_origin_focus_control.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_same_origin_focus_control.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_take_records.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_take_records.tentative.https.window.js.ini
deleted file mode 100644
index 94e875d..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/compute_pressure_take_records.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute_pressure_take_records.tentative.https.window.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html.ini
deleted file mode 100644
index cb3622ce5..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html.ini
deleted file mode 100644
index 58890f8..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute-pressure-allowed-by-permissions-policy-attribute.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.ini
deleted file mode 100644
index 016f839..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute-pressure-allowed-by-permissions-policy.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.ini
deleted file mode 100644
index 09ffe97..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html.ini b/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html.ini
deleted file mode 100644
index 743afa99..0000000
--- a/third_party/blink/web_tests/external/wpt/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[compute-pressure-default-permissions-policy.https.html]
-  expected: CRASH
diff --git a/third_party/blink/web_tests/external/wpt/credential-management/fedcm-multi-idp/__dir__.ini b/third_party/blink/web_tests/external/wpt/credential-management/fedcm-multi-idp/__dir__.ini
index 2e50c090..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/credential-management/fedcm-multi-idp/__dir__.ini
+++ b/third_party/blink/web_tests/external/wpt/credential-management/fedcm-multi-idp/__dir__.ini
@@ -1,3 +1,2 @@
-bug: crbug.com/1373766
-# Since enabling the multi IDP flag affects existing tests, we only enable the flag in the virtual multi IDP test suite
-disabled: neverfix
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/render-blocking/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-transitions/render-blocking/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/render-blocking/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001-ref.html
new file mode 100644
index 0000000..096eb16
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<title>CSS Test Reference: differences in pointer-events shouldn't cause overlay scrollbars to appear</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+
+<style>
+
+#scroll {
+  width: 200px;
+  height: 200px;
+  overflow: auto;
+}
+
+#big {
+  width: 500px;
+  height: 500px;
+}
+
+</style>
+
+
+<div id="scroll">
+  <div id="big">
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001.html b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001.html
new file mode 100644
index 0000000..fc438f7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-001.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<title>CSS Test: differences in pointer-events shouldn't cause overlay scrollbars to appear</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://drafts.csswg.org/css-ui-4/#pointer-events-control">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1414142">
+<meta name="assert" content="Differences in pointer-events shouldn't cause overlay scrollbars to appear.  (I concede this could perhaps be allowed by the wording in the spec that makes basically everything related to scrollbar rendering UA-defined.  However, there is no allowance for pointer-events affecting scrollbar rendering, so I think it's defensible.)">
+<link rel="match" href="pointer-events-no-scrollbars-001-ref.html">
+
+<style>
+
+#scroll {
+  width: 200px;
+  height: 200px;
+  overflow: auto;
+  pointer-events: none;
+}
+
+#big {
+  width: 500px;
+  height: 500px;
+}
+
+</style>
+
+
+<div id="scroll">
+  <div id="big">
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-002.html b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-002.html
new file mode 100644
index 0000000..1371c12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/pointer-events-no-scrollbars-002.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<title>CSS Test: dynamic changes to pointer-events shouldn't cause overlay scrollbars to appear</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://drafts.csswg.org/css-ui-4/#pointer-events-control">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1414142">
+<meta name="assert" content="Dynamic changes to pointer-events shouldn't cause overlay scrollbars to appear.  (I concede this could perhaps be allowed by the wording in the spec that makes basically everything related to scrollbar rendering UA-defined.  However, there is no allowance for pointer-events affecting scrollbar rendering, so I think it's defensible.)">
+<link rel="match" href="pointer-events-no-scrollbars-001-ref.html">
+
+<style>
+
+#scroll {
+  width: 200px;
+  height: 200px;
+  overflow: auto;
+}
+
+#big {
+  width: 500px;
+  height: 500px;
+}
+
+</style>
+
+
+<div id="scroll">
+  <div id="big">
+  </div>
+</div>
+
+<script>
+
+document.documentElement.addEventListener("TestRendered", (event) => {
+  document.getElementById("scroll").style.pointerEvents = "none";
+  document.documentElement.classList.remove("reftest-wait");
+});
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html.ini b/third_party/blink/web_tests/external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html.ini
index 13320f37..6980454 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/calc-in-media-queries-with-mixed-units.html.ini
@@ -1,4 +1,5 @@
 [calc-in-media-queries-with-mixed-units.html]
+  disabled: crbug.com/1385642
   expected: TIMEOUT
   [box should be orange if the calc between px/em in @media was correct]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini
deleted file mode 100644
index b1c35db..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-incoming.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[3d-transform-incoming.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini
deleted file mode 100644
index 68653b2..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/3d-transform-outgoing.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[3d-transform-outgoing.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/__dir__.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/break-inside-avoid-child.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/break-inside-avoid-child.html.ini
deleted file mode 100644
index da60c7b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/break-inside-avoid-child.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[break-inside-avoid-child.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini
deleted file mode 100644
index 3cce9c8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-smaller-than-box-size.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-smaller-than-box-size.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini
deleted file mode 100644
index c063e560..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-visibility-auto-shared-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-visibility-auto-shared-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-child-with-transparent-background.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-child-with-transparent-background.html.ini
deleted file mode 100644
index 49be5f6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-child-with-transparent-background.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-child-with-transparent-background.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini
deleted file mode 100644
index ac13765..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip-root.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-clip-root.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini
deleted file mode 100644
index 1e716b30..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-clip.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-clip.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini
deleted file mode 100644
index 675a9b6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-inline-child.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-inline-child.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini
deleted file mode 100644
index 7c516e26..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-new-image.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-transform-new-image.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-old-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-old-image.html.ini
deleted file mode 100644
index 54b268b2..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transform-old-image.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-transform-old-image.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transparent-background.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transparent-background.html.ini
deleted file mode 100644
index f1d3f61b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/content-with-transparent-background.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[content-with-transparent-background.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini
deleted file mode 100644
index f3ca790..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order-with-entry.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[css-tags-paint-order-with-entry.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini
deleted file mode 100644
index aff84d8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-paint-order.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[css-tags-paint-order.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini
deleted file mode 100644
index cd9dc58d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/css-tags-shared-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[css-tags-shared-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini
deleted file mode 100644
index 6504e802..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-rtl-iframe.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[dialog-in-rtl-iframe.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini
deleted file mode 100644
index 9510a5d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-new.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[dialog-in-top-layer-during-transition-new.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini
deleted file mode 100644
index e517627..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/dialog-in-top-layer-during-transition-old.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[dialog-in-top-layer-during-transition-old.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini
deleted file mode 100644
index ca2f15cb..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/duplicate-tag-rejects-start.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[duplicate-tag-rejects-start.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini
deleted file mode 100644
index c951c41..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/element-with-overflow.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[element-with-overflow.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini
deleted file mode 100644
index 54a3b0b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/event-pseudo-name.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[event-pseudo-name.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini
deleted file mode 100644
index 571e9dde..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/far-away-capture.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[far-away-capture.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-position.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-position.html.ini
deleted file mode 100644
index 9c2084c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-position.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[fractional-translation-from-position.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-transform.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-transform.html.ini
deleted file mode 100644
index 0060853..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fractional-translation-from-transform.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[fractional-translation-from-transform.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini
deleted file mode 100644
index 2277d0b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element-from-point.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[hit-test-unpainted-element-from-point.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini
deleted file mode 100644
index 2c96cdb..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unpainted-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[hit-test-unpainted-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini
deleted file mode 100644
index 15f4827..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/hit-test-unrelated-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[hit-test-unrelated-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-new-has-scrollbar.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-new-has-scrollbar.html.ini
deleted file mode 100644
index 11c22f7..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-new-has-scrollbar.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[iframe-new-has-scrollbar.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-old-has-scrollbar.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-old-has-scrollbar.html.ini
deleted file mode 100644
index 0aeae5c8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/iframe-old-has-scrollbar.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[iframe-old-has-scrollbar.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-filter.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-filter.html.ini
deleted file mode 100644
index 577914e..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-filter.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[inline-child-with-filter.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini
deleted file mode 100644
index 634fd7c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/japanese-tag.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[japanese-tag.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini
deleted file mode 100644
index 003683c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/mix-blend-mode-only-on-transition.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[mix-blend-mode-only-on-transition.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-new.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-new.html.ini
deleted file mode 100644
index 75e8cbc0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-new.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[named-element-with-fix-pos-child-new.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-old.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-old.html.ini
deleted file mode 100644
index 45bc9ae0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-old.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[named-element-with-fix-pos-child-old.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini
deleted file mode 100644
index 3e11e97..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-and-old-sizes-match.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-and-old-sizes-match.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini
deleted file mode 100644
index 3161141..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-clip-path.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-captures-clip-path.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-different-size.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-different-size.html.ini
deleted file mode 100644
index c9555ba..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-different-size.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-captures-different-size.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini
deleted file mode 100644
index 50a4dd3..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-opacity.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[new-content-captures-opacity.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-positioned-spans.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-positioned-spans.html.ini
deleted file mode 100644
index eb37342..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-positioned-spans.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-captures-positioned-spans.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini
deleted file mode 100644
index 13e3cd0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-root.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-captures-root.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-spans.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-spans.html.ini
deleted file mode 100644
index b3699b43..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-captures-spans.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-captures-spans.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini
deleted file mode 100644
index ace8cd4..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-container-writing-modes.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-container-writing-modes.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini
deleted file mode 100644
index e858be9..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-element-writing-modes.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-element-writing-modes.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-from-root-display-none.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-from-root-display-none.html.ini
deleted file mode 100644
index 47430f9d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-from-root-display-none.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-from-root-display-none.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini
deleted file mode 100644
index 7b82b64..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-intrinsic-aspect-ratio.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[new-content-intrinsic-aspect-ratio.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini
deleted file mode 100644
index 0805b5f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-empty-div.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-is-empty-div.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-inline.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-inline.html.ini
deleted file mode 100644
index 15ff38a1..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-is-inline.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[new-content-is-inline.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini
deleted file mode 100644
index 52659a9..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-fill.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-fit-fill.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini
deleted file mode 100644
index 6dc0cdb7..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-fit-none.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-fit-none.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini
deleted file mode 100644
index 1984cf88e..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path-reference.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-view-box-clip-path-reference.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini
deleted file mode 100644
index fcbd352c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-clip-path.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-view-box-clip-path.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini
deleted file mode 100644
index 98577071..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow-clipped.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-view-box-overflow-clipped.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini
deleted file mode 100644
index aa69eb6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-object-view-box-overflow.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-object-view-box-overflow.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini
deleted file mode 100644
index 750c7e9..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-scaling.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-scaling.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini
deleted file mode 100644
index c9ece9e..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow-zoomed.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-with-overflow-zoomed.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini
deleted file mode 100644
index 21c88d0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-content-with-overflow.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-content-with-overflow.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini
deleted file mode 100644
index f8e58c93..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-element-on-start.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-element-on-start.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini
deleted file mode 100644
index b14891c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/new-root-vertical-writing-mode.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[new-root-vertical-writing-mode.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini
deleted file mode 100644
index 379db908..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-crash-set-exception.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[no-crash-set-exception.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-css-animation-while-render-blocked.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-css-animation-while-render-blocked.html.ini
deleted file mode 100644
index f9dd1b3..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-css-animation-while-render-blocked.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-css-animation-while-render-blocked.html]
-  [CSS animation is blocked until prepare callback]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-raf-while-render-blocked.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-raf-while-render-blocked.html.ini
deleted file mode 100644
index aa486fbec..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-raf-while-render-blocked.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[no-raf-while-render-blocked.html]
-  [rAF is blocked until prepare callback]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini
deleted file mode 100644
index 6ebe0a8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/no-root-capture.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[no-root-capture.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini
deleted file mode 100644
index 08e6ad58d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/nothing-captured.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[nothing-captured.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini
deleted file mode 100644
index 42f3adb..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-new-image.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[object-view-box-new-image.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-old-image.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-old-image.html.ini
deleted file mode 100644
index 098e0820..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/object-view-box-old-image.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[object-view-box-old-image.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini
deleted file mode 100644
index cb2f8f96..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-clip-path.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[old-content-captures-clip-path.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-different-size.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-different-size.html.ini
deleted file mode 100644
index 782de8a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-different-size.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-captures-different-size.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini
deleted file mode 100644
index 9f85816..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-opacity.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-captures-opacity.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini
deleted file mode 100644
index a3dcab0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-captures-root.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-captures-root.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini
deleted file mode 100644
index c04c996..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-container-writing-modes.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-container-writing-modes.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini
deleted file mode 100644
index b4e27b1..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-element-writing-modes.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-element-writing-modes.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-has-scrollbars.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-has-scrollbars.html.ini
deleted file mode 100644
index fb5a3b7..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-has-scrollbars.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-has-scrollbars.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini
deleted file mode 100644
index 417cab1d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-intrinsic-aspect-ratio.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini
deleted file mode 100644
index 62e7064..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-empty-div.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-is-empty-div.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-inline.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-inline.html.ini
deleted file mode 100644
index 3ffc20a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-is-inline.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[old-content-is-inline.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini
deleted file mode 100644
index d0a1e3e..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-fill.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-object-fit-fill.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini
deleted file mode 100644
index ba99e88cc..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-fit-none.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-object-fit-none.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini
deleted file mode 100644
index c832fdb..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path-reference.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-object-view-box-clip-path-reference.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini
deleted file mode 100644
index 19f48b6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-clip-path.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-object-view-box-clip-path.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini
deleted file mode 100644
index 9eda867c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-object-view-box-overflow.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-object-view-box-overflow.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini
deleted file mode 100644
index 14e266f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow-zoomed.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-with-overflow-zoomed.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini
deleted file mode 100644
index b6234bc3..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-content-with-overflow.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-content-with-overflow.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini
deleted file mode 100644
index b7caf2d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/old-root-vertical-writing-mode.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[old-root-vertical-writing-mode.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-group.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-group.html.ini
deleted file mode 100644
index 6f2b200..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-group.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-group.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-image-pair.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-image-pair.html.ini
deleted file mode 100644
index ba2cc8a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-image-pair.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-image-pair.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-new.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-new.html.ini
deleted file mode 100644
index 4acc4b1b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-new.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-new.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-old.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-old.html.ini
deleted file mode 100644
index 452b88e..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-old.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-old.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-on-root-element-with-view-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-on-root-element-with-view-transition.html.ini
deleted file mode 100644
index 3a8bc30..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-on-root-element-with-view-transition.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-on-root-element-with-view-transition.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-view-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-view-transition.html.ini
deleted file mode 100644
index b628f29..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/only-child-view-transition.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[only-child-view-transition.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini
deleted file mode 100644
index 61e72a6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/paused-animation-at-end.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[paused-animation-at-end.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini
deleted file mode 100644
index aecea327..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-computed-style-stays-in-sync-with-new-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pseudo-computed-style-stays-in-sync-with-new-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini
deleted file mode 100644
index 2e63cf5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/pseudo-get-computed-style.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pseudo-get-computed-style.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini
deleted file mode 100644
index 6564fe6d..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/ready_resolves_after_dom_before_raf.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[ready_resolves_after_dom_before_raf.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini
deleted file mode 100644
index 8bef666..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-captured-as-different-tag.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-captured-as-different-tag.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html.ini
deleted file mode 100644
index 626705a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-display-none-crash.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-during-transition-crash.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-during-transition-crash.html.ini
deleted file mode 100644
index 41d3e40..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-during-transition-crash.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-display-none-during-transition-crash.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini
deleted file mode 100644
index 6967b0a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-scrollbar-with-fixed-background.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-scrollbar-with-fixed-background.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini
deleted file mode 100644
index 374d7df3..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-style-change-during-animation.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-style-change-during-animation.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini
deleted file mode 100644
index 1d6e3bc..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-end.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-to-shared-animation-end.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini
deleted file mode 100644
index d8098732..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-incoming.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[root-to-shared-animation-incoming.html]
-  expected:
-    if product == "chrome": FAIL
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini
deleted file mode 100644
index 6febe25..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-to-shared-animation-start.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-to-shared-animation-start.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini
deleted file mode 100644
index 76ca4c5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/rtl-with-scrollbar.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[rtl-with-scrollbar.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child-abspos.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child-abspos.html.ini
deleted file mode 100644
index a100e4cc..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child-abspos.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scroller-child-abspos.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child.html.ini
deleted file mode 100644
index b35d4d8..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller-child.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scroller-child.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller.html.ini
deleted file mode 100644
index 33022d5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/scroller.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[scroller.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time-transform.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time-transform.html.ini
deleted file mode 100644
index 7a35a38..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time-transform.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[set-current-time-transform.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html.ini
deleted file mode 100644
index b245ed529..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-current-time.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[set-current-time.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini
deleted file mode 100644
index fa049794..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/set-universal-specificity.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[set-universal-specificity.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini
deleted file mode 100644
index 824d26f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/style-inheritance.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[style-inheritance.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transform-origin-view-transition-group.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transform-origin-view-transition-group.html.ini
deleted file mode 100644
index 280c4bf..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transform-origin-view-transition-group.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[transform-origin-view-transition-group.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-in-empty-iframe.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-in-empty-iframe.html.ini
deleted file mode 100644
index 124b6b5..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-in-empty-iframe.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[transition-in-empty-iframe.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini
deleted file mode 100644
index e0ca5a48..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-after-animation-started.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[transition-skipped-after-animation-started.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini
deleted file mode 100644
index a1413e6c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/transition-skipped-from-invalid-callback.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[transition-skipped-from-invalid-callback.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini
deleted file mode 100644
index 7010a00..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/unset-and-initial-view-transition-name.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[unset-and-initial-view-transition-name.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html.ini
deleted file mode 100644
index 485ca4c..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-is-backdrop-filter-root.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[view-transition-name-is-backdrop-filter-root.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini
deleted file mode 100644
index bb4296f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-on-removed-element.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[view-transition-name-on-removed-element.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-removed-mid-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-removed-mid-transition.html.ini
deleted file mode 100644
index ab9a6d49..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/view-transition-name-removed-mid-transition.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[view-transition-name-removed-mid-transition.html]
-  expected:
-    if product == "chrome": PASS
-    TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animation-pseudo-incorrect-name.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animation-pseudo-incorrect-name.html.ini
deleted file mode 100644
index 8a67842..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animation-pseudo-incorrect-name.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[web-animation-pseudo-incorrect-name.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini
deleted file mode 100644
index 038359f..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/web-animations-api.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[web-animations-api.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini
deleted file mode 100644
index 1a98a8d9..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/window-resize-aborts-transition.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[window-resize-aborts-transition.html]
-  expected: ERROR
-  [View transitions: Resizing viewport skips the transition]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scroll-behavior-smooth-navigation.html.ini b/third_party/blink/web_tests/external/wpt/css/cssom-view/scroll-behavior-smooth-navigation.html.ini
index 9a8b1583..c7ad3e1 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scroll-behavior-smooth-navigation.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/scroll-behavior-smooth-navigation.html.ini
@@ -1,4 +1,5 @@
 [scroll-behavior-smooth-navigation.html]
+  disabled: crbug.com/1289222
   expected:
     if product == "chrome": [TIMEOUT, ERROR]
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/media-loading-pseudo-classes-in-has.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/media-loading-pseudo-classes-in-has.html.ini
index 636911e..5e6e6b9b 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/media-loading-pseudo-classes-in-has.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/media-loading-pseudo-classes-in-has.html.ini
@@ -1,4 +1,5 @@
 [media-loading-pseudo-classes-in-has.html]
+  disabled: crbug.com/1383480
   expected: TIMEOUT
   [Test :has(:buffering) invalidation]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/media/media-loading-state.html.ini b/third_party/blink/web_tests/external/wpt/css/selectors/media/media-loading-state.html.ini
index 7c51c0b..679b1281 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/media/media-loading-state.html.ini
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/media/media-loading-state.html.ini
@@ -1,4 +1,5 @@
 [media-loading-state.html]
+  disabled: crbug.com/1377648
   expected: TIMEOUT
   [Test :buffering pseudo-class]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/direct-sockets/__dir__.ini b/third_party/blink/web_tests/external/wpt/direct-sockets/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/direct-sockets/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/direct-sockets/disabled-by-permissions-policy.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/direct-sockets/disabled-by-permissions-policy.https.sub.html.ini
deleted file mode 100644
index baaf80b..0000000
--- a/third_party/blink/web_tests/external/wpt/direct-sockets/disabled-by-permissions-policy.https.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[disabled-by-permissions-policy.https.sub.html]
-  [tcp disabled by permissions-policy]
-    expected: FAIL
-
-  [udp disabled by permissions-policy]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-1.sub.html.ini b/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-1.sub.html.ini
index d12622e..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-1.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-1.sub.html.ini
@@ -1,2 +1,2 @@
-[EventListener-incumbent-global-1.sub.html]
-  expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-2.sub.html.ini b/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-2.sub.html.ini
index b57ee911..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-2.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/events/EventListener-incumbent-global-2.sub.html.ini
@@ -1,2 +1,2 @@
-[EventListener-incumbent-global-2.sub.html]
-  expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-1.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-1.html.ini
index 08e2974d..1a1fc93 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-1.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-1.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-1.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-2.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-2.html.ini
index 2d4abf3..2872c6a 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-2.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-2.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-2.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3.html.ini
index bf5f6e3..840ccb5c 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-3.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-3.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html.ini
index 5819f10..be45274 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-indexOf-1.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html.ini
index 9bea2f5..5514f81e 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-indexOf-2.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html.ini b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html.ini
index 9b30c5ec..d34deac 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html.ini
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html.ini
@@ -1,2 +1,2 @@
 [NodeList-static-length-getter-tampered-indexOf-3.html]
-  expected: TIMEOUT
+  disabled: crbug.com/1357443
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/__dir__.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/http-cache/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/basic-auth-cache-test.html.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/basic-auth-cache-test.html.ini
deleted file mode 100644
index 8d375b1..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/basic-auth-cache-test.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[basic-auth-cache-test.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js.ini
deleted file mode 100644
index b0c5235e..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cache-mode.any.js.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[cache-mode.any.html]
-  [Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store]
-    expected: FAIL
-
-
-[cache-mode.any.serviceworker.html]
-  [Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store]
-    expected: FAIL
-
-
-[cache-mode.any.sharedworker.html]
-  [Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store]
-    expected: FAIL
-
-
-[cache-mode.any.worker.html]
-  [Fetch sends Cache-Control: no-cache and Pragma: no-cache when cache mode is no-store]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js.ini
deleted file mode 100644
index 45543f8..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/cc-request.any.js.ini
+++ /dev/null
@@ -1,102 +0,0 @@
-[cc-request.any.html]
-  [HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1]
-    expected: FAIL
-
-  [HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness]
-    expected: FAIL
-
-  [HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached]
-    expected: FAIL
-
-
-[cc-request.any.serviceworker.html]
-  [HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1]
-    expected: FAIL
-
-  [HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness]
-    expected: FAIL
-
-  [HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached]
-    expected: FAIL
-
-
-[cc-request.any.sharedworker.html]
-  [HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1]
-    expected: FAIL
-
-  [HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness]
-    expected: FAIL
-
-  [HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached]
-    expected: FAIL
-
-
-[cc-request.any.worker.html]
-  [HTTP cache does reuse stale response with Age header when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache does use aged stale response when request contains Cache-Control: max-stale that permits its use]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response when request contains Cache-Control: no-store]
-    expected: FAIL
-
-  [HTTP cache doesn't reuse fresh response with Age header when request contains Cache-Control: min-fresh that wants it fresher]
-    expected: FAIL
-
-  [HTTP cache doesn't use aged but fresh response when request contains Cache-Control: max-age=1]
-    expected: FAIL
-
-  [HTTP cache doesn't use fresh response with Age header when request contains Cache-Control: max-age that is greater than remaining freshness]
-    expected: FAIL
-
-  [HTTP cache generates 504 status code when nothing is in cache and request contains Cache-Control: only-if-cached]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/credentials.tentative.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/credentials.tentative.any.js.ini
deleted file mode 100644
index ce32874..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/credentials.tentative.any.js.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[credentials.tentative.any.html]
-  [same-origin: 2xAnonymous, 2xCredentialled, 1xAnonymous]
-    expected: FAIL
-
-  [same-origin: 2xCredentialled, 2xAnonymous, 1xCredentialled]
-    expected: FAIL
-
-
-[credentials.tentative.any.serviceworker.html]
-  [same-origin: 2xAnonymous, 2xCredentialled, 1xAnonymous]
-    expected: FAIL
-
-  [same-origin: 2xCredentialled, 2xAnonymous, 1xCredentialled]
-    expected: FAIL
-
-
-[credentials.tentative.any.sharedworker.html]
-  [same-origin: 2xAnonymous, 2xCredentialled, 1xAnonymous]
-    expected: FAIL
-
-  [same-origin: 2xCredentialled, 2xAnonymous, 1xCredentialled]
-    expected: FAIL
-
-
-[credentials.tentative.any.worker.html]
-  [same-origin: 2xAnonymous, 2xCredentialled, 1xAnonymous]
-    expected: FAIL
-
-  [same-origin: 2xCredentialled, 2xAnonymous, 1xCredentialled]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js.ini
deleted file mode 100644
index 015c1ee..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/heuristic.any.js.ini
+++ /dev/null
@@ -1,78 +0,0 @@
-[heuristic.any.html]
-  [HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present]
-    expected: FAIL
-
-
-[heuristic.any.serviceworker.html]
-  [HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present]
-    expected: FAIL
-
-
-[heuristic.any.sharedworker.html]
-  [HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present]
-    expected: FAIL
-
-
-[heuristic.any.worker.html]
-  [HTTP cache reuses a 204 No Content response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 404 Not Found response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 405 Method Not Allowed response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 414 URI Too Long response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses a 501 Not Implemented response with Last-Modified based upon heuristic freshness]
-    expected: FAIL
-
-  [HTTP cache reuses an unknown response with Last-Modified based upon heuristic freshness when Cache-Control: public is present]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js.ini
deleted file mode 100644
index c7a0176e..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/invalidate.any.js.ini
+++ /dev/null
@@ -1,114 +0,0 @@
-[invalidate.any.html]
-  [HTTP cache invalidates Content-Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates after a successful response from an unknown method]
-    expected: FAIL
-
-
-[invalidate.any.serviceworker.html]
-  [HTTP cache invalidates Content-Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates after a successful response from an unknown method]
-    expected: FAIL
-
-
-[invalidate.any.sharedworker.html]
-  [HTTP cache invalidates Content-Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates after a successful response from an unknown method]
-    expected: FAIL
-
-
-[invalidate.any.worker.html]
-  [HTTP cache invalidates Content-Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Content-Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a DELETE]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a POST]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from a PUT]
-    expected: FAIL
-
-  [HTTP cache invalidates Location URL after a successful response from an unknown method]
-    expected: FAIL
-
-  [HTTP cache invalidates after a successful response from an unknown method]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js.ini
deleted file mode 100644
index b54e0bba..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/partial.any.js.ini
+++ /dev/null
@@ -1,78 +0,0 @@
-[partial.any.html]
-  [HTTP cache stores complete response and serves smaller ranges from it with only-if-cached]
-    expected: FAIL
-
-  [HTTP cache stores partial content and completes it]
-    expected: FAIL
-
-  [HTTP cache stores partial content and reuses it]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)]
-    expected: FAIL
-
-
-[partial.any.serviceworker.html]
-  [HTTP cache stores complete response and serves smaller ranges from it with only-if-cached]
-    expected: FAIL
-
-  [HTTP cache stores partial content and completes it]
-    expected: FAIL
-
-  [HTTP cache stores partial content and reuses it]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)]
-    expected: FAIL
-
-
-[partial.any.sharedworker.html]
-  [HTTP cache stores complete response and serves smaller ranges from it with only-if-cached]
-    expected: FAIL
-
-  [HTTP cache stores partial content and completes it]
-    expected: FAIL
-
-  [HTTP cache stores partial content and reuses it]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)]
-    expected: FAIL
-
-
-[partial.any.worker.html]
-  [HTTP cache stores complete response and serves smaller ranges from it with only-if-cached]
-    expected: FAIL
-
-  [HTTP cache stores partial content and completes it]
-    expected: FAIL
-
-  [HTTP cache stores partial content and reuses it]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (absent last-byte-pos)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (byte-range-spec)]
-    expected: FAIL
-
-  [HTTP cache stores partial response and serves smaller ranges from it (suffix-byte-range-spec)]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js.ini
deleted file mode 100644
index 7235595b..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/post-patch.any.js.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[post-patch.any.html]
-  [HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-  [HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-
-[post-patch.any.serviceworker.html]
-  [HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-  [HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-
-[post-patch.any.sharedworker.html]
-  [HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-  [HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-
-[post-patch.any.worker.html]
-  [HTTP cache uses content after PATCH request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
-
-  [HTTP cache uses content after POST request with response containing Content-Location and cache-allowing header]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/split-cache.html.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/split-cache.html.ini
deleted file mode 100644
index 1285b9a..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/split-cache.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[split-cache.html]
-  [HTTP cache is not shared between cross-site top-level frames]
-    expected: FAIL
-
-  [HTTP cache is not shared between same-site frames with cross-site top-level frames]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js.ini b/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js.ini
deleted file mode 100644
index d24ff6d..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/http-cache/vary.any.js.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[vary.any.html]
-  [HTTP cache doesn't invalidate existing Vary response]
-    expected: FAIL
-
-
-[vary.any.serviceworker.html]
-  [HTTP cache doesn't invalidate existing Vary response]
-    expected: FAIL
-
-
-[vary.any.sharedworker.html]
-  [HTTP cache doesn't invalidate existing Vary response]
-    expected: FAIL
-
-
-[vary.any.worker.html]
-  [HTTP cache doesn't invalidate existing Vary response]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.https.sub.tentative.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
index b5e15623..ebc6ecb7 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.https.sub.tentative.html.ini
@@ -1,4 +1,5 @@
 [css-images.https.sub.tentative.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [background-image sec-fetch-dest]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.sub.tentative.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.sub.tentative.html.ini
index ed2900aa..944272a7 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.sub.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/css-images.sub.tentative.html.ini
@@ -1,4 +1,5 @@
 [css-images.sub.tentative.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [background-image sec-fetch-site - HTTPS downgrade-upgrade]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.https.sub.html.ini
index a5b6fbc..eca4f97b 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.https.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.https.sub.html.ini
@@ -1,4 +1,5 @@
 [element-link-icon.https.sub.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [sec-fetch-dest no attributes]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.sub.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.sub.html.ini
index 965fcd578..3798f45 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-link-icon.sub.html.ini
@@ -1,4 +1,5 @@
 [element-link-icon.sub.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [sec-fetch-dest - Not sent to non-trustworthy cross-site destination no attributes]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-video-poster.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-video-poster.https.sub.html.ini
index 3e0f431..e620d8b9 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-video-poster.https.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/generated/element-video-poster.https.sub.html.ini
@@ -1,4 +1,5 @@
 [element-video-poster.https.sub.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [sec-fetch-dest]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/fetch/metadata/portal.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/fetch/metadata/portal.https.sub.html.ini
index a3f0e995..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/metadata/portal.https.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/fetch/metadata/portal.https.sub.html.ini
@@ -1,9 +1,2 @@
-[portal.https.sub.html]
-  [web-platform.test -> web-platform.test:8444 portal]
-    expected: FAIL
-
-  [web-platform.test -> www.not-web-platform.test:8444 portal]
-    expected: FAIL
-
-  [web-platform.test -> www.web-platform.test:8444 portal]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/__dir__.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/forced-colors-mode/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-01.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-01.html.ini
deleted file mode 100644
index 57f193d..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-01.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-01.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-02.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-02.html.ini
deleted file mode 100644
index ea9dfba..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-02.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-02.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-03.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-03.html.ini
deleted file mode 100644
index 428bb754..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-03.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-03.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-04.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-04.html.ini
deleted file mode 100644
index bc50ee0..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-04.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-04.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-05.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-05.html.ini
deleted file mode 100644
index 3ac20f6..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-05.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-05.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-06.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-06.html.ini
deleted file mode 100644
index a595ec21..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-06.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-06.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-08.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-08.html.ini
deleted file mode 100644
index d71f9086..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-08.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-08.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-09.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-09.html.ini
deleted file mode 100644
index 50d4731..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-09.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-09.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-10.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-10.html.ini
deleted file mode 100644
index e4ac4d5..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/backplate/forced-colors-mode-backplate-10.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-backplate-10.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-01.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-01.html.ini
deleted file mode 100644
index 4ac584c..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-01.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-01.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-02.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-02.html.ini
deleted file mode 100644
index 5b9e05e..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-02.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-02.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-03.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-03.html.ini
deleted file mode 100644
index 23926217c..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-03.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-03.html]
-  [Checks that default highlighted text style does not get overridden in forced colors mode.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-05.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-05.html.ini
deleted file mode 100644
index be9d8aa..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-05.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-05.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-06.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-06.html.ini
deleted file mode 100644
index ff878a0..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-06.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-06.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-07.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-07.html.ini
deleted file mode 100644
index f441753..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-07.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-07.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-08.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-08.html.ini
deleted file mode 100644
index d5b8d4b3..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-08.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-08.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-09.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-09.html.ini
deleted file mode 100644
index 3380831..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-09.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-09.html]
-  [Checks that styles defined inside/outside forced-colors are overridden in forced colors mode.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-10.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-10.html.ini
deleted file mode 100644
index 57d1b8e..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-10.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-10.html]
-  [Checks that styles defined inside/outside forced-colors are preserved in forced colors mode if forced-color-ajust is none.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-11.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-11.html.ini
deleted file mode 100644
index 9bb3095..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-11.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-11.html]
-  [Checks that styles defined in forced-colors are preserved in forced colors mode.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-14.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-14.html.ini
deleted file mode 100644
index da584ff..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-14.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-14.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-17.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-17.html.ini
deleted file mode 100644
index 7844e04..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-17.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-17.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-18.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-18.html.ini
deleted file mode 100644
index 2bdec090..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-18.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-18.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-19.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-19.html.ini
deleted file mode 100644
index 0f2e76c..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-19.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-19.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-20.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-20.html.ini
deleted file mode 100644
index 8c5fe2f2..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-20.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-20.html]
-  [Checks that background color alpha channels are preserved in forced colors mode.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-21.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-21.html.ini
deleted file mode 100644
index cbee269..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-21.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-21.html]
-  [Checks that background color alpha channels are preserved in forced colors mode at the root node.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-23.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-23.html.ini
deleted file mode 100644
index 5288de6..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-23.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-23.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-26.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-26.html.ini
deleted file mode 100644
index e88883b..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-26.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-26.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-27.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-27.html.ini
deleted file mode 100644
index 4003157..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-27.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-27.html]
-  [Checks that html/head color is overridden to CanvasText.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-28.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-28.html.ini
deleted file mode 100644
index c7390e9..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-28.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-28.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-33.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-33.html.ini
deleted file mode 100644
index 71ef8de4..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-33.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-33.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-35.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-35.html.ini
deleted file mode 100644
index 962ec13..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-35.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-35.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-37.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-37.html.ini
deleted file mode 100644
index edac8330..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-37.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-37.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html.ini
deleted file mode 100644
index 0a79777..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-39.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-41.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-41.html.ini
deleted file mode 100644
index 9540192..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-41.html.ini
+++ /dev/null
@@ -1,27 +0,0 @@
-[forced-colors-mode-41.html]
-  [Forced colors affects the resolved value of accent-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of background-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of border-bottom-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of border-left-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of border-right-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of border-top-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of caret-color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of color]
-    expected: FAIL
-
-  [Forced colors affects the resolved value of outline-color]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-42.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-42.html.ini
deleted file mode 100644
index 17b44bc..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-42.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-42.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-43.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-43.html.ini
deleted file mode 100644
index fc85295..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-43.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-43.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-46.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-46.html.ini
deleted file mode 100644
index 2120a4a..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-46.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-46.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-49.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-49.html.ini
deleted file mode 100644
index 2167ed45..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-49.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-49.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-50.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-50.html.ini
deleted file mode 100644
index be7a2ad..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-50.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-50.html]
-  [Accent-color computes to auto in forced colors mode, unless forced-color-adjust is none or accent-color is a system color.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html.ini
deleted file mode 100644
index d36cc36..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[forced-colors-mode-51.html]
-  [Color-scheme computes to 'light dark' in forced colors mode, unless forced-color-adjust is none.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-52.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-52.html.ini
deleted file mode 100644
index 1428d55d..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-52.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-52.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-53.html.ini b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-53.html.ini
deleted file mode 100644
index 6c166a60..0000000
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-53.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[forced-colors-mode-53.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.https.window.html.ini b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.https.window.html.ini
new file mode 100644
index 0000000..c055041
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.https.window.html.ini
@@ -0,0 +1,2 @@
+disabled:
+  crbug.com/626703 slow timeout test
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html.ini
index 5f67327..f73cb132 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html.ini
@@ -1,4 +1,5 @@
 [joint-session-history-remove-iframe.html]
+  disabled: crbug.com/1317067
   expected:
     if product == "chrome": ERROR
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html.ini
index ea72d8f..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html.ini
@@ -1,9 +1,2 @@
-[allow_prototype_cycle_through_location.sub.html]
-  [cross-origin, but joined via document.domain, location cycle]
-    expected: FAIL
-
-  [same-origin, different-window location cycle]
-    expected: FAIL
-
-  [same-origin, same-window location cycle]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-same-origin-domain.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-same-origin-domain.sub.html.ini
index ed2001b..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-same-origin-domain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-same-origin-domain.sub.html.ini
@@ -1,7 +1,2 @@
-[location-prototype-setting-same-origin-domain.sub.html]
-  expected: ERROR
-  [Same-origin-domain prerequisite check: the original prototype is accessible]
-    expected: FAIL
-
-  [Same-origin-domain: setting the prototype to an empty object via Object.setPrototypeOf should throw a TypeError]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
index 90a1ea48..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects-on-new-window.html.ini
@@ -1,3 +1,2 @@
-[cross-origin-objects-on-new-window.html]
-  [Cross-origin object identity preserved across document.domain]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-no-child-bad-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-no-child-bad-subdomain.sub.https.html.ini
deleted file mode 100644
index 00d1f68b..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-no-child-bad-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[parent-no-child-bad-subdomain.sub.https.html]
-  ["": setting document.domain must give sync access]
-    expected: FAIL
-
-  [""?1"": setting document.domain must give sync access]
-    expected: FAIL
-
-  ["(?1)": setting document.domain must give sync access]
-    expected: FAIL
-
-  ["1": setting document.domain must give sync access]
-    expected: FAIL
-
-  ["?0": setting document.domain must give sync access]
-    expected: FAIL
-
-  ["?2": setting document.domain must give sync access]
-    expected: FAIL
-
-  ["true": setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-port.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-port.sub.https.html.ini
deleted file mode 100644
index 4f4d238..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-port.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child-no-port.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
-
-  [setting document.domain must not give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-same.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-same.sub.https.html.ini
deleted file mode 100644
index 1c67ab6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-same.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child-no-same.sub.https.html]
-  [child: originAgentCluster must equal true]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-subdomain.sub.https.html.ini
deleted file mode 100644
index 3c86f1b6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-no-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child-no-subdomain.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
-
-  [setting document.domain must not give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-port.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-port.sub.https.html.ini
deleted file mode 100644
index d2351d6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-port.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child-yes-port.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-same.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-same.sub.https.html.ini
deleted file mode 100644
index c5b3057..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-same.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child-yes-same.sub.https.html]
-  [child: originAgentCluster must equal true]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index 645ab5c..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-yes-child-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child-yes-subdomain.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index 25741a3..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-no-child1-no-subdomain-child2-yes-subdomain.sub.https.html]
-  [Parent to child1: setting document.domain must give sync access]
-    expected: FAIL
-
-  [Parent to child2: setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini
deleted file mode 100644
index 6328e43..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-no-child1-no-subdomain-child2-yes-subdomainport.sub.https.html]
-  [Parent to child1: setting document.domain must give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal false]
-    expected: [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html.ini
deleted file mode 100644
index 7f4e06fc..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-no-child1-no-subdomain1-child2-yes-subdomain2.sub.https.html]
-  [Parent to child1: setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain.sub.https.html.ini
deleted file mode 100644
index 7a78712..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[parent-yes-child1-no-subdomain-child2-no-subdomain.sub.https.html]
-  [Parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [Parent to child2: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain2.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain2.sub.https.html.ini
deleted file mode 100644
index 5516d656..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-no-subdomain2.sub.https.html.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[parent-yes-child1-no-subdomain-child2-no-subdomain2.sub.https.html]
-  [Parent to child1: setting document.domain must not give sync access]
-    expected:
-      if product == "chrome": FAIL
-
-  [Parent to child2: setting document.domain must not give sync access]
-    expected:
-      if product == "chrome": FAIL
-
-  [child1 to child2: setting document.domain must give sync access]
-    expected:
-      if product == "chrome": PASS
-      FAIL
-
-  [child2 to child1: setting document.domain must give sync access]
-    expected:
-      if product == "chrome": PASS
-      FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected:
-      if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index 6009c77..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[parent-yes-child1-no-subdomain-child2-yes-subdomain.sub.https.html]
-  [Parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [Parent to child2: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain2.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain2.sub.https.html.ini
deleted file mode 100644
index 6dddf49..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomain2.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child1-no-subdomain-child2-yes-subdomain2.sub.https.html]
-  [Parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini
deleted file mode 100644
index 8009bcb..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-no-subdomain-child2-yes-subdomainport.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child1-no-subdomain-child2-yes-subdomainport.sub.https.html]
-  [Parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-port.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-port.sub.https.html.ini
deleted file mode 100644
index 96a081e..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-port.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-yes-child1-yes-subdomain-child2-no-port.sub.https.html]
-  [Parent to child2: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-subdomain.sub.https.html.ini
deleted file mode 100644
index 9418308..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child1-yes-subdomain-child2-no-subdomain.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index 5af6030..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child1-yes-subdomain-child2-yes-subdomain.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain2.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain2.sub.https.html.ini
deleted file mode 100644
index 3256aa4..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomain2.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child1-yes-subdomain-child2-yes-subdomain2.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html.ini
deleted file mode 100644
index d7e304e..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html]
-  [parent: originAgentCluster must equal true]
-    expected: [FAIL, PASS]
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/__dir__.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/about-blank.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/about-blank.https.sub.html.ini
deleted file mode 100644
index d41c881..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/about-blank.https.sub.html.ini
+++ /dev/null
@@ -1,25 +0,0 @@
-[about-blank.https.sub.html]
-  expected: ERROR
-  [about:blank to child2: messageerror event must occur]
-    expected: NOTRUN
-
-  [about:blank to child2: setting document.domain must not give sync access]
-    expected: NOTRUN
-
-  [about:blank: originAgentCluster must equal true]
-    expected: NOTRUN
-
-  [child2 to about:blank: messageerror event must occur]
-    expected: NOTRUN
-
-  [child2 to about:blank: setting document.domain must not give sync access]
-    expected: NOTRUN
-
-  [child2: originAgentCluster must equal false]
-    expected: NOTRUN
-
-  [parent to about:blank: setting document.domain must give sync access]
-    expected: NOTRUN
-
-  [parent: originAgentCluster must equal true]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/document-domain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/document-domain.sub.https.html.ini
deleted file mode 100644
index ac7b637..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/document-domain.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[document-domain.sub.https.html]
-  [Setting document.domain must not change same-originness]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini
deleted file mode 100644
index 6ec7e98..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/removed-iframe.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[removed-iframe.sub.https.html]
-  [Removing the iframe does not change originAgentCluster]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/sandboxed-same-origin-iframe-yes.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/sandboxed-same-origin-iframe-yes.https.html.ini
deleted file mode 100644
index ba7bf6d0..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/getter-special-cases/sandboxed-same-origin-iframe-yes.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[sandboxed-same-origin-iframe-yes.https.html]
-  [originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/going-back.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/going-back.sub.https.html.ini
deleted file mode 100644
index dc231a8c..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/going-back.sub.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[going-back.sub.https.html]
-  [After back: parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [After back: parent to child2: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [After navigation: parent to child2: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [Before navigation: parent to child1: setting document.domain must not give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index fe43adfb..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-no-1-no-subdomain-2-yes-subdomain.sub.https.html]
-  [After: parent to child: setting document.domain must give sync access]
-    expected: FAIL
-
-  [Before: parent to child: setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain2.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain2.sub.https.html.ini
deleted file mode 100644
index 22a18b4..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-no-subdomain-2-yes-subdomain2.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[parent-no-1-no-subdomain-2-yes-subdomain2.sub.https.html]
-  [Before: parent to child: setting document.domain must give sync access]
-    expected: FAIL
-
-  [before child: originAgentCluster must equal false]
-    expected: [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-subdomain-yes-2-subdomain2-no.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-subdomain-yes-2-subdomain2-no.sub.https.html.ini
deleted file mode 100644
index 76c2cb0..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-no-1-subdomain-yes-2-subdomain2-no.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parent-no-1-subdomain-yes-2-subdomain2-no.sub.https.html]
-  [After: parent to child: setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-port.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-port.sub.https.html.ini
deleted file mode 100644
index 596af08..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-port.sub.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[parent-yes-1-no-same-2-no-port.sub.https.html]
-  [After: parent to child: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [after parent: originAgentCluster must equal true]
-    expected: FAIL
-
-  [before child: originAgentCluster must equal true]
-    expected: FAIL
-
-  [before parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-subdomain.sub.https.html.ini
deleted file mode 100644
index c560c42..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/iframe-navigation/parent-yes-1-no-same-2-no-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[parent-yes-1-no-same-2-no-subdomain.sub.https.html]
-  [After: parent to child: setting document.domain must not give sync access]
-    expected: FAIL
-
-  [after parent: originAgentCluster must equal true]
-    expected: FAIL
-
-  [before child: originAgentCluster must equal true]
-    expected: FAIL
-
-  [before parent: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/insecure-http.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/insecure-http.sub.html.ini
deleted file mode 100644
index 3d66bce..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/insecure-http.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[insecure-http.sub.html]
-  [setting document.domain must give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-same.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-same.sub.https.html.ini
deleted file mode 100644
index 6033375..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-same.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[opener-yes-openee-no-same.sub.https.html]
-  [openee: originAgentCluster must equal true]
-    expected: FAIL
-
-  [opener: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-subdomain.sub.https.html.ini
deleted file mode 100644
index 26713597..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-no-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[opener-yes-openee-no-subdomain.sub.https.html]
-  [opener: originAgentCluster must equal true]
-    expected: FAIL
-
-  [setting document.domain must not give sync access]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-port.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-port.sub.https.html.ini
deleted file mode 100644
index 66ae53db..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-port.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[opener-yes-openee-yes-port.sub.https.html]
-  [opener: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-same.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-same.sub.https.html.ini
deleted file mode 100644
index 659a9c6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-same.sub.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[opener-yes-openee-yes-same.sub.https.html]
-  [openee: originAgentCluster must equal true]
-    expected: FAIL
-
-  [opener: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-subdomain.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-subdomain.sub.https.html.ini
deleted file mode 100644
index 4f129222..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-yes-openee-yes-subdomain.sub.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[opener-yes-openee-yes-subdomain.sub.https.html]
-  [opener: originAgentCluster must equal true]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/removing-iframes.sub.https.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/removing-iframes.sub.https.html.ini
deleted file mode 100644
index 6151a954..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/removing-iframes.sub.https.html.ini
+++ /dev/null
@@ -1,26 +0,0 @@
-[removing-iframes.sub.https.html]
-  [Before: setting document.domain must not give sync access]
-    expected:
-      if product == "chrome": FAIL
-
-  [Parent to child2: setting document.domain must not give sync access]
-    expected:
-      if product == "chrome": FAIL
-
-  [Parent to child3: setting document.domain must not give sync access]
-    expected:
-      if product == "chrome": FAIL
-
-  [child2 to child3: setting document.domain must give sync access]
-    expected:
-      if product == "chrome": PASS
-      FAIL
-
-  [child3 to child2: setting document.domain must give sync access]
-    expected:
-      if product == "chrome": PASS
-      FAIL
-
-  [parent: originAgentCluster must equal true]
-    expected:
-      if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/__dir__.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_access_details.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_access_details.sub.html.ini
deleted file mode 100644
index 154dcd9b..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_access_details.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[document_domain_access_details.sub.html]
-  [Access allowed if different-origin but both set document.domain to parent domain.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini
deleted file mode 100644
index a3e54b02..0000000
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[document_domain_setter.html]
-  [same-origin-domain iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin-domain.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin-domain.sub.html.ini
index 0624d01..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin-domain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin-domain.sub.html.ini
@@ -1,7 +1,2 @@
-[windowproxy-prototype-setting-same-origin-domain.sub.html]
-  expected: ERROR
-  [Same-origin-domain prerequisite check: the original prototype is accessible]
-    expected: FAIL
-
-  [Same-origin-domain: setting the prototype to an empty object via Object.setPrototypeOf should throw a TypeError]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/windows/nested-browsing-contexts/frameElement-siblings.sub.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/windows/nested-browsing-contexts/frameElement-siblings.sub.html.ini
index 32a43d2..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/windows/nested-browsing-contexts/frameElement-siblings.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/windows/nested-browsing-contexts/frameElement-siblings.sub.html.ini
@@ -1,3 +1,2 @@
-[frameElement-siblings.sub.html]
-  [it must return the iframe element if the pages are same-origin domain]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/windows/noreferrer-window-name.html.ini b/third_party/blink/web_tests/external/wpt/html/browsers/windows/noreferrer-window-name.html.ini
index b766121a..b3c2909 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/windows/noreferrer-window-name.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/windows/noreferrer-window-name.html.ini
@@ -1,4 +1,5 @@
 [noreferrer-window-name.html]
+  disabled: crbug.com/1299834
   expected: TIMEOUT
   [Targeting a rel=noreferrer link at an existing named window should work]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/aria-element-reflection-disconnected.html b/third_party/blink/web_tests/external/wpt/html/dom/aria-element-reflection-disconnected.html
new file mode 100644
index 0000000..7bc1052
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/aria-element-reflection-disconnected.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8" />
+<link rel=help href="https://html.spec.whatwg.org/#attr-associated-element">
+<link rel="author" href="masonf@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id=container>
+  <input aria-activedescendant=foo>
+  <p id=foo></p>
+</div>
+
+<script>
+  test(() => {
+    const container = document.getElementById('container');
+    const el = container.querySelector('input');
+    const target = container.querySelector('#foo');
+    assert_equals(el.ariaActiveDescendantElement,target);
+    container.remove();
+    assert_equals(el.ariaActiveDescendantElement,null,'idrefs should stop working when target is disconnected');
+    assert_equals(el.getAttribute('aria-activedescendant'),'foo','Attribute value is still ok');
+    document.body.appendChild(container);
+    assert_equals(el.ariaActiveDescendantElement,target,'functional when reconnected');
+    // Now set up an attr-associated element:
+    el.ariaActiveDescendantElement = target;
+    assert_equals(el.ariaActiveDescendantElement,target);
+    assert_equals(el.getAttribute('aria-activedescendant'),'','Content attribute is present but empty');
+    container.remove();
+    assert_equals(el.ariaActiveDescendantElement,target,'attr-associated element still functional');
+    assert_equals(el.getAttribute('aria-activedescendant'),'','Attribute still blank');
+    document.body.appendChild(container);
+    assert_equals(el.ariaActiveDescendantElement,target,'still functional when reconnected');
+  },'Element references should stay valid when content is disconnected');
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/__dir__.ini b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/parser-inserted-async-script.tentative.html.ini b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/parser-inserted-async-script.tentative.html.ini
deleted file mode 100644
index af0a2227..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/parser-inserted-async-script.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[parser-inserted-async-script.tentative.html]
-  [Rendering is blocked before render-blocking resources are loaded]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-attr-script-keeps-blocking.tentative.html.ini b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-attr-script-keeps-blocking.tentative.html.ini
deleted file mode 100644
index 0d2530b..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-attr-script-keeps-blocking.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[remove-attr-script-keeps-blocking.tentative.html]
-  [Rendering is blocked before render-blocking resources are loaded]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-module-script.tentative.html.ini b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-module-script.tentative.html.ini
deleted file mode 100644
index 1300db7..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-module-script.tentative.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-inserted-module-script.tentative.html]
-  [Rendering is blocked before render-blocking resources are loaded]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-script.html.ini b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-script.html.ini
deleted file mode 100644
index 45c02d6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/script-inserted-script.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[script-inserted-script.html]
-  [Rendering is blocked before render-blocking resources are loaded]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html.ini b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html.ini b/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html.ini
index 315ae7b5..cdde69d7 100644
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html.ini
@@ -27,6 +27,7 @@
 
 
 [utf-16be.html?include=workers]
+  disabled: crbug.com/930297
   expected:
     if product == "chrome": ERROR
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16le.html.ini b/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16le.html.ini
index 3deb270..d1104339 100644
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16le.html.ini
+++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16le.html.ini
@@ -27,6 +27,7 @@
 
 
 [utf-16le.html?include=workers]
+  disabled: crbug.com/930297
   expected:
     if product == "chrome": ERROR
     TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-user-select.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-user-select.tentative.html
new file mode 100644
index 0000000..dc6e2e2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-user-select.tentative.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/openui/open-ui/issues/687">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<selectmenu id=useragent>
+  <option id=useragentoptionone>one</option>
+  <option id=useragentoptiontwo>two</option>
+</selectmenu>
+
+<selectmenu id=custom>
+  <div id=custombutton slot=button behavior=button>button</div>
+  <div id=customlistbox popover=auto slot=listbox behavior=listbox>listbox</div>
+</selectmenu>
+
+<selectmenu id=customwithselection style="user-select:auto">
+  <div id=custombuttonwithselection slot=button behavior=button>button</div>
+  <div id=customlistboxwithselection popover=auto slot=listbox behavior=listbox>listbox</div>
+</selectmenu>
+
+<selectmenu id=customwithmixedselection>
+  <div id=custombuttonwithmixedselection slot=button behavior=button style="user-select:auto">button</div>
+  <div id=customlistboxwithmixedselection popover=auto slot=listbox behavior=listbox style="user-select:auto">listbox</div>
+</selectmenu>
+
+<script>
+test(() => {
+  assert_equals(getComputedStyle(useragent).userSelect, 'none',
+    'The selectmenu should have user-select:none.');
+  assert_equals(getComputedStyle(useragentoptionone).userSelect, 'none',
+    'The first option should have user-select:none.');
+  assert_equals(getComputedStyle(useragentoptiontwo).userSelect, 'none',
+    'The second option should have user-select:none.');
+}, 'Option elements should have user-select:none without slotting buttons or listboxes.');
+
+test(() => {
+  assert_equals(getComputedStyle(custom).userSelect, 'none',
+    'The selectmenu should have user-select:none.');
+  assert_equals(getComputedStyle(custombutton).userSelect, 'none',
+    'The custom button should have user-select:none.');
+  assert_equals(getComputedStyle(customlistbox).userSelect, 'none',
+    'The custom listbox should have user-select:none.');
+}, 'Slotted in buttons and listboxes should have user-select:none.');
+
+test(() => {
+  assert_equals(getComputedStyle(customwithselection).userSelect, 'auto',
+    'The selectmenu should have user-select:auto.');
+  assert_equals(getComputedStyle(custombuttonwithselection).userSelect, 'auto',
+    'The custom button should have user-select:auto.');
+  assert_equals(getComputedStyle(customlistboxwithselection).userSelect, 'auto',
+    'The custom listbox should have user-select:auto.');
+}, 'Setting user-select:auto on selectmenus should re-enable selection.');
+
+test(() => {
+  assert_equals(getComputedStyle(customwithmixedselection).userSelect, 'none',
+    'The selectmenu should have user-select:none.');
+  assert_equals(getComputedStyle(custombuttonwithmixedselection).userSelect, 'auto',
+    'The custom button should have user-select:auto.');
+  assert_equals(getComputedStyle(customlistboxwithmixedselection).userSelect, 'auto',
+    'The custom listbox should have user-select:auto.');
+}, 'Children of selectmenu should be able to opt-in to user-select.');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/__dir__.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/is-input-pending/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-complex-clip.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-complex-clip.sub.html.ini
deleted file mode 100644
index aa1d7415..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-complex-clip.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-subframe-complex-clip.sub.html]
-  [parent cannot detect cross-origin events]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-complex-clip.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-complex-clip.sub.html.ini
deleted file mode 100644
index 2c20eee..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-complex-clip.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[cross-origin-subframe-masked-complex-clip.sub.html]
-  [parent cannot detect cross-origin events outside of clip]
-    expected: FAIL
-
-  [subframe cannot detect events inside of clip]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed-2.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed-2.sub.html.ini
deleted file mode 100644
index a3b30ce..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed-2.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[cross-origin-subframe-masked-pointer-events-mixed-2.sub.html]
-  [parent cannot detect cross-origin events in `pointer-events: none` region]
-    expected: FAIL
-
-  [subframe cannot detect events in `pointer-events: initial` region]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed.sub.html.ini
deleted file mode 100644
index 640e7369f..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-mixed.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-subframe-masked-pointer-events-mixed.sub.html]
-  [cannot detect cross-origin events in `pointer-events: none` region]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-none.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-none.sub.html.ini
deleted file mode 100644
index df1e3d8..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-masked-pointer-events-none.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-subframe-masked-pointer-events-none.sub.html]
-  [parent cannot detect events]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-overlap.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-overlap.sub.html.ini
deleted file mode 100644
index cfeb8f4..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-overlap.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[cross-origin-subframe-overlap.sub.html]
-  [occluded iframe cannot detect input on occluding iframe]
-    expected: FAIL
-
-  [parent cannot detect input on occluding iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-pointer-events-none.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-pointer-events-none.sub.html.ini
deleted file mode 100644
index da65ff0..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-pointer-events-none.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-subframe-pointer-events-none.sub.html]
-  [iframe cannot detect events with pointer-events: none]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-transformed.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-transformed.sub.html.ini
deleted file mode 100644
index 6859314..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe-transformed.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[cross-origin-subframe-transformed.sub.html]
-  [parent cannot detect input inside of iframe bounds]
-    expected: FAIL
-
-  [subframe cannot detect input outside of iframe bounds]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe.sub.html.ini
deleted file mode 100644
index e440c0d..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/security/cross-origin-subframe.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-subframe.sub.html]
-  [cannot detect cross-origin events on subframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/same-origin-subframe.sub.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/same-origin-subframe.sub.html.ini
deleted file mode 100644
index c3a9b4c3..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/same-origin-subframe.sub.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[same-origin-subframe.sub.html]
-  [can detect same-origin iframe events in parent]
-    expected: FAIL
-
-  [can detect same-origin iframe events in subframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/toplevel.html.ini b/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/toplevel.html.ini
deleted file mode 100644
index e6b53b28..0000000
--- a/third_party/blink/web_tests/external/wpt/is-input-pending/tentative/toplevel.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[toplevel.html]
-  [toplevel mouse events detected]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-background.tentative.html.ini b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-background.tentative.html.ini
index 4bd8b93..60fd145 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-background.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-background.tentative.html.ini
@@ -1,4 +1,5 @@
 [mouseover-heuristics-background.tentative.html]
+  disabled: crbug.com/1288027
   expected: ERROR
   [LCP mouseover heuristics ignore background-based zoom widgets]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-element.tentative.html.ini b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-element.tentative.html.ini
index aa1921a..cdb2836d 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-element.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/mouseover-heuristics-element.tentative.html.ini
@@ -1,4 +1,5 @@
 [mouseover-heuristics-element.tentative.html]
+  disabled: crbug.com/1288027
   expected: ERROR
   [LCP mouseover heuristics ignore element-based zoom widgets]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-after-fcp.tentative.html.ini b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-after-fcp.tentative.html.ini
index a5de6ce..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-after-fcp.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-after-fcp.tentative.html.ini
@@ -1,3 +1,2 @@
-[non-tao-image-load-after-fcp.tentative.html]
-  [Non-Tao Image Load and Render After FCP.]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-after.tentative.html.ini b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-after.tentative.html.ini
index 5cec90b..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-after.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-after.tentative.html.ini
@@ -1,3 +1,2 @@
-[non-tao-image-load-before-fcp-render-after.tentative.html]
-  [Non-Tao Image Load Before FCP and Render After FCP.]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-at-fcp.tentative.html.ini b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-at-fcp.tentative.html.ini
index 9254277b..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-at-fcp.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/non-tao-image-load-before-fcp-render-at-fcp.tentative.html.ini
@@ -1,5 +1,2 @@
-[non-tao-image-load-before-fcp-render-at-fcp.tentative.html]
-  [Non-Tao Image Load Before LCP and Render at the Same Time of FCP.]
-    expected:
-      if (product == "content_shell") and (os == "linux"): [FAIL, PASS]
-      FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/__dir__.ini b/third_party/blink/web_tests/external/wpt/measure-memory/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/measure-memory/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js.ini
deleted file mode 100644
index ec4b2ae..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/detached.https.window.js.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[detached.https.window.html]
-  expected: TIMEOUT
-  [performance.measureUserAgentSpecificMemory URLs within a cross-site iframe.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/idlharness.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/idlharness.window.js.ini
deleted file mode 100644
index 1aa8b404..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/idlharness.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[idlharness.window.html]
-  [Performance interface: operation measureUserAgentSpecificMemory()]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js.ini
deleted file mode 100644
index 924b9e8..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.cross-origin.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[iframe.cross-origin.https.window.html]
-  [performance.measureUserAgentSpecificMemory URLs within a cross-origin iframe.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js.ini
deleted file mode 100644
index 97ddb46..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/iframe.same-origin.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[iframe.same-origin.https.window.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory with same-origin iframes.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js.ini
deleted file mode 100644
index 857460e..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame-and-worker.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[main-frame-and-worker.https.window.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js.ini
deleted file mode 100644
index caf176a5..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/main-frame.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[main-frame.https.window.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js.ini
deleted file mode 100644
index f5b03709..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/randomized-breakdown.https.window.js.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[randomized-breakdown.https.window.html]
-  expected:
-    if product == "chrome": OK
-    TIMEOUT
-  [Well-formed result of performance.measureUserAgentSpecificMemory.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js.ini
deleted file mode 100644
index d0d751e..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.client.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[redirect.client.https.window.html]
-  [performance.measureUserAgentSpecificMemory does not leak client redirected URL.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js.ini
deleted file mode 100644
index 783d5ae..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/redirect.server.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[redirect.server.https.window.html]
-  [performance.measureUserAgentSpecificMemory does not leak server redirected URL.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/service-worker.https.any.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/service-worker.https.any.js.ini
deleted file mode 100644
index 1898832..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/service-worker.https.any.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[service-worker.https.any.serviceworker.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/shared-worker.https.any.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/shared-worker.https.any.js.ini
deleted file mode 100644
index 0e35ab4..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/shared-worker.https.any.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shared-worker.https.any.sharedworker.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js.ini
deleted file mode 100644
index 3f3df995..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-origin.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-open.cross-origin.https.window.html]
-  [performance.measureUserAgentSpecificMemory does not leak URL of cross-origin window.open.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js.ini
deleted file mode 100644
index d9b3660..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.cross-site.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-open.cross-site.https.window.html]
-  [performance.measureUserAgentSpecificMemory does not leak URL of cross-site window.open.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js.ini
deleted file mode 100644
index fda1659..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.mix.https.window.js.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[window-open.mix.https.window.html]
-  expected: TIMEOUT
-  [performance.measureUserAgentSpecificMemory does not leak URLs in cross-origin iframes and windows.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js.ini b/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js.ini
deleted file mode 100644
index d326cb6..0000000
--- a/third_party/blink/web_tests/external/wpt/measure-memory/window-open.same-origin.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-open.same-origin.https.window.html]
-  [Well-formed result of performance.measureUserAgentSpecificMemory with same-origin window.open.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection.https.html.ini
index 3d02462a..683f9ba04 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-peerconnection.https.html.ini
@@ -1,4 +1,5 @@
 [MediaRecorder-peerconnection.https.html]
+  disabled: crbug.com/626703 slow timeout test
   expected: TIMEOUT
   [PeerConnection MediaRecorder gets ondata on stopping tracks, {"audio":{}} mimeType ""]
     expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html.ini
index e4f9bea..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStream-default-feature-policy.https.html.ini
@@ -1,6 +1,2 @@
-[MediaStream-default-feature-policy.https.html]
-  [Feature policy "camera" can be enabled in cross-origin iframes using "allow" attribute.]
-    expected: FAIL
-
-  [Feature policy "microphone" can be enabled in cross-origin iframes using "allow" attribute.]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-audio-transfer.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-audio-transfer.https.html.ini
index 72e1db2..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-audio-transfer.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-audio-transfer.https.html.ini
@@ -1,4 +1,2 @@
-[MediaStreamTrack-iframe-audio-transfer.https.html]
-  expected: ERROR
-  [MediaStreamTrack transfer to iframe]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-transfer.https.html.ini b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-transfer.https.html.ini
index d02c8f9..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-transfer.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-iframe-transfer.https.html.ini
@@ -1,3 +1,2 @@
-[MediaStreamTrack-iframe-transfer.https.html]
-  [MediaStreamTrack transfer to iframe]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/gen/top.http-rp/opt-in/object-tag.https.html.ini b/third_party/blink/web_tests/external/wpt/mixed-content/gen/top.http-rp/opt-in/object-tag.https.html.ini
index 2af3bfc..83360b7 100644
--- a/third_party/blink/web_tests/external/wpt/mixed-content/gen/top.http-rp/opt-in/object-tag.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/mixed-content/gen/top.http-rp/opt-in/object-tag.https.html.ini
@@ -1,4 +1,5 @@
 [object-tag.https.html]
+  disabled: crbug.com/1050826
   expected: TIMEOUT
   [Mixed-Content: Expects blocked for object-tag to cross-https origin and swap-scheme redirection from https context.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html.ini
index 04764ea0..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[click-crossdocument-crossorigin-sameorigindomain.sub.html]
-  [clicking on an <a> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html.ini
index 976ba04..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[click-samedocument-crossorigin-sameorigindomain.sub.html]
-  [clicking on an <a> element that navigates same-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html.ini
index fef880d..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[location-crossdocument-crossorigin-sameorigindomain.sub.html]
-  [using location.href to navigate cross-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html.ini
index b139b3a..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[location-samedocument-crossorigin-sameorigindomain.sub.html]
-  [using location.href to navigate same-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html.ini
index 70bb151..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[open-crossdocument-crossorigin-sameorigindomain.sub.html]
-  [using window.open() to navigate cross-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html.ini
index 2b0a9dd..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[open-samedocument-crossorigin-sameorigindomain.sub.html]
-  [using window.open() to navigate same-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html.ini
index 203b4c9..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[submit-crossdocument-crossorigin-sameorigindomain.sub.html]
-  [submitting a <form> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html.ini b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html.ini
index b4e60f6c..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html.ini
@@ -1,3 +1,2 @@
-[submit-samedocument-crossorigin-sameorigindomain.sub.html]
-  [submitting a <form> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window]
-    expected: FAIL
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/page-visibility/visibility-state-entry.tentative.html.ini b/third_party/blink/web_tests/external/wpt/page-visibility/visibility-state-entry.tentative.html.ini
index 98b66545..eae7903 100644
--- a/third_party/blink/web_tests/external/wpt/page-visibility/visibility-state-entry.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/page-visibility/visibility-state-entry.tentative.html.ini
@@ -1,4 +1,5 @@
 [visibility-state-entry.tentative.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [Hiding/showing the page should create visibility-state entries]
     expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/pending-beacon/__dir__.ini b/third_party/blink/web_tests/external/wpt/pending-beacon/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/pending-beacon/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-basic.window.js.ini b/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-basic.window.js.ini
deleted file mode 100644
index 71b9819..0000000
--- a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-basic.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pending_beacon-basic.window.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendondiscard.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendondiscard.tentative.https.window.js.ini
deleted file mode 100644
index dcd9f1435..0000000
--- a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendondiscard.tentative.https.window.js.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[pending_beacon-sendondiscard.tentative.https.window.html]
-  expected:
-    if (product == "content_shell") and (os == "mac"): OK
-    if (product == "content_shell") and (os == "win"): OK
-    ERROR
-  [A discarded document does not send an already sent beacon.]
-    expected:
-      if (product == "content_shell") and (os == "mac"): [PASS, FAIL]
-      FAIL
-
-  [A discarded document sends all its beacons of which backgroundTimeouts are\n    not default.]
-    expected:
-      if (product == "content_shell") and (os == "mac"): [FAIL, PASS]
-
-  [A discarded document sends all its beacons of which timeouts are not\n    default.]
-    expected:
-      if (product == "content_shell") and (os == "mac"): [FAIL, PASS]
-
-  [A discarded document sends all its beacons with default config.]
-    expected:
-      if (product == "content_shell") and (os == "mac"): [PASS, FAIL]
-      FAIL
diff --git a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendonhidden.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendonhidden.tentative.https.window.js.ini
deleted file mode 100644
index c71611d..0000000
--- a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_beacon-sendonhidden.tentative.https.window.js.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[pending_beacon-sendonhidden.tentative.https.window.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_post_beacon-cors.tentative.https.window.js.ini b/third_party/blink/web_tests/external/wpt/pending-beacon/pending_post_beacon-cors.tentative.https.window.js.ini
deleted file mode 100644
index 9aa002cc..0000000
--- a/third_party/blink/web_tests/external/wpt/pending-beacon/pending_post_beacon-cors.tentative.https.window.js.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[pending_post_beacon-cors.tentative.https.window.html]
-  expected:
-    if (product == "content_shell") and (os == "mac"): TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/permissions-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant-expected.txt b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant-expected.txt
deleted file mode 100644
index 3ccab14..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Wheel-scroll over pointer-events: auto descendant scrolls pointer-events: none scroller. assert_equals: Incorrect element scrolled expected "overlay" but got "root"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant.html.ini b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant.html.ini
deleted file mode 100644
index 04e88a8..0000000
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_hit_test_scroll_visible_descendant.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[pointerevent_hit_test_scroll_visible_descendant.html]
-  [Wheel-scroll over pointer-events: auto descendant scrolls pointer-events: none scroller.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/__dir__.ini b/third_party/blink/web_tests/external/wpt/portals/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/portals/about-blank-cannot-host.html.ini b/third_party/blink/web_tests/external/wpt/portals/about-blank-cannot-host.html.ini
deleted file mode 100644
index e8a61823..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/about-blank-cannot-host.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[about-blank-cannot-host.html]
-  [about:blank cannot host a portal]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/csp/frame-ancestors.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/csp/frame-ancestors.sub.html.ini
deleted file mode 100644
index 1aefc578..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/csp/frame-ancestors.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[frame-ancestors.sub.html]
-  [Violation report status OK.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/csp/frame-src.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/csp/frame-src.sub.html.ini
deleted file mode 100644
index 44a9c376d..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/csp/frame-src.sub.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[frame-src.sub.html]
-  [Tests that a portal can be loaded when the origin matches the frame-src CSP header.]
-    expected: FAIL
-
-  [Tests that a portal can't be loaded when it violates frame-src]
-    expected: FAIL
-
-  [Tests that a portal will fail to load on an origin different than the one specified in the frame-src CSP, but that it can be loaded when the origin matches the frame-src CSP.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal-with-subframes.html.ini b/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal-with-subframes.html.ini
deleted file mode 100644
index 252a303..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal-with-subframes.html.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[history-manipulation-inside-portal-with-subframes.html]
-  expected:
-    if product == "chrome": OK
-    TIMEOUT
-  [Cross site iframe navigates itself independently with replacement in a portal]
-    expected: FAIL
-
-  [Setting cross site iframe src navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [Setting iframe src navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [iframe navigates itself independently with replacement in a portal]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal.html.ini b/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal.html.ini
deleted file mode 100644
index 235e437e..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/history/history-manipulation-inside-portal.html.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[history-manipulation-inside-portal.html]
-  [Setting location.href navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [Synthetic anchor click navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [history.pushState navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [history.replaceState navigates independently in a portal]
-    expected: FAIL
-
-  [location.assign navigates independently with replacement in a portal]
-    expected: FAIL
-
-  [location.replace navigates independently in a portal]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html.ini b/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html.ini
deleted file mode 100644
index 2a3a56f4..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/htmlportalelement-event-handler-content-attributes.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[htmlportalelement-event-handler-content-attributes.html]
-  [Tests that event handler content attributes for supported event names work.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/idlharness.window.js.ini b/third_party/blink/web_tests/external/wpt/portals/idlharness.window.js.ini
deleted file mode 100644
index 4580f8f..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/idlharness.window.js.ini
+++ /dev/null
@@ -1,159 +0,0 @@
-[idlharness.window.html]
-  [HTMLBodyElement interface: attribute onportalactivate]
-    expected: FAIL
-
-  [HTMLFrameSetElement interface: attribute onportalactivate]
-    expected: FAIL
-
-  [HTMLPortalElement interface object length]
-    expected: FAIL
-
-  [HTMLPortalElement interface object name]
-    expected: FAIL
-
-  [HTMLPortalElement interface: attribute onmessage]
-    expected: FAIL
-
-  [HTMLPortalElement interface: attribute onmessageerror]
-    expected: FAIL
-
-  [HTMLPortalElement interface: attribute referrerPolicy]
-    expected: FAIL
-
-  [HTMLPortalElement interface: attribute src]
-    expected: FAIL
-
-  [HTMLPortalElement interface: calling activate(optional PortalActivateOptions) on document.createElement("portal") with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [HTMLPortalElement interface: calling postMessage(any, optional StructuredSerializeOptions) on document.createElement("portal") with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "activate(optional PortalActivateOptions)" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "onmessage" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "onmessageerror" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "postMessage(any, optional StructuredSerializeOptions)" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "referrerPolicy" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: document.createElement("portal") must inherit property "src" with the proper type]
-    expected: FAIL
-
-  [HTMLPortalElement interface: existence and properties of interface object]
-    expected: FAIL
-
-  [HTMLPortalElement interface: existence and properties of interface prototype object]
-    expected: FAIL
-
-  [HTMLPortalElement interface: existence and properties of interface prototype object's "constructor" property]
-    expected: FAIL
-
-  [HTMLPortalElement interface: existence and properties of interface prototype object's @@unscopables property]
-    expected: FAIL
-
-  [HTMLPortalElement interface: operation activate(optional PortalActivateOptions)]
-    expected: FAIL
-
-  [HTMLPortalElement interface: operation postMessage(any, optional StructuredSerializeOptions)]
-    expected: FAIL
-
-  [HTMLPortalElement must be primary interface of document.createElement("portal")]
-    expected: FAIL
-
-  [PortalActivateEvent interface object length]
-    expected: FAIL
-
-  [PortalActivateEvent interface object name]
-    expected: FAIL
-
-  [PortalActivateEvent interface: attribute data]
-    expected: FAIL
-
-  [PortalActivateEvent interface: existence and properties of interface object]
-    expected: FAIL
-
-  [PortalActivateEvent interface: existence and properties of interface prototype object]
-    expected: FAIL
-
-  [PortalActivateEvent interface: existence and properties of interface prototype object's "constructor" property]
-    expected: FAIL
-
-  [PortalActivateEvent interface: existence and properties of interface prototype object's @@unscopables property]
-    expected: FAIL
-
-  [PortalActivateEvent interface: new PortalActivateEvent("portalactivate") must inherit property "adoptPredecessor()" with the proper type]
-    expected: FAIL
-
-  [PortalActivateEvent interface: new PortalActivateEvent("portalactivate") must inherit property "data" with the proper type]
-    expected: FAIL
-
-  [PortalActivateEvent interface: operation adoptPredecessor()]
-    expected: FAIL
-
-  [PortalActivateEvent must be primary interface of new PortalActivateEvent("portalactivate")]
-    expected: FAIL
-
-  [PortalHost interface object length]
-    expected: FAIL
-
-  [PortalHost interface object name]
-    expected: FAIL
-
-  [PortalHost interface: attribute onmessage]
-    expected: FAIL
-
-  [PortalHost interface: attribute onmessageerror]
-    expected: FAIL
-
-  [PortalHost interface: calling postMessage(any, optional StructuredSerializeOptions) on window.portalHost with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [PortalHost interface: existence and properties of interface object]
-    expected: FAIL
-
-  [PortalHost interface: existence and properties of interface prototype object]
-    expected: FAIL
-
-  [PortalHost interface: existence and properties of interface prototype object's "constructor" property]
-    expected: FAIL
-
-  [PortalHost interface: existence and properties of interface prototype object's @@unscopables property]
-    expected: FAIL
-
-  [PortalHost interface: operation postMessage(any, optional StructuredSerializeOptions)]
-    expected: FAIL
-
-  [PortalHost interface: window.portalHost must inherit property "onmessage" with the proper type]
-    expected: FAIL
-
-  [PortalHost interface: window.portalHost must inherit property "onmessageerror" with the proper type]
-    expected: FAIL
-
-  [PortalHost interface: window.portalHost must inherit property "postMessage(any, optional StructuredSerializeOptions)" with the proper type]
-    expected: FAIL
-
-  [PortalHost must be primary interface of window.portalHost]
-    expected: FAIL
-
-  [Stringification of document.createElement("portal")]
-    expected: FAIL
-
-  [Stringification of new PortalActivateEvent("portalactivate")]
-    expected: FAIL
-
-  [Stringification of window.portalHost]
-    expected: FAIL
-
-  [Window interface: attribute onportalactivate]
-    expected: FAIL
-
-  [Window interface: attribute portalHost]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html.ini
deleted file mode 100644
index a7ff35b..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-data.html.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[portal-activate-data.html]
-  [A SharedArrayBuffer cannot be passed through activate data.]
-    expected: FAIL
-
-  [A message port can be passed through activate data.]
-    expected: FAIL
-
-  [A string can be passed through activate data.]
-    expected: FAIL
-
-  [An array buffer can be transferred through activate data.]
-    expected: FAIL
-
-  [An image bitmap can be transferred through activate data.]
-    expected: FAIL
-
-  [Errors during transfer list processing are propagated.]
-    expected: FAIL
-
-  [Uncloneable data has its exception propagated.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-default.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-activate-default.html.ini
deleted file mode 100644
index 7d8ef04..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-default.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portal-activate-default.html]
-  [Clicking should activate with undefined data.]
-    expected: FAIL
-
-  [Clicking shouldn't activate if prevented.]
-    expected: FAIL
-
-  [Failed activation should not surface as an unhandled promise rejection.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event-constructor.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-activate-event-constructor.html.ini
deleted file mode 100644
index c90733c..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event-constructor.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portal-activate-event-constructor.html]
-  [A PortalActivateEvent should expose exactly the data object supplied in the original realm]
-    expected: FAIL
-
-  [Invoking adoptPredecessor on a synthetic PortalActivateEvent should throw]
-    expected: FAIL
-
-  [It should be possible to construct a PortalActivateEvent with a dictionary]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html.ini
deleted file mode 100644
index 29ac665..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portal-activate-event.html]
-  [Tests that the HTMLBodyElement has the portalactivate event handler.]
-    expected: FAIL
-
-  [Tests that the PortalActivateEvent is dispatched when a portal is activated.]
-    expected: FAIL
-
-  [Tests that the portalactivate event handler is dispatched when a portal is activated.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-non-http-navigation.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-non-http-navigation.html.ini
deleted file mode 100644
index 828edc7..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-non-http-navigation.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portal-non-http-navigation.html]
-  [Tests that a portal can't navigate to a data URL.]
-    expected: FAIL
-
-  [Tests that a portal can't navigate to about:blank.]
-    expected: FAIL
-
-  [Tests that a portal can't navigate to javascript URLs.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-onload-event.html.ini b/third_party/blink/web_tests/external/wpt/portals/portal-onload-event.html.ini
deleted file mode 100644
index 15fc60a..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portal-onload-event.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portal-onload-event.html]
-  [Tests that the load event is dispatched when a portal finishes loading.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-empty-browsing-context.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-empty-browsing-context.html.ini
deleted file mode 100644
index 66e6da1..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-empty-browsing-context.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[portals-activate-empty-browsing-context.html]
-  [A portal that has never been navigated cannot be activated]
-    expected: FAIL
-
-  [A portal that has not completed an initial navigation cannot be activated]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-iframe.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-iframe.html.ini
deleted file mode 100644
index 3446518..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-iframe.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-activate-inside-iframe.html]
-  [activating portal inside iframe should fail]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-portal.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-portal.html.ini
deleted file mode 100644
index 00fe714..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-inside-portal.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-activate-inside-portal.html]
-  [activating a nested portal should throw an error]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-network-error.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-network-error.html.ini
deleted file mode 100644
index c677f2da..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-network-error.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-activate-network-error.html]
-  [A portal that is showing inline content for a network error cannot be activated]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html.ini
deleted file mode 100644
index a9bc4810..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-no-browsing-context.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-activate-no-browsing-context.html]
-  [A portal with nothing in it cannot be activated]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html.ini
deleted file mode 100644
index cdadc3b1..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-resolution.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-activate-resolution.html]
-  [portals-activate-resolution]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-twice.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-twice.html.ini
deleted file mode 100644
index 6ca04ee..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-twice.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[portals-activate-twice.html]
-  [Calling activate when a portal is already activating should fail]
-    expected: FAIL
-
-  [portals-activate-twice]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-activate-while-unloading.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-activate-while-unloading.html.ini
deleted file mode 100644
index 2b405d73..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-activate-while-unloading.html.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[portals-activate-while-unloading.html]
-  expected: TIMEOUT
-  [cannot activate portal from beforeunload]
-    expected: TIMEOUT
-
-  [cannot activate portal from pagehide]
-    expected: NOTRUN
-
-  [cannot activate portal from unload]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html.ini
deleted file mode 100644
index e7b416d9..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-adopt-predecessor.html.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[portals-adopt-predecessor.html]
-  [Tests that a portal can adopt its predecessor.]
-    expected: FAIL
-
-  [Tests that activating an adopted predecessor without inserting it works]
-    expected: FAIL
-
-  [Tests that an adopted portal can be inserted into a disconnected node.]
-    expected: FAIL
-
-  [Tests that an adopting, inserting and then removing a predecessor works correctly]
-    expected: FAIL
-
-  [Tests that the adopted predecessor is destroyed if it isn't inserted]
-    expected: FAIL
-
-  [Tests that trying to adopt the predecessor after the PortalActivateEvent will throw an exception.]
-    expected: FAIL
-
-  [Tests that trying to adopt the predecessor twice will throw an exception.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-api.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-api.html.ini
deleted file mode 100644
index 930ee91..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-api.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-api.html]
-  [portal element exists]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-close-window.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-close-window.html.ini
deleted file mode 100644
index 7e6a236..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-close-window.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-close-window.html]
-  [A portal's window cannot be closed]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html.ini
deleted file mode 100644
index 24a6f9e..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-cross-origin-load.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-cross-origin-load.sub.html]
-  [portals-cross-origin-load]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-focus.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-focus.sub.html.ini
deleted file mode 100644
index 9df3af8..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-focus.sub.html.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[portals-focus.sub.html]
-  [test that a portal is keyboard activatable]
-    expected: FAIL
-
-  [test that a portal is keyboard focusable]
-    expected: FAIL
-
-  [test that a portal's x-origin subframe becomes active element on focus]
-    expected: FAIL
-
-  [test that a x-origin iframe inside an adopted portal cannot steal focus]
-    expected: FAIL
-
-  [test that activeElement inside a portal is updated after focus() is called]
-    expected: FAIL
-
-  [test that an element inside a portal cannot steal focus]
-    expected: FAIL
-
-  [test that an element inside a portal's x-origin subframe cannot steal focus]
-    expected: FAIL
-
-  [test that an element inside an adopted portal cannot steal focus]
-    expected: FAIL
-
-  [test that autofocus inside a portal works]
-    expected: FAIL
-
-  [test that we cannot tab into a portal's contents]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html.ini
deleted file mode 100644
index df0901e..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-host-exposure.sub.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portals-host-exposure.sub.html]
-  [window.portalHost should be exposed in cross-origin portal]
-    expected: FAIL
-
-  [window.portalHost should be exposed in portal after cross-origin navigation]
-    expected: FAIL
-
-  [window.portalHost should be exposed in same-origin portal]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-host-hidden-after-activation.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-host-hidden-after-activation.html.ini
deleted file mode 100644
index f725876..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-host-hidden-after-activation.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-host-hidden-after-activation.html]
-  [window.portalHost should be null after portal is activated]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-host-null.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-host-null.html.ini
deleted file mode 100644
index d4d3d68..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-host-null.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-host-null.html]
-  [portals-host-null]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-host-post-message.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-host-post-message.sub.html.ini
deleted file mode 100644
index ae0752b5..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-host-post-message.sub.html.ini
+++ /dev/null
@@ -1,27 +0,0 @@
-[portals-host-post-message.sub.html]
-  [Calling postMessage after receiving onactivate event should fail]
-    expected: FAIL
-
-  [Message received after postMessage from portal host]
-    expected: FAIL
-
-  [postMessage before and after portal navigation should work]
-    expected: FAIL
-
-  [postMessage should throw error when serialization fails]
-    expected: FAIL
-
-  [postMessage with array buffer with transfer]
-    expected: FAIL
-
-  [postMessage with array buffer without transfer]
-    expected: FAIL
-
-  [postMessage with invalid transferable should throw error]
-    expected: FAIL
-
-  [postMessage with message ports]
-    expected: FAIL
-
-  [postMessage with object message]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-navigate-after-adoption.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-navigate-after-adoption.html.ini
deleted file mode 100644
index 25e024fb..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-navigate-after-adoption.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-navigate-after-adoption.html]
-  [can set portal src during portalactivate]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-nested.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-nested.html.ini
deleted file mode 100644
index 0c0437c..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-nested.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-nested.html]
-  [nested portals shouldn't crash]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html.ini
deleted file mode 100644
index 70878f2..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html.ini
+++ /dev/null
@@ -1,39 +0,0 @@
-[portals-post-message.sub.html]
-  [cannot call postMessage on portal without portal browsing context]
-    expected: FAIL
-
-  [postMessage after activate throws error]
-    expected: FAIL
-
-  [postMessage before activate should work and preserve order]
-    expected: FAIL
-
-  [postMessage during activate throws error]
-    expected: FAIL
-
-  [postMessage message received by portalHost]
-    expected: FAIL
-
-  [postMessage should be blocked for cross-origin portals]
-    expected: FAIL
-
-  [postMessage should fail if message serialization fails]
-    expected: FAIL
-
-  [postMessage should fail with invalid ports]
-    expected: FAIL
-
-  [postMessage with array buffer without transfer]
-    expected: FAIL
-
-  [postMessage with includeUserActivation]
-    expected: FAIL
-
-  [postMessage with message object]
-    expected: FAIL
-
-  [postMessage with message ports and same-origin portal]
-    expected: FAIL
-
-  [postMessage with transferred array buffer]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-header.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-header.html.ini
deleted file mode 100644
index 86c39b8..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-header.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-referrer-inherit-header.html]
-  [portal contents should be loaded with no referrer if document requests it]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-meta.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-meta.html.ini
deleted file mode 100644
index d24dfa0..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-referrer-inherit-meta.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-referrer-inherit-meta.html]
-  [portal contents should be loaded with no referrer if document requests it]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-referrer.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-referrer.html.ini
deleted file mode 100644
index 6651fbda..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-referrer.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portals-referrer.html]
-  [portal contents should be loaded with no referrer if referrerpolicy=no-referrer]
-    expected: FAIL
-
-  [portal contents should be loaded with origin only if referrerpolicy=origin]
-    expected: FAIL
-
-  [portal contents should be loaded with referrer]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html.ini
deleted file mode 100644
index ae07b40..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-rendering.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[portals-rendering.html]
-  expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-repeated-activate.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-repeated-activate.html.ini
deleted file mode 100644
index 1f0d66ab..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-repeated-activate.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-repeated-activate.html]
-  [test activation in page that has been reactivated]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-set-src-after-activate.html.ini b/third_party/blink/web_tests/external/wpt/portals/portals-set-src-after-activate.html.ini
deleted file mode 100644
index 5aa1270..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/portals-set-src-after-activate.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-set-src-after-activate.html]
-  [Tests that a portal element can be fully reused after activate has detached it]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/predecessor-fires-unload.html.ini b/third_party/blink/web_tests/external/wpt/portals/predecessor-fires-unload.html.ini
deleted file mode 100644
index 3f94f18..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/predecessor-fires-unload.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[predecessor-fires-unload.html]
-  [pagehide and unload should fire if the predecessor is not adopted]
-    expected: FAIL
-
-  [pagehide and unload should fire if the predecessor is not adopted, even without a window/opener association]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-deny.sub.html.ini b/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-deny.sub.html.ini
deleted file mode 100644
index 8ec9554..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-deny.sub.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[portals-xfo-deny.sub.html]
-  [Portals blocked by `XFO: DENY` cannot be activated.]
-    expected: FAIL
-
-  [`XFO: DENY` blocks cross-origin portals.]
-    expected: FAIL
-
-  [`XFO: DENY` blocks same-origin portals.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-sameorigin.html.ini b/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-sameorigin.html.ini
deleted file mode 100644
index eb69c6ac..0000000
--- a/third_party/blink/web_tests/external/wpt/portals/xfo/portals-xfo-sameorigin.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[portals-xfo-sameorigin.html]
-  [`XFO: SAMEORIGIN` blocks cross-origin portals.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/__dir__.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/requestidlecallback/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout-when-busy.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout-when-busy.html.ini
deleted file mode 100644
index 4905c1f..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout-when-busy.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[callback-timeout-when-busy.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout.html.ini
deleted file mode 100644
index a5795ef..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-timeout.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[callback-timeout.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-xhr-sync.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-xhr-sync.html.ini
deleted file mode 100644
index de3c0b2..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/callback-xhr-sync.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[callback-xhr-sync.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF-dynamic.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF-dynamic.html.ini
deleted file mode 100644
index ed0c58e..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF-dynamic.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[deadline-max-rAF-dynamic.html]
-  expected:
-    if (product == "content_shell") and (os == "mac"): [TIMEOUT, OK]
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF.html.ini
deleted file mode 100644
index 0f79d87..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-rAF.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[deadline-max-rAF.html]
-  expected:
-    if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): [TIMEOUT, OK]
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-timeout-dynamic.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-timeout-dynamic.html.ini
deleted file mode 100644
index 631da19..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max-timeout-dynamic.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[deadline-max-timeout-dynamic.html]
-  expected:
-    if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [TIMEOUT, OK]
-    if product == "chrome": OK
-    [OK, TIMEOUT]
-  [Check that the deadline is changed if there is a new timeout from within requestIdleCallback.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max.html.ini b/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max.html.ini
deleted file mode 100644
index 3dd5535..0000000
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/deadline-max.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[deadline-max.html]
-  expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/scheduler/tentative/yield/yield-priority-idle-callbacks.html.ini b/third_party/blink/web_tests/external/wpt/scheduler/tentative/yield/yield-priority-idle-callbacks.html.ini
index 946451e..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/scheduler/tentative/yield/yield-priority-idle-callbacks.html.ini
+++ b/third_party/blink/web_tests/external/wpt/scheduler/tentative/yield/yield-priority-idle-callbacks.html.ini
@@ -1,4 +1,2 @@
-[yield-priority-idle-callbacks.html]
-  expected:
-    if product == "chrome": OK
-    TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/__dir__.ini b/third_party/blink/web_tests/external/wpt/shared-storage/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shared-storage/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.ini
deleted file mode 100644
index d11c26a..0000000
--- a/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[select-url-permissions-policy-none.tentative.https.sub.html]
-  [permissions policy header shared-storage-select-url=() disallows sharedStorage.selectURL() in cross-origin iframes.]
-    expected: FAIL
-
-  [permissions policy header shared-storage-select-url=() disallows sharedStorage.selectURL() in same-origin iframes.]
-    expected: FAIL
-
-  [permissions policy header shared-storage-select-url=() disallows sharedStorage.selectURL() in the current page.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.ini
deleted file mode 100644
index 5a7c2d8..0000000
--- a/third_party/blink/web_tests/external/wpt/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[select-url-permissions-policy-self.tentative.https.sub.html]
-  [permissions policy header shared-storage-select-url=(self) disallows sharedStorage.selectURL() in cross-origin iframes.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html.ini
deleted file mode 100644
index 4ddcd7c..0000000
--- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[shared-storage-permissions-policy-default.tentative.https.sub.html]
-  expected:
-    if product == "chrome": TIMEOUT
-    ERROR
-  [Default permissions policy allows sharedStorage in cross-origin iframes.]
-    expected: TIMEOUT
-
-  [Default permissions policy allows sharedStorage in same-origin iframes.]
-    expected: TIMEOUT
-
-  [Default permissions policy allows sharedStorage in the current page.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.ini
deleted file mode 100644
index 049ec35..0000000
--- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[shared-storage-permissions-policy-none.tentative.https.sub.html]
-  expected:
-    if product == "chrome": TIMEOUT
-    ERROR
-  [permissions policy header shared-storage=() disallows sharedStorage in cross-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header shared-storage=() disallows sharedStorage in same-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header shared-storage=() disallows sharedStorage in the current page.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.ini b/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.ini
deleted file mode 100644
index 934ffa5..0000000
--- a/third_party/blink/web_tests/external/wpt/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[shared-storage-permissions-policy-self.tentative.https.sub.html]
-  expected:
-    if product == "chrome": TIMEOUT
-    ERROR
-  [permissions policy header shared-storage=(self) allows sharedStorage in same-origin iframes.]
-    expected: TIMEOUT
-
-  [permissions policy header shared-storage=(self) allows sharedStorage in the current page.]
-    expected: FAIL
-
-  [permissions policy header shared-storage=(self) disallows sharedStorage in cross-origin iframes.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/__dir__.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/anonymous-client.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/anonymous-client.https.html.ini
deleted file mode 100644
index 34f51537..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/anonymous-client.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[anonymous-client.https.html]
-  [test anonymous-client url prefetch for cross origin pages]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/cross-origin-cookies.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/cross-origin-cookies.https.html.ini
deleted file mode 100644
index b8c8e768..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/cross-origin-cookies.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[cross-origin-cookies.https.html]
-  [speculation rules based prefetch should not use cookies for cross origin urls.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html.ini
deleted file mode 100644
index a926331..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html.ini
+++ /dev/null
@@ -1,38 +0,0 @@
-[document-rules.https.html?include=and]
-  [test document rule with conjunction predicate]
-    expected: FAIL
-
-
-[document-rules.https.html?include=defaultPredicate]
-  [test document rule with no predicate]
-    expected: FAIL
-
-
-[document-rules.https.html?include=hrefMatches]
-  [test href_matches document rule]
-    expected: FAIL
-
-
-[document-rules.https.html?include=linkHrefChanged]
-  [test that changing the href of an invalid link to a matching value triggers a prefetch]
-    expected: FAIL
-
-
-[document-rules.https.html?include=linkInShadowTree]
-  [test that matching link in a shadow tree is prefetched]
-    expected: FAIL
-
-
-[document-rules.https.html?include=newRuleSetAdded]
-  [test that adding a second rule set triggers prefetch]
-    expected: FAIL
-
-
-[document-rules.https.html?include=not]
-  [test document rule with negation predicate]
-    expected: FAIL
-
-
-[document-rules.https.html?include=or]
-  [test document rule with disjunction predicate]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/__dir__.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single.https.html.ini
deleted file mode 100644
index efb419ee..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single.https.html.ini
+++ /dev/null
@@ -1,103 +0,0 @@
-[prefetch-single.https.html?1-1]
-  [Use prefetched response as query parameter b has the same value.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?11-11]
-  [Use prefetched response as query parameter c can be ignored.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?12-12]
-  [Use prefetched response as query parameter a can be ignored.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?13-13]
-  [Use prefetched response as query parameter a can be ignored.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?14-14]
-  [Use prefetched response as all query parameters except c can be ignored.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?15-15]
-  [Use prefetched response as all query parameters except c can be ignored. Only the last except matters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?17-17]
-  [Use prefetched response as even though all query parameters except c and d can be ignored, c value matches and d value matches.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?18-18]
-  [Use prefetched response as even though all query parameters except c and d can be ignored, c value matches and d value matches. Some query parameters to be ignored appear multiple times in the query.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?19-19]
-  [Use prefetched response as all query parameters except c can be ignored. Allow extension via parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?20-20]
-  [Use prefetched response as query parameter c can be ignored. Allow extension via parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?21-21]
-  [Use prefetched response as the URLs have the values in different order for a. Allow extension via parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?22-22]
-  [Use prefetched response as the URLs do not vary on any query parameters. Allow extension via parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?23-23]
-  [Use prefetched response as all query parameters except c can be ignored. Allow extension via parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?27-27]
-  [Use the prefetched URL. Non-ASCII key - 2 UTF-8 code units. Don't vary the response on the non-ASCII key.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?28-28]
-  [Use the prefetched URL. Non-ASCII key - 2 UTF-8 code units. Don't vary the response on the non-ASCII key.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?3-3]
-  [Use prefetched response as the URLs do not vary by a and b.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?30-last]
-  [Use the prefetched URL. Non-ASCII key - 2 UTF-8 code units. Vary the response on the non-ASCII key.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?4-4]
-  [Use prefetched response as the URLs do not vary on any query parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?5-5]
-  [Use prefetched response as the URLs do not vary on any query parameters.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?8-8]
-  [Use prefetched response as the URLs have the same values for a.]
-    expected: FAIL
-
-
-[prefetch-single.https.html?9-9]
-  [Use prefetched response as the URLs have the same values for a.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html.ini
deleted file mode 100644
index ee28f8b..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[out-of-document-rule-set.https.html?include=BaseCase]
-  [Base case.]
-    expected: FAIL
-
-
-[out-of-document-rule-set.https.html?include=FollowRedirect]
-  [It should follow redirects and fetch the speculation rules set.]
-    expected: FAIL
-
-
-[out-of-document-rule-set.https.html?include=RelativeUrlForSpeculationRulesSet]
-  [It should fetch a speculation rules set using its relative URL.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/redirect-url.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/redirect-url.https.html.ini
deleted file mode 100644
index 82e95fb..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/redirect-url.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[redirect-url.https.html]
-  [browser should be able to prefetch redirected urls]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy-from-rules.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy-from-rules.https.html.ini
deleted file mode 100644
index 8cce3f7..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy-from-rules.https.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[referrer-policy-from-rules.https.html?2-2]
-  [with "strict-origin" referrer policy in rule set override "no-referrer" of link]
-    expected: FAIL
-
-
-[referrer-policy-from-rules.https.html?3-3]
-  [with "no-referrer" referrer policy in rule set overriding "unsafe-url" of cross-site referring page]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy.https.html.ini
deleted file mode 100644
index ca647c63..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/referrer-policy.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[referrer-policy.https.html?4-last]
-  [with "strict-origin" link referrer policy overriding "no-referrer" of referring page]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/user-pass.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/user-pass.https.html.ini
deleted file mode 100644
index 97d1b6f2..0000000
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/user-pass.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[user-pass.https.html?cross-origin=true]
-  [test www-authenticate basic does not forward credentials to cross-origin pages.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-elem-inline-speculation-rules.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-elem-inline-speculation-rules.tentative.html.ini
index b206c17..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-elem-inline-speculation-rules.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-elem-inline-speculation-rules.tentative.html.ini
@@ -1,4 +1,2 @@
-[csp-script-src-elem-inline-speculation-rules.tentative.html]
-  expected: TIMEOUT
-  [Test if CSP script-src-elem inline-speculation-rules permits inline speculationrules.]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-inline-speculation-rules.tentative.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-inline-speculation-rules.tentative.html.ini
index 1e4b580..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-inline-speculation-rules.tentative.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/csp-script-src-inline-speculation-rules.tentative.html.ini
@@ -1,4 +1,2 @@
-[csp-script-src-inline-speculation-rules.tentative.html]
-  expected: TIMEOUT
-  [Test if CSP script-src inline-speculation-rules permits inline speculationrules.]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-from-rules.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-from-rules.html.ini
index 439636b..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-from-rules.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/referrer-policy-from-rules.html.ini
@@ -1,4 +1,2 @@
-[referrer-policy-from-rules.html?1-1]
-  expected: TIMEOUT
-  [with "strict-origin" referrer policy in rule set overriding "strict-origin-when-cross-origin" of referring page]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restrictions.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restrictions.html.ini
index 3292b9f2..5848c024 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restrictions.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/restrictions.html.ini
@@ -1,4 +1,5 @@
 [restrictions.html]
+  disabled: crbug.com/1126305
   [Geolocation API should be deferred]
     expected: FAIL
 
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/service-workers.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/service-workers.https.html.ini
index 05cc21e6..a7d0de98 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/service-workers.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/service-workers.https.html.ini
@@ -1,4 +1,5 @@
 [service-workers.https.html]
+  disabled: tentatively disabled crbug.com/1302831
   expected:
     if (product == "content_shell") and (os == "win") and (port == "win11"): [TIMEOUT, OK]
     if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/__dir__.ini b/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/has-trust-token-with-no-top-frame.tentative.https.html.ini b/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/has-trust-token-with-no-top-frame.tentative.https.html.ini
deleted file mode 100644
index 3adfdab..0000000
--- a/third_party/blink/web_tests/external/wpt/trust-tokens/end-to-end/has-trust-token-with-no-top-frame.tentative.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[has-trust-token-with-no-top-frame.tentative.https.html]
-  [hasPrivateToken in a destroyed document.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/iframe-blank-inherit.meta/unset/iframe-tag.https.html.ini b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/iframe-blank-inherit.meta/unset/iframe-tag.https.html.ini
index 97edeaf..6294ebc4 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/iframe-blank-inherit.meta/unset/iframe-tag.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/iframe-blank-inherit.meta/unset/iframe-tag.https.html.ini
@@ -1,4 +1,5 @@
 [iframe-tag.https.html]
+  disabled: crbug.com/1001374
   expected: TIMEOUT
   [Upgrade-Insecure-Requests: Expects blocked for iframe-tag to cross-http-downgrade origin and downgrade redirection from https context.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/srcdoc-inherit.meta/unset/iframe-tag.https.html.ini b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/srcdoc-inherit.meta/unset/iframe-tag.https.html.ini
index 97edeaf..6294ebc4 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/srcdoc-inherit.meta/unset/iframe-tag.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/srcdoc-inherit.meta/unset/iframe-tag.https.html.ini
@@ -1,4 +1,5 @@
 [iframe-tag.https.html]
+  disabled: crbug.com/1001374
   expected: TIMEOUT
   [Upgrade-Insecure-Requests: Expects blocked for iframe-tag to cross-http-downgrade origin and downgrade redirection from https context.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/top.meta/unset/iframe-tag.https.html.ini b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/top.meta/unset/iframe-tag.https.html.ini
index 97edeaf..6294ebc4 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/top.meta/unset/iframe-tag.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/gen/top.meta/unset/iframe-tag.https.html.ini
@@ -1,4 +1,5 @@
 [iframe-tag.https.html]
+  disabled: crbug.com/1001374
   expected: TIMEOUT
   [Upgrade-Insecure-Requests: Expects blocked for iframe-tag to cross-http-downgrade origin and downgrade redirection from https context.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/share-module-cross-origin-fails.sub.html.ini b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/share-module-cross-origin-fails.sub.html.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/share-module-cross-origin-fails.sub.html.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-domain-success.sub.html.ini b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-domain-success.sub.html.ini
index 92b86d4..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-domain-success.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-domain-success.sub.html.ini
@@ -1,4 +1,2 @@
-[window-domain-success.sub.html]
-  expected: TIMEOUT
-  [postMessaging to a same-origin-domain (but not same-origin) iframe allows them to instantiate]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-similar-but-cross-origin-success.sub.html.ini b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-similar-but-cross-origin-success.sub.html.ini
index 43b96474..8f1e84e 100644
--- a/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-similar-but-cross-origin-success.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/wasm/serialization/module/window-similar-but-cross-origin-success.sub.html.ini
@@ -1,4 +1,2 @@
-[window-similar-but-cross-origin-success.sub.html]
-  expected: TIMEOUT
-  [postMessaging to a not same-origin-domain, but similar origin, iframe allows them to instantiate]
-    expected: TIMEOUT
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html.ini
index 72b001ea..685bb72 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCConfiguration-iceTransportPolicy.html.ini
@@ -1,4 +1,5 @@
 [RTCConfiguration-iceTransportPolicy.html]
+  disabled: crbug.com/626703 slow timeout test
   expected: TIMEOUT
   [Changing iceTransportPolicy from "all" to "relay" causes an ICE restart which should fail, with no new candidates]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html.ini
index e0f5581..67faf41 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html.ini
@@ -1,4 +1,5 @@
 [RTCPeerConnection-remote-track-mute.https.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [Changing transceiver direction to 'inactive' mutes the remote track]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html.ini
index f4c253e..15a3f0a 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html.ini
@@ -1,4 +1,5 @@
 [RTCPeerConnection-setRemoteDescription-tracks.https.html]
+  disabled: crbug.com/626703
   expected: TIMEOUT
   [removeTrack() makes track.onmute fire and the track to be muted.]
     expected: TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9.https.html.ini b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9.https.html.ini
index 4b957fc..cb393b5 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9.https.html.ini
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simulcast/vp9.https.html.ini
@@ -1,4 +1,5 @@
 [vp9.https.html]
+  disabled: crbug.com/webrtc/14889
   expected:
     if product == "chrome": TIMEOUT
   [VP9 simulcast setup with two streams]
diff --git a/third_party/blink/web_tests/fast/scrolling/scrolling-container-moves-offscreen.html b/third_party/blink/web_tests/fast/scrolling/scrolling-container-moves-offscreen.html
new file mode 100644
index 0000000..13b3c9f
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/scrolling-container-moves-offscreen.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/testdriver.js"></script>
+<script src="../../resources/testdriver-actions.js"></script>
+<script src="../../resources/testdriver-vendor.js"></script>
+<script src="../../resources/gesture-util.js"></script>
+
+<style>
+  #scroller {
+    width: 100px;
+    height: 100px;
+    overflow: scroll;
+    position: relative;
+    background-color: red;
+  }
+
+  #spacer {
+    width: 100px;
+    height: 1000px;
+    background-color: gray;
+    border: solid 1px black;
+  }
+</style>
+
+<body onload="runTest()">
+  <div id="scroller">
+    <div id="spacer"></div>
+  </div>
+  <script>
+
+    function resetScrollerStyle() {
+      scroller.style.transform = '';
+    }
+
+    function listener() {
+      if (scroller.style.transform == '') {
+        scroller.style.transform = 'translateY(1000vh)';
+      }
+    }
+
+    function runTest() {
+      promise_test(async (t) => {
+        await waitForScrollReset(scroller);
+        resetScrollerStyle();
+        waitForCompositorCommit();
+
+        scroller.addEventListener('scroll', listener);
+        let scroller_rect = scroller.getBoundingClientRect();
+        let y = (scroller_rect.top + scroller_rect.bottom) / 2;
+        let x = (scroller_rect.left + scroller_rect.right) / 2;
+
+        let scrollend_promise = waitForScrollendEvent(scroller);
+        await swipe(y - scroller_rect.top,
+          x,
+          y,
+          "up",
+          SPEED_INSTANT /* touch_velocity, fast enough to cause fling */,
+          0             /* fling_velocity, should be zero for touch */,
+          GestureSourceType.TOUCH_INPUT);
+        await scrollend_promise;
+
+        // In the short-term, for a fling, we are okay with simply knowing
+        // that a scroll happened.
+        // TODO(awogbemila): In the long-term, we want to know that the scroll
+        // was completed so this should test for more than just that a scroll
+        // happened.
+        assert_true(scroller.scrollTop > 0, 'fling should happen');
+        assert_greater_than(scroller.getBoundingClientRect().top,
+                            visualViewport.height,
+                            "scroller should be off-screen");
+
+        // Bring the scroller back on-screen and verify that touch-scrolling works.
+        scroller.removeEventListener('scroll', listener);
+        resetScrollerStyle();
+        await waitForScrollReset(scroller);
+        await waitForCompositorCommit();
+        assert_equals(scroller.scrollTop, 0);
+
+        scrollend_promise = waitForScrollendEvent(scroller);
+        await smoothScroll(y - scroller_rect.top,
+          x,
+          y,
+          GestureSourceType.TOUCH_INPUT,
+          "down");
+        await scrollend_promise;
+
+        assert_greater_than(scroller.getBoundingClientRect().top,
+                            visualViewport.offsetTop,
+                            "scroller on-screen, scroller top > viewport top");
+        assert_greater_than(visualViewport.offsetTop + visualViewport.height,
+                            scroller.getBoundingClientRect().bottom,
+                            "scroller on-screen, scroller bottom < viewport bottom.");
+        assert_equals(scroller.scrollTop, y - scroller_rect.top);
+      }, 'fling');
+    }
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/fast/scrolling/unpainted-scroller-expected.txt b/third_party/blink/web_tests/fast/scrolling/unpainted-scroller-expected.txt
new file mode 100644
index 0000000..730ebf6
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/unpainted-scroller-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/fast/scrolling/unpainted-scroller.html b/third_party/blink/web_tests/fast/scrolling/unpainted-scroller.html
new file mode 100644
index 0000000..c9630a5
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/unpainted-scroller.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+  #scroller {
+    position: absolute;
+    overflow: scroll;
+    background: yellow;
+    left: 10px;
+    top: 10px;
+    width: 100px;
+    height: 0px; /* 0-height causes scroller to be unpainted. */
+  }
+</style>
+<div id="scroller"></div>
+
+<body>
+  <script>
+    scroller.animate(
+      [
+        {
+          "transform": "translateX(-10px)",
+          "opacity": "0.8",
+        },
+        {
+          "transform": "translateX(-20px)",
+          "opacity": "0.9",
+        },
+      ], { duration: 1000 });
+    if (window.testRunner)
+      testRunner.dumpAsText();
+  </script>
+  This test passes if it doesn't crash.
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt
index 01c06a0..2fad4bba 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt
@@ -9,10 +9,22 @@
     {
       "name": "LayoutNGBlockFlow DIV id='target'",
       "bounds": [100, 100],
-      "invalidations": [
-        [0, 30, 50, 50]
-      ],
+      "drawsContent": false,
       "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [100, 100],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "position": [0, 80],
+      "bounds": [50, 50],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 2
     }
   ],
   "transforms": [
@@ -24,6 +36,16 @@
         [0, 0, 1, 0],
         [8, 8, 0, 1]
       ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/blink/web_tests/virtual/overlay-scrollbar/README.txt b/third_party/blink/web_tests/virtual/overlay-scrollbar/README.md
similarity index 100%
rename from third_party/blink/web_tests/virtual/overlay-scrollbar/README.txt
rename to third_party/blink/web_tests/virtual/overlay-scrollbar/README.md
diff --git a/third_party/blink/web_tests/wpt_internal/direct-sockets/__dir__.ini b/third_party/blink/web_tests/wpt_internal/direct-sockets/__dir__.ini
index e10005e5..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/direct-sockets/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/direct-sockets/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/__dir__.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/ancestor-throttle.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/ancestor-throttle.https.html.ini
deleted file mode 100644
index bff2d26e..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/ancestor-throttle.https.html.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[ancestor-throttle.https.html]
-  [root(origin1)->fenced(origin1)->iframe(origin2)->iframe(origin2) should honor CSP frame-ancestors headers up until the fenced frame root]
-    expected: FAIL
-
-  [root(origin1)->fenced(origin1)->iframe(origin2)->iframe(origin2) should honor XFO SAMEORIGIN headers up until the fenced frame root]
-    expected: FAIL
-
-  [root(origin1)->fenced(origin2)->iframe(origin1) should honor CSP frame-ancestors headers up until the fenced frame root]
-    expected: FAIL
-
-  [root(origin1)->fenced(origin2)->iframe(origin1) should honor XFO SAMEORIGIN headers up until the fenced frame root]
-    expected: FAIL
-
-  [root(origin1)->fenced(origin2)->iframe(origin2) should honor CSP frame-ancestors headers up until the fenced frame root]
-    expected: FAIL
-
-  [root(origin1)->fenced(origin2)->iframe(origin2) should honor XFO SAMEORIGIN headers up until the fenced frame root]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/anchor-focus.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/anchor-focus.https.html.ini
deleted file mode 100644
index 70a167f4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/anchor-focus.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[anchor-focus.https.html]
-  expected: TIMEOUT
-  [Anchor focusing is allowed on an element in a fenced frame with user activation.]
-    expected: NOTRUN
-
-  [Anchor focusing is blocked on an element in a fenced frame without user activation.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/autofocus-denied.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/autofocus-denied.https.html.ini
deleted file mode 100644
index 35a0999..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/autofocus-denied.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[autofocus-denied.https.html]
-  expected: TIMEOUT
-  [Autofocusing is blocked on an element in a fenced frame as it's treated like a cross-origin subframe.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini
deleted file mode 100644
index 17ac4f0..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/autoplay.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[autoplay.https.html]
-  expected: TIMEOUT
-  [If Autoplay plocy is set to 'user-gesture-required', autoplaying  should be blocked in a fenced frame as it's treated like a cross-origin subframe.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/background-fetch.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/background-fetch.https.html.ini
deleted file mode 100644
index 39a94ac6..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/background-fetch.https.html.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[background-fetch.https.html]
-  [backgroundFetch.fetch]
-    expected: FAIL
-
-  [backgroundFetch.fetch in service worker]
-    expected: FAIL
-
-  [backgroundFetch.get]
-    expected: FAIL
-
-  [backgroundFetch.get in service worker]
-    expected: FAIL
-
-  [backgroundFetch.getIds]
-    expected: FAIL
-
-  [backgroundFetch.getIds in service worker]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html.ini
deleted file mode 100644
index 25f9d422..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/background-sync.https.html.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[background-sync.https.html]
-  [background sync getTags]
-    expected: FAIL
-
-  [background sync getTags in service worker]
-    expected: FAIL
-
-  [background sync register]
-    expected: FAIL
-
-  [background sync register in service worker]
-    expected: FAIL
-
-  [periodic sync getTags]
-    expected: FAIL
-
-  [periodic sync getTags in service worker]
-    expected: FAIL
-
-  [periodic sync register]
-    expected: FAIL
-
-  [periodic sync register in service worker]
-    expected: FAIL
-
-  [periodic sync unregister]
-    expected: FAIL
-
-  [periodic sync unregister in service worker]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/badging.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/badging.https.html.ini
deleted file mode 100644
index dd365387..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/badging.https.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[badging.https.html]
-  expected: TIMEOUT
-  [clearAppBadge should fail from a service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [clearAppBadge should fail inside a fenced frame]
-    expected: NOTRUN
-
-  [setAppBadge should fail from a service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [setAppBadge should fail inside a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/battery_status.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/battery_status.https.html.ini
deleted file mode 100644
index 9799ea7..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/battery_status.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[battery_status.https.html]
-  [battery status should not be read in the fenced frame.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/before-unload.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/before-unload.https.html.ini
deleted file mode 100644
index 75c163f..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/before-unload.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[before-unload.https.html]
-  [before unload event in fenced frames]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/can-load-api.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/can-load-api.https.html.ini
deleted file mode 100644
index 27b4eb4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/can-load-api.https.html.ini
+++ /dev/null
@@ -1,26 +0,0 @@
-[can-load-api.https.html]
-  expected: TIMEOUT
-  [canLoadOpaqueURL called on a page that can load a FF should return true]
-    expected: FAIL
-
-  [canLoadOpaqueURL ignores fallback CSPs]
-    expected: NOTRUN
-
-  [canLoadOpaqueURL ignores unrelated CSPs]
-    expected: NOTRUN
-
-  [canLoadOpaqueURL returns false in a detached frame]
-    expected: NOTRUN
-
-  [canLoadOpaqueURL returns false inside an default fenced frame]
-    expected:
-      if product == "chrome": TIMEOUT
-      NOTRUN
-
-  [canLoadOpaqueURL returns true for all 3 fenced-frame-src allowed values]
-    expected: NOTRUN
-
-  [canLoadOpaqueURL returns true inside an opaque-ads fenced frame]
-    expected:
-      if product == "chrome": FAIL
-      TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/change-src-attribute-after-config-installation-does-not-trigger-navigation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/change-src-attribute-after-config-installation-does-not-trigger-navigation.https.html.ini
deleted file mode 100644
index 9baaa39..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/change-src-attribute-after-config-installation-does-not-trigger-navigation.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[change-src-attribute-after-config-installation-does-not-trigger-navigation.https.html]
-  [Changing the src attribute of a fenced frame when a config with url]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints-meta.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints-meta.https.html.ini
deleted file mode 100644
index 5127e8f..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints-meta.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[client-hints-meta.https.html]
-  [fenced frames not send client hints]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints.https.html.ini
deleted file mode 100644
index 57240da..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/client-hints.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[client-hints.https.html]
-  [fenced frames not send client hints]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html.ini
deleted file mode 100644
index 1cac4f5d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[compute-pressure.https.html]
-  expected: TIMEOUT
-  [PressureObserver.observe() fails in a fenced frame.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation-of-navigated-fenced-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation-of-navigated-fenced-frame.https.html.ini
deleted file mode 100644
index bc20678..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation-of-navigated-fenced-frame.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[config-installation-triggers-navigation-of-navigated-fenced-frame.https.html]
-  expected: TIMEOUT
-  [Installing an inner config to a fenced frame that has navigated triggers]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation.https.html.ini
deleted file mode 100644
index b1a77d03..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-installation-triggers-navigation.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[config-installation-triggers-navigation.https.html]
-  [Installing an inner config to a fenced frame triggers navigation.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-with-empty-url-installation-unloads-navigated-fenced-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/config-with-empty-url-installation-unloads-navigated-fenced-frame.https.html.ini
deleted file mode 100644
index 238abaf..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/config-with-empty-url-installation-unloads-navigated-fenced-frame.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[config-with-empty-url-installation-unloads-navigated-fenced-frame.https.html]
-  expected: TIMEOUT
-  [Installing a config with empty url to a navigated fenced unloads ]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/consume-user-activation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/consume-user-activation.https.html.ini
deleted file mode 100644
index c399dc4e..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/consume-user-activation.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[consume-user-activation.https.html]
-  expected: TIMEOUT
-  [user-activation]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/content-index.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/content-index.https.html.ini
deleted file mode 100644
index 2323a32..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/content-index.https.html.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[content-index.https.html]
-  expected: TIMEOUT
-  [index.add should fail from the service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [index.add should fail inside a fenced frame]
-    expected: TIMEOUT
-
-  [index.delete should fail from the service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [index.delete should fail inside a fenced frame]
-    expected: NOTRUN
-
-  [index.getAll should fail from the service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [index.getAll should fail inside a fenced frame]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/coop-bcg-swap.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/coop-bcg-swap.https.html.ini
deleted file mode 100644
index e98606a..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/coop-bcg-swap.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[coop-bcg-swap.https.html]
-  expected: TIMEOUT
-  [window.name after bcg swap]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/create-credential.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/create-credential.https.html.ini
deleted file mode 100644
index 5203677..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/create-credential.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[create-credential.https.html]
-  [navigator.credentials.create]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/create-in-sandbox-and-adopt-outside-sandbox.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/create-in-sandbox-and-adopt-outside-sandbox.https.html.ini
deleted file mode 100644
index dd1d8cb..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/create-in-sandbox-and-adopt-outside-sandbox.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[create-in-sandbox-and-adopt-outside-sandbox.https.html]
-  expected: TIMEOUT
-  [Adopting a fenced frame from a too-strict document to a suitable document leaves the frame in a functional state]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-allowed.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-allowed.https.html.ini
deleted file mode 100644
index e482ef6d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-allowed.https.html.ini
+++ /dev/null
@@ -1,36 +0,0 @@
-[csp-allowed.https.html]
-  [Fenced frame loaded for CSP fenced-frame-src * using config]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src * using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src https: using config]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src https: using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src https://*:* using config]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src https://*:* using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for * using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for * using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for https: using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for https: using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for https://*:* using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns true for https://*:* using urn:uuid]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-blocked.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-blocked.https.html.ini
deleted file mode 100644
index 207b9b6..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-blocked.https.html.ini
+++ /dev/null
@@ -1,78 +0,0 @@
-[csp-blocked.https.html]
-  [Fenced frame blocked for CSP fenced-frame-src 'none' using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src 'none' using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src 'self' using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src 'self' using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src data: using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src data: using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://* using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://* using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://*:80 using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://*:80 using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://b.test:* using config]
-    expected: FAIL
-
-  [Fenced frame blocked for CSP fenced-frame-src https://b.test:* using urn:uuid]
-    expected: FAIL
-
-  [Fenced frame not loaded using config if any of CSPs in place disallow loading]
-    expected: FAIL
-
-  [Fenced frame not loaded using urn:uuid if any of CSPs in place disallow loading]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for 'none' using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for 'none' using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for 'self' using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for 'self' using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for data: using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for data: using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://* using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://* using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://*:80 using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://*:80 using urn:uuid]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://b.test:* using config]
-    expected: FAIL
-
-  [Opaque-ads can load API returns false for https://b.test:* using urn:uuid]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-allowed.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-allowed.https.html.ini
deleted file mode 100644
index b1ae4730..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-allowed.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[csp-fenced-frame-src-allowed.https.html]
-  [csp-fenced-frame-src-allowed]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-blocked.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-blocked.https.html.ini
deleted file mode 100644
index d23dcfb..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-fenced-frame-src-blocked.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[csp-fenced-frame-src-blocked.https.html]
-  [csp-fenced-frame-src-blocked]
-    expected: FAIL
-
-  [fenced-frame-src none is taken into account with navigator.canLoadAdAuctionFencedFrame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-allowed.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-allowed.https.html.ini
deleted file mode 100644
index 21d50fb..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-allowed.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[csp-frame-src-allowed.https.html]
-  [csp-frame-src-allowed]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-blocked.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-blocked.https.html.ini
deleted file mode 100644
index 14df316..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-frame-src-blocked.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[csp-frame-src-blocked.https.html]
-  [csp-frame-src-blocked]
-    expected: FAIL
-
-  [frame-src none is taken into account with navigator.canLoadAdAuctionFencedFrame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-transparent-url-opaque-ads.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-transparent-url-opaque-ads.https.html.ini
deleted file mode 100644
index a884687..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp-transparent-url-opaque-ads.https.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[csp-transparent-url-opaque-ads.https.html]
-  expected: TIMEOUT
-  [Fenced frame blocked for CSP fenced-frame-src 'none']
-    expected: TIMEOUT
-
-  [Fenced frame loaded for CSP fenced-frame-src 'self']
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src *]
-    expected: FAIL
-
-  [Fenced frame loaded for CSP fenced-frame-src https:]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.https.html.ini
deleted file mode 100644
index 3ee3a442..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/csp.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[csp.https.html]
-  [Fenced Frames should not honor the csp attribute from parent page]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/cspee.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/cspee.https.html.ini
deleted file mode 100644
index 31d6407..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/cspee.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[cspee.https.html]
-  [canLoadOpaqueURL considers CSPEE headers]
-    expected: FAIL
-
-  [canLoadOpaqueURL considers CSPEE headers up the ancestor chain]
-    expected: FAIL
-
-  [canLoadOpaqueURL returns true if no CSPEE headers are present in iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-all.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-all.https.html.ini
deleted file mode 100644
index 081dc89..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-all.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-allow-all.https.html]
-  [Cross-origin fenced frame loads when feature policies are *]
-    expected: FAIL
-
-  [Same-origin fenced frame loads when feature policies are *]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-none.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-none.https.html.ini
deleted file mode 100644
index 048a754a..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-none.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-allow-none.https.html]
-  [Cross-origin fenced frame does not load when feature policies are none]
-    expected: FAIL
-
-  [Same-origin fenced frame does not load when feature policies are none]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-self.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-self.https.html.ini
deleted file mode 100644
index 83398434..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-allow-self.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[default-enabled-features-allow-self.https.html]
-  [A fenced frame redirected to a page that does not allow feature policies does not navigate]
-    expected: FAIL
-
-  [Cross-origin fenced frame does not load when feature policies are self]
-    expected: FAIL
-
-  [Fenced frames default feature policies are set to allow *]
-    expected: FAIL
-
-  [Same-origin fenced frame loads when feature policies are self]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-allow.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-allow.https.html.ini
deleted file mode 100644
index 14cb6c3..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-allow.https.html.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[default-enabled-features-attribute-allow.https.html]
-  expected: TIMEOUT
-  [Cross-origin fenced frame with allow attribute enabling required features]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [Delivered policies can further restrict permissions of a fenced frame]
-    expected:
-      if product == "chrome": TIMEOUT
-      NOTRUN
-
-  [Same-origin fenced frame with allow attribute enabling required features]
-    expected:
-      if product == "chrome": FAIL
-      TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-change.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-change.https.html.ini
deleted file mode 100644
index 72feb9f..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-change.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-attribute-change.https.html]
-  [Changing the allow attribute is a no-op for frame-initiated navigations]
-    expected: FAIL
-
-  [Changing the allow attribute is a no-op for the current navigation]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-disallow.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-disallow.https.html.ini
deleted file mode 100644
index edf9d6d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribute-disallow.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-attribute-disallow.https.html]
-  [Cross-origin fenced frame with allow attribute disabling required feature]
-    expected: FAIL
-
-  [Same-origin fenced frame with allow attribute disabling required feature]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribution-disabled.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribution-disabled.https.html.ini
deleted file mode 100644
index 31e286e..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-attribution-disabled.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-attribution-disabled.https.html]
-  [Cross-origin fenced frame with allow attribute enabling required feature but page disabling feature.]
-    expected: FAIL
-
-  [Same-origin fenced frame with allow attribute enabling required feature but page disabling feature.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-unset.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-unset.https.html.ini
deleted file mode 100644
index 221cd47..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/default-enabled-features-unset.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[default-enabled-features-unset.https.html]
-  [Cross-origin fenced frame loads when feature policies are unset]
-    expected: FAIL
-
-  [Same-origin fenced frame loads when feature policies are unset]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/deprecated-config-apis.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/deprecated-config-apis.https.html.ini
deleted file mode 100644
index 3fa6e6c2..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/deprecated-config-apis.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[deprecated-config-apis.https.html]
-  [deprecated urn APIs should not work with configs generated by a WebIDL constructor]
-    expected: FAIL
-
-  [deprecated urn APIs should work with configs generated by an API]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-blob.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-blob.https.html.ini
deleted file mode 100644
index a380540..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-blob.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[disallowed-navigation-to-blob.https.html]
-  [fenced frame config => blob: URL]
-    expected: FAIL
-
-  [fenced frame urn:uuid => blob: URL]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-data.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-data.https.html.ini
deleted file mode 100644
index ce1162a..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-data.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[disallowed-navigation-to-data.https.html]
-  [fenced frame config => data: URL]
-    expected: FAIL
-
-  [fenced frame urn:uuid => data: URL]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-http.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-http.https.html.ini
deleted file mode 100644
index 5b88d8d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigation-to-http.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[disallowed-navigation-to-http.https.html]
-  [fenced frame config => http: URL]
-    expected: FAIL
-
-  [fenced frame urn:uuid => http: URL]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup-urn.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup-urn.https.html.ini
deleted file mode 100644
index cfbaa19e..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup-urn.https.html.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[disallowed-navigations-dangling-markup-urn.https.html]
-  [fenced frame opaque URN => https: URL with dangling markup 'blo\tck<ed']
-    expected: FAIL
-
-  [fenced frame opaque URN => https: URL with dangling markup 'blo\nck<ed']
-    expected: FAIL
-
-  [fenced frame opaque URN => https: URL with dangling markup 'blo\rck<ed']
-    expected: FAIL
-
-  [fenced frame opaque URN => https: URL with dangling markup 'blo<ck\ted']
-    expected: FAIL
-
-  [fenced frame opaque URN => https: URL with dangling markup 'blo<ck\ned']
-    expected: FAIL
-
-  [fenced frame opaque URN => https: URL with dangling markup 'blo<ck\red']
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup.https.html.ini
deleted file mode 100644
index abc350f79..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations-dangling-markup.https.html.ini
+++ /dev/null
@@ -1,36 +0,0 @@
-[disallowed-navigations-dangling-markup.https.html]
-  [fenced frame mode=default dangling-markup URL with 'blo\tck<ed']
-    expected: FAIL
-
-  [fenced frame mode=default dangling-markup URL with 'blo\nck<ed']
-    expected: FAIL
-
-  [fenced frame mode=default dangling-markup URL with 'blo\rck<ed']
-    expected: FAIL
-
-  [fenced frame mode=default dangling-markup URL with 'blo<ck\ted']
-    expected: FAIL
-
-  [fenced frame mode=default dangling-markup URL with 'blo<ck\ned']
-    expected: FAIL
-
-  [fenced frame mode=default dangling-markup URL with 'blo<ck\red']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo\tck<ed']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo\nck<ed']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo\rck<ed']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo<ck\ted']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo<ck\ned']
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads dangling-markup URL with 'blo<ck\red']
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations.https.html.ini
deleted file mode 100644
index 83e22d54..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/disallowed-navigations.https.html.ini
+++ /dev/null
@@ -1,25 +0,0 @@
-[disallowed-navigations.https.html]
-  expected: TIMEOUT
-  [fenced frame mode=default blob: URL]
-    expected: NOTRUN
-
-  [fenced frame mode=default data: URL]
-    expected: NOTRUN
-
-  [fenced frame mode=default http: URL]
-    expected: NOTRUN
-
-  [fenced frame mode=default javascript: URL]
-    expected: NOTRUN
-
-  [fenced frame mode=opaque-ads blob: URL]
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads data: URL]
-    expected: FAIL
-
-  [fenced frame mode=opaque-ads http: URL]
-    expected: NOTRUN
-
-  [fenced frame mode=opaque-ads javascript: URL]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/document-referrer.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/document-referrer.https.html.ini
deleted file mode 100644
index 5fe59c7..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/document-referrer.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[document-referrer.https.html]
-  expected: TIMEOUT
-  [document.referrer]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/download.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/download.https.html.ini
deleted file mode 100644
index 3c2c702..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/download.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[download.https.html]
-  [Anchor click triggering download in fenced frames is blocked.]
-    expected: FAIL
-
-  [Navigation resulted download in fenced frames is blocked.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-csp-not-propagate.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-csp-not-propagate.https.html.ini
deleted file mode 100644
index 998be84..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-csp-not-propagate.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[embedder-csp-not-propagate.https.html]
-  expected: TIMEOUT
-  [Embedder CSP should not propagate to fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-no-coep.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-no-coep.https.html.ini
deleted file mode 100644
index e98b7d4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-no-coep.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[embedder-no-coep.https.html]
-  expected:
-    if product == "chrome": ERROR
-    TIMEOUT
-  [Create fencedframe with COEP:require-corp]
-    expected: TIMEOUT
-
-  [Create fencedframe without COEP header]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-require-corp.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-require-corp.https.html.ini
deleted file mode 100644
index 7aa74ba5..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/embedder-require-corp.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[embedder-require-corp.https.html]
-  expected:
-    if product == "chrome": ERROR
-    TIMEOUT
-  [Create fencedframe with COEP:require-corp]
-    expected: TIMEOUT
-
-  [Create fencedframe with a cross site COEP:require-corp and CORP:same-orign]
-    expected: NOTRUN
-
-  [Create fencedframe without COEP header]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/fedcm-get-credential.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/fedcm-get-credential.https.html.ini
deleted file mode 100644
index 3552549..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/fedcm-get-credential.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[fedcm-get-credential.https.html]
-  [navigator.credentials.get]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-api.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-api.https.html.ini
deleted file mode 100644
index 6e78c61..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-api.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[fence-api.https.html]
-  [window.fence]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-report-event.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-report-event.https.html.ini
deleted file mode 100644
index 8e432d4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-report-event.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[fence-report-event.https.html]
-  expected: TIMEOUT
-  [window.fence.reportEvent]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-urn-iframes.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-urn-iframes.https.html.ini
deleted file mode 100644
index 2557afd..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/fence-urn-iframes.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[fence-urn-iframes.https.html]
-  [window.fence is available in same-origin subframes of urn iframes]
-    expected: FAIL
-
-  [window.fence is available in urn iframes]
-    expected: FAIL
-
-  [window.fence is unavailable in normal (non-urn) iframes]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/fragment-navigation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/fragment-navigation.https.html.ini
deleted file mode 100644
index 4a3aadd..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/fragment-navigation.https.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[fragment-navigation.https.html]
-  expected: TIMEOUT
-  [opaque to opaque fragment navigation]
-    expected: FAIL
-
-  [opaque to transparent fragment navigation]
-    expected: FAIL
-
-  [transparent to opaque fragment navigation]
-    expected: FAIL
-
-  [transparent to transparent fragment navigation]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/frame-navigation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/frame-navigation.https.html.ini
deleted file mode 100644
index ea223ac5..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/frame-navigation.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[frame-navigation.https.html]
-  [Fenced frame navigation should succeed]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/gamepad.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/gamepad.https.html.ini
deleted file mode 100644
index 5a83ebd..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/gamepad.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[gamepad.https.html]
-  [Gamepads information should not be read in the fenced frame.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/get-mode-in-nested-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/get-mode-in-nested-frame.https.html.ini
deleted file mode 100644
index 0df262c..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/get-mode-in-nested-frame.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[get-mode-in-nested-frame.https.html]
-  expected: TIMEOUT
-  [Trigger GetFencedFrameMode() in a nested nested iframe]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/get-nested-configs.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/get-nested-configs.https.html.ini
deleted file mode 100644
index f689090..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/get-nested-configs.https.html.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[get-nested-configs.https.html]
-  [Navigating an invalid config should be handled gracefully]
-    expected: FAIL
-
-  [Nested configs created by FLEDGE should be navigable by URN iframe]
-    expected: FAIL
-
-  [Nested configs created by FLEDGE should be navigable by fenced frame]
-    expected: FAIL
-
-  [getNestedConfigs() created by FLEDGE should return configurations]
-    expected: FAIL
-
-  [getNestedConfigs() from a default mode frame should be empty]
-    expected: FAIL
-
-  [getNestedConfigs() from a fenced frame with the config from sharedStroage.selectURL() should be empty]
-    expected: FAIL
-
-  [getNestedConfigs() from a fenced frame with the urn:uuid from sharedStroage.selectURL() should be empty]
-    expected: FAIL
-
-  [getNestedConfigs() should work in a same-origin nested iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/header-referrer.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/header-referrer.https.html.ini
deleted file mode 100644
index 9724bdd..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/header-referrer.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[header-referrer.https.html]
-  [header.referrer]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/header-secFetchDest.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/header-secFetchDest.https.html.ini
deleted file mode 100644
index ee710d91..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/header-secFetchDest.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[header-secFetchDest.https.html]
-  [header.secFetchDest]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html.ini
deleted file mode 100644
index fcb72be..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/hid.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[hid.https.html]
-  expected: TIMEOUT
-  [HID getDevice must fail in a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-back-and-forward-should-not-work-in-fenced-tree.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/history-back-and-forward-should-not-work-in-fenced-tree.https.html.ini
deleted file mode 100644
index 5f519077..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-back-and-forward-should-not-work-in-fenced-tree.https.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[history-back-and-forward-should-not-work-in-fenced-tree.https.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-fenced-navigations-replace-do-not-contribute-to-joint.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-fenced-navigations-replace-do-not-contribute-to-joint.https.html.ini
deleted file mode 100644
index 66cf38b..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-fenced-navigations-replace-do-not-contribute-to-joint.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[history-length-fenced-navigations-replace-do-not-contribute-to-joint.https.html]
-  [All fenced navigations should be replace-only and not contribute to joint session history]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-outer-page-navigation-not-reflected-in-fenced.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-outer-page-navigation-not-reflected-in-fenced.https.html.ini
deleted file mode 100644
index 5e7a344..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/history-length-outer-page-navigation-not-reflected-in-fenced.https.html.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[history-length-outer-page-navigation-not-reflected-in-fenced.https.html]
-  expected:
-    if product == "chrome": [ERROR, OK]
-  [history.length should not reflect navigations within outer page in fenced frame]
-    expected: FAIL
-
-  [history.length should not reflect navigations within outer page in fenced frame nexted iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/ignore-child-fenced-frame-onload-event.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/ignore-child-fenced-frame-onload-event.https.html.ini
deleted file mode 100644
index 39839a9..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/ignore-child-fenced-frame-onload-event.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[ignore-child-fenced-frame-onload-event.https.html]
-  [ignore child fenced frame onload event test.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/input-on-coop-fenced-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/input-on-coop-fenced-frame.https.html.ini
deleted file mode 100644
index bb4e4fa..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/input-on-coop-fenced-frame.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[input-on-coop-fenced-frame.https.html]
-  expected: TIMEOUT
-  [Input in non-matching COOP fenced frame doesn't crash.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/insecure-context.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/insecure-context.html.ini
deleted file mode 100644
index 8a35709e..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/insecure-context.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[insecure-context.html]
-  [FencedFrame is not available in an insecure context]
-    expected: FAIL
-
-  [navigator.canLoadAdAuctionFencedFrame looks at insecure contexts]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/intersection-observer.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/intersection-observer.https.html.ini
deleted file mode 100644
index b801211..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/intersection-observer.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[intersection-observer.https.html]
-  [Intersection Observer Test]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/invalid-url.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/invalid-url.https.html.ini
deleted file mode 100644
index ab44e9cb..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/invalid-url.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[invalid-url.https.html]
-  [URL with invalid port specified]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/key-scrolling.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/key-scrolling.https.html.ini
deleted file mode 100644
index 5934890..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/key-scrolling.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[key-scrolling.https.html]
-  expected: TIMEOUT
-  [Keyboard scrolling bubbles out of fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/loading.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/loading.https.html.ini
deleted file mode 100644
index ad372b8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/loading.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[loading.https.html]
-  [fenced frame loading a config.]
-    expected: FAIL
-
-  [fenced frame loading an urn:uuid.]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/location-ancestorOrigins.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/location-ancestorOrigins.https.html.ini
deleted file mode 100644
index 25811c4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/location-ancestorOrigins.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[location-ancestorOrigins.https.html]
-  [location.ancestorOrigins]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini
deleted file mode 100644
index 160624d8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/maxframes.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[maxframes.https.html]
-  [Max Subframes Test]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/mediaDevices-setCaptureHandle.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/mediaDevices-setCaptureHandle.https.html.ini
deleted file mode 100644
index 739f4e3..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/mediaDevices-setCaptureHandle.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[mediaDevices-setCaptureHandle.https.html]
-  expected: TIMEOUT
-  [navigator.mediaDevices.setCaptureHandleConfig]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html.ini
deleted file mode 100644
index 72bce26..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[navigate-ancestor-by-name.https.html]
-  expected: TIMEOUT
-  [navigate named ancestors]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-fenced-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-fenced-frame.https.html.ini
deleted file mode 100644
index 009fc92..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-fenced-frame.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[navigate-ancestor-nested-fenced-frame.https.html]
-  [Nested fenced frames that navigate _parent end up navigating themselves]
-    expected: FAIL
-
-  [Nested fenced frames that navigate _top end up navigating themselves]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-iframe.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-iframe.https.html.ini
deleted file mode 100644
index 0f37f40..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-nested-iframe.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[navigate-ancestor-nested-iframe.https.html]
-  [Iframes nested in fenced frames fail to navigate _parent]
-    expected: FAIL
-
-  [Iframes nested in fenced frames fail to navigate _top]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-top-level-fenced-frame.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-top-level-fenced-frame.https.html.ini
deleted file mode 100644
index 26e0ba8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-top-level-fenced-frame.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[navigate-ancestor-top-level-fenced-frame.https.html]
-  [Top-level fenced frames that navigate _parent end up navigating themselves]
-    expected: FAIL
-
-  [Top-level fenced frames that navigate _top end up navigating themselves]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html.ini
deleted file mode 100644
index d7e7add4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[navigate-descendant-by-name.https.html]
-  [navigate iframe nested in a fenced frame by name]
-    expected: FAIL
-
-  [navigate nested fenced frame by name]
-    expected: FAIL
-
-  [navigate top-level fenced frame by name]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html.ini
deleted file mode 100644
index 271bba3..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[navigate-related-page-by-name.https.html]
-  expected: TIMEOUT
-  [navigate fenced frames inside related pages from the embedder]
-    expected: NOTRUN
-
-  [navigate related pages from inside a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-layout-map.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-layout-map.https.html.ini
deleted file mode 100644
index e9fcde99..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-layout-map.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[navigator-keyboard-layout-map.https.html]
-  [keyboard.getLayoutMap()]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-lock.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-lock.https.html.ini
deleted file mode 100644
index 0ee6a9e9..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-keyboard-lock.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[navigator-keyboard-lock.https.html]
-  [keyboard.lock]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-subapp.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-subapp.https.html.ini
deleted file mode 100644
index 22ce698..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-subapp.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[navigator-subapp.https.html]
-  expected: TIMEOUT
-  [navigator.subApps.list() should fail in the fenced frame.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-vibrate.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-vibrate.https.html.ini
deleted file mode 100644
index c0779f7..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-vibrate.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[navigator-vibrate.https.html]
-  expected: TIMEOUT
-  [navigator.vibrate]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-virtualkeyboard.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-virtualkeyboard.https.html.ini
deleted file mode 100644
index efcf5a8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigator-virtualkeyboard.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[navigator-virtualkeyboard.https.html]
-  expected: TIMEOUT
-  [virtualKeyboard.overlaysContent]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/nested-opaque-ad-sizes.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/nested-opaque-ad-sizes.https.html.ini
deleted file mode 100644
index 5b39484..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/nested-opaque-ad-sizes.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[nested-opaque-ad-sizes.https.html]
-  [nested fenced frames don't use the size list]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/notification.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/notification.https.html.ini
deleted file mode 100644
index 7702f32..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/notification.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[notification.https.html]
-  [new Notification should fail from the service worker in a fenced frame]
-    expected: FAIL
-
-  [new Notification should fail inside a fenced frame]
-    expected: FAIL
-
-  [showNotification() should fail from the service worker in a fenced frame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/opaque-ad-sizes.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/opaque-ad-sizes.https.html.ini
deleted file mode 100644
index d6fdec805..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/opaque-ad-sizes.https.html.ini
+++ /dev/null
@@ -1,57 +0,0 @@
-[opaque-ad-sizes.https.html]
-  [0x100]
-    expected: FAIL
-
-  [100x0]
-    expected: FAIL
-
-  [160x600]
-    expected: FAIL
-
-  [300x1050]
-    expected: FAIL
-
-  [300x250]
-    expected: FAIL
-
-  [300x600]
-    expected: FAIL
-
-  [320x100]
-    expected: FAIL
-
-  [320x48]
-    expected: FAIL
-
-  [320x50]
-    expected: FAIL
-
-  [336x280]
-    expected: FAIL
-
-  [728x90]
-    expected: FAIL
-
-  [970.1x250]
-    expected: FAIL
-
-  [970x250]
-    expected: FAIL
-
-  [970x250.1]
-    expected: FAIL
-
-  [970x251]
-    expected: FAIL
-
-  [970x90]
-    expected: FAIL
-
-  [971x250]
-    expected: FAIL
-
-  [INFINITYxINFINITY]
-    expected: FAIL
-
-  [MAXxMAX]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-handler.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-handler.https.html.ini
deleted file mode 100644
index 98fcfa2d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-handler.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[payment-handler.https.html]
-  expected: TIMEOUT
-  [paymentManager should fail from the service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [paymentManager should fail inside a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-request.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-request.https.html.ini
deleted file mode 100644
index ce0e7329..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/payment-request.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[payment-request.https.html]
-  expected: TIMEOUT
-  [new PaymentRequest should fail inside a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied-non-standard.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied-non-standard.https.html.ini
deleted file mode 100644
index 228b804..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied-non-standard.https.html.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[permission-api-denied-non-standard.https.html]
-  [Permission API in fenced frames should always return denied]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 1]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 2]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 3]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 4]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 5]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 6]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 7]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 8]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 9]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied.https.html.ini
deleted file mode 100644
index 24c07c7..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-api-denied.https.html.ini
+++ /dev/null
@@ -1,48 +0,0 @@
-[permission-api-denied.https.html]
-  [Permission API in fenced frames should always return denied]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 1]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 10]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 11]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 12]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 13]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 14]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 15]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 2]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 3]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 4]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 5]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 6]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 7]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 8]
-    expected: FAIL
-
-  [Permission API in fenced frames should always return denied 9]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-geolocation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-geolocation.https.html.ini
deleted file mode 100644
index 0cb560f..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-geolocation.https.html.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[permission-geolocation.https.html]
-  expected: TIMEOUT
-  [geolocation permission is not permitted for fenced frames]
-    expected: TIMEOUT
-
-  [geolocation permission is not permitted for fenced frames, even if a `Permissions-Policy` header and an `allow` attribute is set for an iframe in the fenced frame.]
-    expected: NOTRUN
-
-  [geolocation permission is not permitted for fenced frames, even if a `Permissions-Policy` header is sent on the fenced frame response.]
-    expected: NOTRUN
-
-  [geolocation permission is not permitted for fenced frames, even if a `Permissions-Policy` header is sent on the primary page.]
-    expected: NOTRUN
-
-  [geolocation permission is not permitted for fenced frames, even if an `allow` attribute is set for an iframe in the fenced frame.]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-notification.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-notification.https.html.ini
deleted file mode 100644
index effca6a8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/permission-notification.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[permission-notification.https.html]
-  [notification permission should not be granted]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/picture-in-picture.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/picture-in-picture.https.html.ini
deleted file mode 100644
index 692c863..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/picture-in-picture.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[picture-in-picture.https.html]
-  expected: TIMEOUT
-  [Test HTMLVideoElement.requestPictureInPicture]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/popup-noopener.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/popup-noopener.https.html.ini
deleted file mode 100644
index 89e2345..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/popup-noopener.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[popup-noopener.https.html]
-  [Create popup from iframe nested in a fenced frame]
-    expected: FAIL
-
-  [Create popup from nested fenced frame]
-    expected: FAIL
-
-  [Create popup from top-level fenced frame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/prerender.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/prerender.https.html.ini
deleted file mode 100644
index caf94ab4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/prerender.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[prerender.https.html]
-  expected: TIMEOUT
-  [Fenced Frame must not load prerendered page.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/presentation-receiver.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/presentation-receiver.https.html.ini
deleted file mode 100644
index aa1c09d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/presentation-receiver.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[presentation-receiver.https.html]
-  [presentation receiver should not be allowed]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/reinsert.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/reinsert.https.html.ini
deleted file mode 100644
index 828a2d8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/reinsert.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reinsert.https.html]
-  [Fenced frames should not crash and burn when re-inserting a fenced frame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-input.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-input.https.html.ini
deleted file mode 100644
index ef753b9..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-input.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[resize-lock-input.https.html]
-  [Test Resize Lock]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-zoom.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-zoom.https.html.ini
deleted file mode 100644
index 2ff71ef..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock-zoom.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[resize-lock-zoom.https.html]
-  [Test Resize Lock]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock.https.html.ini
deleted file mode 100644
index 310d6109..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/resize-lock.https.html.ini
+++ /dev/null
@@ -1,28 +0,0 @@
-[resize-lock.https.html]
-  expected: TIMEOUT
-  [FLEDGE->FLEDGE]
-    expected: FAIL
-
-  [FLEDGE->default]
-    expected: NOTRUN
-
-  [FLEDGE->sharedStorage]
-    expected: NOTRUN
-
-  [default->FLEDGE]
-    expected: NOTRUN
-
-  [default->default]
-    expected: TIMEOUT
-
-  [default->sharedStorage]
-    expected: NOTRUN
-
-  [sharedStorage->FLEDGE]
-    expected: NOTRUN
-
-  [sharedStorage->default]
-    expected: NOTRUN
-
-  [sharedStorage->sharedStorage]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandbox-mandatory-flags.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandbox-mandatory-flags.https.html.ini
deleted file mode 100644
index 8ef5cd6..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandbox-mandatory-flags.https.html.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[sandbox-mandatory-flags.https.html]
-  expected: TIMEOUT
-  [Nested sandboxed iframe without one of mandatory flag must fail to load afenced frame even when the inner nested sandboxed iframe has all mandatory allow- flags.]
-    expected: NOTRUN
-
-  [Sandboxed Iframe with mandatory flags can load a fenced frame.]
-    expected: TIMEOUT
-
-  [Sandboxed Iframe without one of mandatory flag must fail to load a fenced frame.]
-    expected: NOTRUN
-
-  [navigator.canLoadAdAuctionFencedFrame considers mandatory sandbox flags]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-alert.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-alert.https.html.ini
deleted file mode 100644
index d752bb2..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-alert.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-alert.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to open an alert dialog.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to open an alert dialog.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-confirm.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-confirm.https.html.ini
deleted file mode 100644
index 397bceb..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-confirm.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-confirm.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to open a confirm dialog.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to open a confirm dialog.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-documentdomain.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-documentdomain.https.html.ini
deleted file mode 100644
index 8a6db06..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-documentdomain.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-documentdomain.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to change Document.domain.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to change Document.domain.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-pointerlock.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-pointerlock.https.html.ini
deleted file mode 100644
index 7d3cdb0..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-pointerlock.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-pointerlock.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to call requestPointerLock().]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to call requestPointerLock().[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-presentation-request.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-presentation-request.https.html.ini
deleted file mode 100644
index b6be60b3..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-presentation-request.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-presentation-request.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to create a PresentationRequest.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to create a PresentationRequest.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-printdialog.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-printdialog.https.html.ini
deleted file mode 100644
index 83c356263..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-printdialog.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-printdialog.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to print the page.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to print the page.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-prompt.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-prompt.https.html.ini
deleted file mode 100644
index fc815528..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-prompt.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-prompt.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to open a prompt.]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to open a prompt.[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-screen-orientation-lock.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-screen-orientation-lock.https.html.ini
deleted file mode 100644
index abe81b8a..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/sandboxed-features-screen-orientation-lock.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[sandboxed-features-screen-orientation-lock.https.html]
-  expected: TIMEOUT
-  [The fenced frame must fail to call screen.orientation.lock().]
-    expected: TIMEOUT
-
-  [The fenced frame must fail to call screen.orientation.lock().[looser sandboxed\]]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/script-focus.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/script-focus.https.html.ini
deleted file mode 100644
index 5e120f1..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/script-focus.https.html.ini
+++ /dev/null
@@ -1,28 +0,0 @@
-[script-focus.https.html]
-  expected: TIMEOUT
-  [A fenced frame can pull window.focus() after user activation]
-    expected: NOTRUN
-
-  [A fenced frame cannot pull window.focus() without user activation]
-    expected: NOTRUN
-
-  [A fenced frame nested in another fenced frame cannot pull focus]
-    expected: NOTRUN
-
-  [An cross-origin iframe can pull focus back and forth without activation]
-    expected: NOTRUN
-
-  [An embedder can focus out of a fenced frame]
-    expected: TIMEOUT
-
-  [Another fenced frame cannot pull focus out of a focused fenced frame]
-    expected: NOTRUN
-
-  [Fenced frames can't pull script focus until getting user activation]
-    expected: NOTRUN
-
-  [Focused fenced frames can move programmatic focus within frame]
-    expected: NOTRUN
-
-  [Script focus into a fenced frame consumes user activation]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/selecturl-flexible-size.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/selecturl-flexible-size.https.html.ini
deleted file mode 100644
index 09ec0ca..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/selecturl-flexible-size.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[selecturl-flexible-size.https.html]
-  [299x72->100x101]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/self-urn-navigation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/self-urn-navigation.https.html.ini
deleted file mode 100644
index 66b6e36..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/self-urn-navigation.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[self-urn-navigation.https.html]
-  [fenced frame-initiated self urn navigation]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html.ini
deleted file mode 100644
index a1ba492..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-dedicated-worker.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[serviceWorker-dedicated-worker.https.html]
-  [Fenced frame's service workers can control fenced frame's dedicated workers]
-    expected: FAIL
-
-  [Fenced frame's service workers can not control the dedicated workers in the parent frame]
-    expected: FAIL
-
-  [Service workers in the parent frame of fenced frames can not control dedicated workers in fenced frames]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-frameType.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-frameType.https.html.ini
deleted file mode 100644
index ae253ac..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-frameType.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[serviceWorker-frameType.https.html]
-  [serviceWorker.frameType]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-push.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-push.https.html.ini
deleted file mode 100644
index b29746f7..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/serviceWorker-push.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[serviceWorker-push.https.html]
-  expected: TIMEOUT
-  [subscribe() should fail from the service worker inside a fenced frame]
-    expected: NOTRUN
-
-  [subscribe() should fail inside a fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/set-automatic-beacon.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/set-automatic-beacon.https.html.ini
deleted file mode 100644
index 5b4f7a1..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/set-automatic-beacon.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[set-automatic-beacon.https.html]
-  [setReportEventDataForAutomaticBeacons fails for invalid destination]
-    expected: FAIL
-
-  [setReportEventDataForAutomaticBeacons fails over the size limit]
-    expected: FAIL
-
-  [setReportEventDataForAutomaticBeacons works at the size limit]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/show-directory-picker.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/show-directory-picker.https.html.ini
deleted file mode 100644
index 78aef5b..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/show-directory-picker.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[show-directory-picker.https.html]
-  expected: TIMEOUT
-  [Directory information should not be read in the fenced frame.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/show-open-file-picker.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/show-open-file-picker.https.html.ini
deleted file mode 100644
index 1a4ad604..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/show-open-file-picker.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[show-open-file-picker.https.html]
-  expected: TIMEOUT
-  [Directory information should not be read in the fenced frame.]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/storage-partitioning.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/storage-partitioning.https.html.ini
deleted file mode 100644
index d2eea43..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/storage-partitioning.https.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[storage-partitioning.https.html]
-  expected: TIMEOUT
-  [document.cookie]
-    expected: TIMEOUT
-
-  [localStorage]
-    expected: NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini
deleted file mode 100644
index 0101260..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus-last-element.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[tab-focus-last-element.https.html]
-  [Tab focus last element]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini
deleted file mode 100644
index 42555c9..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/tab-focus.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[tab-focus.https.html]
-  [Tab focus]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini
deleted file mode 100644
index 5a743c43..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/unfenced-top.https.html.ini
+++ /dev/null
@@ -1,45 +0,0 @@
-[unfenced-top.https.html]
-  expected: TIMEOUT
-  [_unfencedTop :blob URL failure]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [_unfencedTop :javascript URL failure]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [_unfencedTop fragment navigation]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [_unfencedTop in default fenced frame]
-    expected:
-      if product == "chrome": TIMEOUT
-      NOTRUN
-
-  [_unfencedTop in opaque-ads -> default fenced frame]
-    expected:
-      if product == "chrome": NOTRUN
-
-  [_unfencedTop opaque-ads nested iframe success case]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [_unfencedTop opaque-ads non-refresh success case]
-    expected:
-      if product == "chrome": FAIL
-      TIMEOUT
-
-  [_unfencedTop opaque-ads refresh success case]
-    expected:
-      if product == "chrome": FAIL
-      NOTRUN
-
-  [_unfencedTop outside a fenced frame]
-    expected:
-      if product == "chrome": PASS
-      NOTRUN
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/unique-cookie-partition.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/unique-cookie-partition.https.html.ini
deleted file mode 100644
index da8f2c6f..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/unique-cookie-partition.https.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[unique-cookie-partition.https.html]
-  [Cookie access from iframe nested in a fenced frame]
-    expected: FAIL
-
-  [Cookie access from nested fenced frame]
-    expected: FAIL
-
-  [Cookie access from top-level fenced frame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/user-activation.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/user-activation.https.html.ini
deleted file mode 100644
index b08d165a..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/user-activation.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[user-activation.https.html]
-  expected: TIMEOUT
-  [user-activation]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/visual-viewport.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/visual-viewport.https.html.ini
deleted file mode 100644
index abd881b..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/visual-viewport.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[visual-viewport.https.html]
-  expected: TIMEOUT
-  [visualViewport values inside fenced frame]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-bluetooth.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/web-bluetooth.https.html.ini
deleted file mode 100644
index ddee410..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-bluetooth.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[web-bluetooth.https.html]
-  [Web Bluetooth requestDevice() must fail in a fenced frame]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-nfc.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/web-nfc.https.html.ini
deleted file mode 100644
index 049cc9f6..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-nfc.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[web-nfc.https.html]
-  [Test Web NFC API]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-share.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/web-share.https.html.ini
deleted file mode 100644
index 0baf1fc4..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-share.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[web-share.https.html]
-  [Web Sharelock in a fenced frame must fail]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-usb.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/web-usb.https.html.ini
deleted file mode 100644
index cbc8d1b..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/web-usb.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[web-usb.https.html]
-  expected: TIMEOUT
-  [navigator.usb.requestDevice]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-close.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-close.https.html.ini
deleted file mode 100644
index baf07df..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-close.https.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[window-close.https.html]
-  expected: TIMEOUT
-  [window.close]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-frameElement.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-frameElement.https.html.ini
deleted file mode 100644
index 5d1c8a1..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-frameElement.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-frameElement.https.html]
-  [window.frameElement null for same-origin fenced frames]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-navigation-204.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-navigation-204.https.html.ini
deleted file mode 100644
index 98b0d5d..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-navigation-204.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-navigation-204.https.html]
-  [window.navigation.204]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-outer-dimensions.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-outer-dimensions.https.html.ini
deleted file mode 100644
index 8ccd5fd1..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-outer-dimensions.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[window-outer-dimensions.https.html]
-  [window.outerHeight]
-    expected: FAIL
-
-  [window.outerHeight nested iframe]
-    expected: FAIL
-
-  [window.outerWidth]
-    expected: FAIL
-
-  [window.outerWidth nested iframe]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-parent.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-parent.https.html.ini
deleted file mode 100644
index 40ba19c..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-parent.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-parent.https.html]
-  [window.parent]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-top.https.html.ini b/third_party/blink/web_tests/wpt_internal/fenced_frame/window-top.https.html.ini
deleted file mode 100644
index a3772a8..0000000
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/window-top.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[window-top.https.html]
-  [window.top]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/js/shared_memory/__dir__.ini b/third_party/blink/web_tests/wpt_internal/js/shared_memory/__dir__.ini
index 74535e63..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/js/shared_memory/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/js/shared_memory/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True  # not run in rwt either
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/lazyembed/__dir__.ini b/third_party/blink/web_tests/wpt_internal/lazyembed/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/lazyembed/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/lazyembed/automatic-lazy-frame-loading.sub.html.ini b/third_party/blink/web_tests/wpt_internal/lazyembed/automatic-lazy-frame-loading.sub.html.ini
deleted file mode 100644
index 421f2f6..0000000
--- a/third_party/blink/web_tests/wpt_internal/lazyembed/automatic-lazy-frame-loading.sub.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[automatic-lazy-frame-loading.sub.html]
-  [Automatic lazy frame loading with timeout]
-    expected: FAIL
-
-  [LazyEmbeds for below the fold]
-    expected: FAIL
-
-  [LazyEmbeds timeout is prioritized than LazyAds whtn the frame is eligible for both]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/__dir__.ini b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/__dir__.ini
index e10005e5..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/origin-agent-cluster-default-warning/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/pending-beacon/__dir__.ini b/third_party/blink/web_tests/wpt_internal/pending-beacon/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/pending-beacon/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/portals/__dir__.ini b/third_party/blink/web_tests/wpt_internal/portals/__dir__.ini
index 74535e63..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/portals/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/portals/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True  # not run in rwt either
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage/__dir__.ini b/third_party/blink/web_tests/wpt_internal/shared_storage/__dir__.ini
index 74535e63..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/shared_storage/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/shared_storage/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True  # not run in rwt either
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/__dir__.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html.ini
deleted file mode 100644
index fdfbdfd..0000000
--- a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[report-event-limit-with-nested.https.html]
-  [window.fence.reportEvent]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html.ini
deleted file mode 100644
index 1fb5454..0000000
--- a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[report-event-limit.https.html]
-  [window.fence.reportEvent]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/__dir__.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit-multiple-origins.https.html.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit-multiple-origins.https.html.ini
deleted file mode 100644
index 53bff4d..0000000
--- a/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit-multiple-origins.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[run-url-selection-operation-limit-multiple-origins.https.html]
-  expected:
-    if product == "chrome": TIMEOUT
-    ERROR
-  [selectURL() with overall per-pageload limit]
-    expected: TIMEOUT
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit.https.html.ini b/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit.https.html.ini
deleted file mode 100644
index 6bc22e7..0000000
--- a/third_party/blink/web_tests/wpt_internal/shared_storage_selecturl_limit/run-url-selection-operation-limit.https.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[run-url-selection-operation-limit.https.html]
-  [selectURL() with per-origin per-pageload limit]
-    expected: FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/task-tracking/__dir__.ini b/third_party/blink/web_tests/wpt_internal/task-tracking/__dir__.ini
index 74535e63..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/task-tracking/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/task-tracking/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True  # not run in rwt either
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/trust-tokens/__dir__.ini b/third_party/blink/web_tests/wpt_internal/trust-tokens/__dir__.ini
index e10005e5..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/trust-tokens/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/trust-tokens/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/__dir__.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/__dir__.ini
new file mode 100644
index 0000000..8f1e84e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/__dir__.ini
@@ -0,0 +1,2 @@
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/reload-crash.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/reload-crash.html.ini
deleted file mode 100644
index e1659b9..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/reload-crash.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[reload-crash.html]
-  expected: [ERROR, PASS]
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-and-nested-element-transition.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-and-nested-element-transition.html.ini
deleted file mode 100644
index e1161b9b..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-and-nested-element-transition.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[root-and-nested-element-transition.html]
-  expected:
-    if product == "chrome": [FAIL, ERROR]
-    FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-new.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-new.html.ini
deleted file mode 100644
index ae1b14f..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-new.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-transition-no-opt-in-on-new.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-old.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-old.html.ini
deleted file mode 100644
index 6ffc9e0..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-no-opt-in-on-old.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-transition-no-opt-in-on-old.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-new.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-new.html.ini
deleted file mode 100644
index b91618c..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-new.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-transition-opt-in-removed-on-new.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-old.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-old.html.ini
deleted file mode 100644
index ff782080..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition-opt-in-removed-on-old.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[root-element-transition-opt-in-removed-on-old.html]
-  expected: ERROR
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini b/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini
deleted file mode 100644
index b29fbb59..0000000
--- a/third_party/blink/web_tests/wpt_internal/view-transition-on-navigation/root-element-transition.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[root-element-transition.html]
-  expected:
-    if product == "chrome": [ERROR, FAIL]
-    FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/view-transition/__dir__.ini b/third_party/blink/web_tests/wpt_internal/view-transition/__dir__.ini
index e10005e5..8f1e84e 100644
--- a/third_party/blink/web_tests/wpt_internal/view-transition/__dir__.ini
+++ b/third_party/blink/web_tests/wpt_internal/view-transition/__dir__.ini
@@ -1 +1,2 @@
-disabled: @True
+disabled:
+  skipped due to exclusive virtual tests
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6729ddbc..6b4983f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -61046,7 +61046,6 @@
   <int value="-336768659" label="NtpPhotosModule:enabled"/>
   <int value="-335331552" label="TabGroupsForTablets:disabled"/>
   <int value="-334873793" label="MediaSessionNotification:enabled"/>
-  <int value="-333216449" label="MouseSubframeNoImplicitCapture:enabled"/>
   <int value="-332010491" label="RetailCoupons:enabled"/>
   <int value="-331952590" label="OmniboxTriggerForPrerender2:enabled"/>
   <int value="-331137136"
@@ -64327,7 +64326,6 @@
       label="AutofillEnableOffersInClankKeyboardAccessory:enabled"/>
   <int value="1486171015" label="disable-fill-on-account-select"/>
   <int value="1486347614" label="IsolatedWebApps:disabled"/>
-  <int value="1486784197" label="MouseSubframeNoImplicitCapture:disabled"/>
   <int value="1487341558" label="MacViewsAutofillPopup:enabled"/>
   <int value="1488193175" label="ChromeOSAssistant:enabled"/>
   <int value="1488700164" label="password-import:disabled"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 2cedfa3..9a94a5c7d 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4401,6 +4401,25 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Ash.Personalization.KeyboardBacklight.ZoneColors.Zone{ZoneIdx}.Settled"
+    enum="PersonalizationKeyboardBacklightColor" expires_after="2024-03-25">
+  <owner>thuongphan@chromium.org</owner>
+  <owner>assistive-eng@google.com</owner>
+  <summary>
+    Records the keyboard backlight color for zone {ZoneIdx} that the user has
+    settled on. Emitted once for every UMA upload if the user currently uses
+    customized zone colors for keyboard backlight.
+  </summary>
+  <token key="ZoneIdx">
+    <variant name="1" summary="Zone 1"/>
+    <variant name="2" summary="Zone 2"/>
+    <variant name="3" summary="Zone 3"/>
+    <variant name="4" summary="Zone 4"/>
+    <variant name="5" summary="Zone 5"/>
+  </token>
+</histogram>
+
 <histogram name="Ash.Personalization.Path" enum="PersonalizationPath"
     expires_after="2023-08-20">
   <owner>jasontt@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 8d51d1b..ffd63b3b 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1917,7 +1917,7 @@
   </summary>
 </histogram>
 
-<histogram name="Omnibox.SuggestionUsed.Search.InputToNavigationStart"
+<histogram name="Omnibox.SuggestionUsed.Search.InputToNavigationStart2"
     units="ms" expires_after="2023-08-20">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
@@ -2012,7 +2012,7 @@
   </summary>
 </histogram>
 
-<histogram name="Omnibox.SuggestionUsed.URL.InputToNavigationStart" units="ms"
+<histogram name="Omnibox.SuggestionUsed.URL.InputToNavigationStart2" units="ms"
     expires_after="2023-08-20">
   <owner>spelchat@chromium.org</owner>
   <owner>chrome-brapp-loading@google.com</owner>
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 971468b..a4d3192 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -449,6 +449,8 @@
   sources = [
     "javatests/src/org/chromium/ui/test/util/BlankUiTestActivity.java",
     "javatests/src/org/chromium/ui/test/util/BlankUiTestActivityTestCase.java",
+    "javatests/src/org/chromium/ui/test/util/DeviceRestriction.java",
+    "javatests/src/org/chromium/ui/test/util/DeviceRestrictionSkipCheck.java",
     "javatests/src/org/chromium/ui/test/util/DisableAnimationsTestRule.java",
     "javatests/src/org/chromium/ui/test/util/MockitoHelper.java",
     "javatests/src/org/chromium/ui/test/util/NightModeTestUtils.java",
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestriction.java b/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestriction.java
new file mode 100644
index 0000000..1a2fe81c79
--- /dev/null
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestriction.java
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui.test.util;
+
+import org.chromium.base.test.util.Restriction;
+
+/**
+ * DeviceRestrictions list device form factor restrictions, that are usable with the {@link
+ * Restriction} annotation in layers depending on device type.
+ * E.g. <code>
+ *   \@Restriction({DeviceRestriction.RESTRICTION_TYPE_AUTO})
+ * </code>
+ */
+
+public final class DeviceRestriction {
+    /** Specifies the test is only valid on automotive form factors. */
+    public static final String RESTRICTION_TYPE_AUTO = "Auto";
+    /** Specifies the test is only valid on non-automotive form factors. */
+    public static final String RESTRICTION_TYPE_NON_AUTO = "Non Auto";
+}
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestrictionSkipCheck.java b/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestrictionSkipCheck.java
new file mode 100644
index 0000000..ba102f6
--- /dev/null
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/DeviceRestrictionSkipCheck.java
@@ -0,0 +1,40 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui.test.util;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import org.chromium.base.BuildInfo;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.RestrictionSkipCheck;
+
+/**
+ * Checks if any restrictions exist and skip the test if it meets those restrictions.
+ */
+public class DeviceRestrictionSkipCheck extends RestrictionSkipCheck {
+    public DeviceRestrictionSkipCheck(Context targetContext) {
+        super(targetContext);
+    }
+
+    @Override
+    protected boolean restrictionApplies(String restriction) {
+        boolean restrictedToAuto =
+                TextUtils.equals(restriction, DeviceRestriction.RESTRICTION_TYPE_AUTO);
+        boolean restrictedToNonAuto =
+                TextUtils.equals(restriction, DeviceRestriction.RESTRICTION_TYPE_NON_AUTO);
+
+        boolean noRestrictionsApply = !restrictedToAuto && !restrictedToNonAuto;
+        if (noRestrictionsApply) {
+            return false;
+        }
+
+        boolean isAuto = ThreadUtils.runOnUiThreadBlockingNoException(
+                () -> BuildInfo.getInstance().isAutomotive);
+        boolean autoRestrictionApplies = restrictedToAuto && !isAuto;
+        boolean nonAutoRestrictionApplies = restrictedToNonAuto && isAuto;
+        return autoRestrictionApplies || nonAutoRestrictionApplies;
+    }
+}