diff --git a/DEPS b/DEPS
index 0149255..d44dc5d 100644
--- a/DEPS
+++ b/DEPS
@@ -304,11 +304,11 @@
   # 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': '14c62c66936707e9d26c4972242ee2c6229410c8',
+  'skia_revision': '91a14b75ee56bdba22d97d8573e7878ce17bfa8c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '6813c888ce1426bee5e6a3cceca0e0095f44e1b3',
+  'v8_revision': '950b7b1c0499da2862630ae7cf4f627989bd4454',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -320,7 +320,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '54020fcdf229355df6e09d989b23600879eac0c2',
+  'pdfium_revision': 'a2f4718eca79b33328f8b589782590da9ababa47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # 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:11.20230118.2.1',
+  'fuchsia_version': 'version:11.20230122.0.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.
@@ -383,7 +383,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '75eada74795ea506c979d1db745c21e6cfcd0c03',
+  'devtools_frontend_revision': '5532ca1f7b7db428ef7229703d7e73314822e5c1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -419,7 +419,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'f586545aef99b21bf5cc34c91e8877c592854913',
+  'dawn_revision': '57c0bbc2a5167f6ac63bd2f3b7fe0511c141a195',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -455,7 +455,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.
-  'cros_components_revision': '2f0cb6f5ec3c18128f65fecdc50f5aafb9209a73',
+  'cros_components_revision': '45ca37d4c4b5ca1e751df3c2761b5b9a1f00e49c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -770,7 +770,7 @@
 
   'src/clank': {
     'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
-    '4a684aa5bb100eaa6526f1996c518308fefd8655',
+    '4d7dcf804663cf43e003ee67e0c55c96c4dfaec6',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -869,7 +869,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'Zvq-bUflpsGxRrcnSXD_So0-tQuRC-04LpqqgaNiriQC',
+          'version': 'EvpbU346tcDhtTSlwxeCYTUkn_gwGAm7DOmQsDmSgnEC',
         },
       ],
       'dep_type': 'cipd',
@@ -880,7 +880,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': '61CHd6aEhpApwoMB9MADIejCVK72JC0TzGOYkNZk81wC',
+          'version': 'SVh5S_32wuT7mbOKvRjmg00i-bbng_xn7PEdZJbAwLsC',
         },
       ],
       'dep_type': 'cipd',
@@ -891,7 +891,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'Cabgge58W6srLHdxjBUgd9_HXHe1TtSqN4gjeaKzPKEC',
+          'version': 'fweoqwL7f8ZPTysi8y-baT3qUHkTrV_rBvnGe25rbtkC',
         },
       ],
       'dep_type': 'cipd',
@@ -1081,7 +1081,7 @@
           },
           {
               'package': 'chromium/third_party/android_sdk/public/cmdline-tools',
-              'version': 'oWlET2yQhaPKQ66tYNuSPaueU78Z9VlxpyxOoUjwRuIC',
+              'version': '3Yn5Sn7BMObm8gsoZCF0loJMKg9_PpgU07G9DObCLdQC',
           },
       ],
       'condition': 'checkout_android_native_support',
@@ -1210,7 +1210,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'fd2a693a39a9c8fdded6f2b74fa746fcef89a188',
+      'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '390f56e357b56ac288628078b875807bbb38d7b2',
     'condition': 'checkout_src_internal',
   },
 
@@ -1695,7 +1695,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': '-zULvtoUlL3ZlX-wYBRJuptakgqclqk9dpsQizt8gysC',
+              'version': 'XBkol4a9AeFOtX-9cvNPpKCbqj9UAqZuoVvFop6AX9wC',
           },
       ],
       'condition': 'checkout_android',
@@ -1800,7 +1800,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@e55b93bb3f992cdee2c74a0dbc9f6b7fd0478832',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@d7dfd14fa0d0bc1411976c7800a9076bab44524a',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1910,7 +1910,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4a29dd840779bec3bd089b95bab37a947223bfcd',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@081fe5aa0249d8b556ed36615f9842c48936d234',
     'condition': 'checkout_src_internal',
   },
 
@@ -1940,7 +1940,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '41WKKf6lX096x3eV27mPzRcGzaX3pFpShn2cNc_bRHAC',
+        'version': 'ykLNqy96X-qziJmuQdK7bdcunnlYSf2Vn12BGNg8h6gC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1951,7 +1951,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '-92_e0UmqSAtsPVNLszDQNaxzJvLscTOb02ISAxpkjMC',
+        'version': 'oFGSGDPnnfz3OzIpNADONktOep72JLUrbtWWgeAnB2wC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1962,7 +1962,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'LidcYHe6Cu4snY6o3PF_56OROikaMEOMF-h3Z0HjBMQC',
+        'version': 'U9vawi-ZzU6VqZyz56KlnhT6niXurjhjIXNJdyPUsrAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index 470b56a..86312a66 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -467,12 +467,54 @@
 }
 
 void AmbientController::OnUserActivity(const ui::Event* event) {
+  // The following events are handled separately so that we can consume them.
+  if (event->IsMouseEvent() || event->IsTouchEvent() || event->IsKeyEvent() ||
+      event->IsFlingScrollEvent()) {
+    return;
+  }
+  // While |kPreview| is loading, don't |DismissUI| on user activity.
+  // Users can still |DismissUI| with mouse, touch, key or assistant events.
+  if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview &&
+      !Shell::GetPrimaryRootWindowController()->HasAmbientWidget()) {
+    return;
+  }
   DismissUI();
 }
 
 void AmbientController::OnKeyEvent(ui::KeyEvent* event) {
   // Prevent dispatching key press event to the login UI.
   event->StopPropagation();
+  // |DismissUI| only on |ET_KEY_PRESSED|. Otherwise it won't be possible to
+  // start the preview by pressing "enter" key. It'll be cancelled immediately
+  // on |ET_KEY_RELEASED|.
+  if (event->type() == ui::ET_KEY_PRESSED) {
+    DismissUI();
+  }
+}
+
+void AmbientController::OnMouseEvent(ui::MouseEvent* event) {
+  // Prevent dispatching mouse event to the windows behind screen saver.
+  event->StopPropagation();
+  // |DismissUI| on actual mouse move only if the screen saver widget is shown
+  // (images are downloaded).
+  if (event->type() == ui::ET_MOUSE_MOVED) {
+    if (last_mouse_event_was_move_ &&
+        Shell::GetPrimaryRootWindowController()->HasAmbientWidget()) {
+      DismissUI();
+    }
+    last_mouse_event_was_move_ = true;
+    return;
+  }
+
+  if (event->IsAnyButton()) {
+    DismissUI();
+  }
+  last_mouse_event_was_move_ = false;
+}
+
+void AmbientController::OnTouchEvent(ui::TouchEvent* event) {
+  // Prevent dispatching touch event to the windows behind screen saver.
+  event->StopPropagation();
   DismissUI();
 }
 
@@ -783,7 +825,10 @@
   }
 
   if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kHidden) {
-    inactivity_timer_.Reset();
+    // Double resetting crashes the UI, make sure it is running.
+    if (inactivity_timer_.IsRunning()) {
+      inactivity_timer_.Reset();
+    }
     return;
   }
 
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h
index 9b0a64b..12dfb5a 100644
--- a/ash/ambient/ambient_controller.h
+++ b/ash/ambient/ambient_controller.h
@@ -114,6 +114,8 @@
 
   // ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
+  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnTouchEvent(ui::TouchEvent* event) override;
 
   // AssistantInteractionModelObserver:
   void OnInteractionStateChanged(InteractionState interaction_state) override;
@@ -267,6 +269,12 @@
 
   bool close_widgets_immediately_ = false;
 
+  // ui::ET_MOUSE_MOVE is fired before many mouse events. An event is an actual
+  // mouse move event only if the last event was ui::ET_MOUSE_MOVE too. Used
+  // to keep track of the last event and identify a true mouse move event.
+  // TODO(safarli): Remove this workaround when b/266234711 is fixed.
+  bool last_mouse_event_was_move_ = false;
+
   // Not set until the AmbientAnimationTheme is initially read from pref
   // storage when ambient mode is enabled.
   absl::optional<AmbientAnimationTheme> current_theme_from_pref_;
diff --git a/ash/ambient/ambient_controller_unittest.cc b/ash/ambient/ambient_controller_unittest.cc
index cab3b3f0..3adbda1 100644
--- a/ash/ambient/ambient_controller_unittest.cc
+++ b/ash/ambient/ambient_controller_unittest.cc
@@ -662,12 +662,12 @@
   for (auto mouse_event_type : {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_MOVED}) {
     events.emplace_back(std::make_unique<ui::MouseEvent>(
         mouse_event_type, gfx::Point(), gfx::Point(), base::TimeTicks(),
-        ui::EF_NONE, ui::EF_NONE));
+        ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE));
   }
 
   events.emplace_back(std::make_unique<ui::MouseWheelEvent>(
       gfx::Vector2d(), gfx::PointF(), gfx::PointF(), base::TimeTicks(),
-      ui::EF_NONE, ui::EF_NONE));
+      ui::EF_MIDDLE_MOUSE_BUTTON, ui::EF_NONE));
 
   events.emplace_back(std::make_unique<ui::ScrollEvent>(
       ui::ET_SCROLL, gfx::PointF(), gfx::PointF(), base::TimeTicks(),
@@ -685,7 +685,13 @@
     FastForwardTiny();
     EXPECT_TRUE(WidgetsVisible());
 
-    ambient_controller()->OnUserActivity(event.get());
+    if (event.get()->IsMouseEvent()) {
+      ambient_controller()->OnMouseEvent(event.get()->AsMouseEvent());
+    } else if (event.get()->IsTouchEvent()) {
+      ambient_controller()->OnTouchEvent(event.get()->AsTouchEvent());
+    } else {
+      ambient_controller()->OnUserActivity(event.get());
+    }
 
     FastForwardTiny();
     EXPECT_TRUE(GetContainerViews().empty());
@@ -701,9 +707,7 @@
   FastForwardTiny();
   EXPECT_TRUE(WidgetsVisible());
 
-  ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                             base::TimeTicks(), ui::EF_NONE, ui::EF_NONE);
-  ambient_controller()->OnUserActivity(&mouse_event);
+  GetEventGenerator()->PressLeftButton();
   FastForwardTiny();
   EXPECT_TRUE(GetContainerViews().empty());
 
@@ -1452,4 +1456,79 @@
       base::Minutes(1), 1);
 }
 
+TEST_F(AmbientControllerTest, ShouldStartScreenSaverPreview) {
+  ambient_controller()->StartScreenSaverPreview();
+  FastForwardToLockScreenTimeout();
+  FastForwardTiny();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+  EXPECT_FALSE(IsLocked());
+}
+
+TEST_F(AmbientControllerTest,
+       ShouldNotDismissScreenSaverPreviewOnUserActivity) {
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  ui::MouseEvent mouse_event(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
+                             base::TimeTicks(), ui::EF_NONE, ui::EF_NONE);
+  ambient_controller()->OnUserActivity(&mouse_event);
+  FastForwardTiny();
+
+  EXPECT_TRUE(ambient_controller()->IsShown());
+}
+
+TEST_F(AmbientControllerTest, ShouldDismissScreenSaverPreviewOnKeyReleased) {
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->ReleaseKey(ui::VKEY_A, ui::EF_NONE);
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->PressKey(ui::VKEY_A, ui::EF_NONE);
+  EXPECT_FALSE(ambient_controller()->IsShown());
+}
+
+TEST_F(AmbientControllerTest,
+       ShouldNotDismissScreenSaverPreviewOnSomeMouseEvents) {
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->MoveMouseWheel(10, 10);
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->SendMouseEnter();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->SendMouseExit();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+}
+
+TEST_F(AmbientControllerTest, ShouldDismissScreenSaverPreviewOnMouseClick) {
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->ClickLeftButton();
+  EXPECT_FALSE(ambient_controller()->IsShown());
+
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->ClickRightButton();
+  EXPECT_FALSE(ambient_controller()->IsShown());
+}
+
+TEST_F(AmbientControllerTest, ShouldDismissScreenSaverPreviewOnTouch) {
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->PressTouch();
+  EXPECT_FALSE(ambient_controller()->IsShown());
+
+  ambient_controller()->StartScreenSaverPreview();
+  EXPECT_TRUE(ambient_controller()->IsShown());
+
+  GetEventGenerator()->ReleaseTouch();
+  EXPECT_FALSE(ambient_controller()->IsShown());
+}
+
 }  // namespace ash
diff --git a/ash/webui/file_manager/resources/BUILD.gn b/ash/webui/file_manager/resources/BUILD.gn
index 73a0251..7ce95dc0 100644
--- a/ash/webui/file_manager/resources/BUILD.gn
+++ b/ash/webui/file_manager/resources/BUILD.gn
@@ -153,7 +153,6 @@
     ":preprocess",
     ":preprocess_mojo",
     "//ui/file_manager:build_ts",
-    "//ui/webui/resources:preprocess",
   ]
 }
 
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn
index 8f4c88b..ef93dde 100644
--- a/ash/webui/personalization_app/resources/BUILD.gn
+++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -228,10 +228,7 @@
     js_module_in_files = [ "js/personalization_app.js" ]
     out_manifest = "$target_gen_dir/$build_manifest"
 
-    deps = [
-      ":build_ts",
-      "//ui/webui/resources:preprocess",
-    ]
+    deps = [ ":build_ts" ]
 
     excludes = [ "chrome://resources/mojo/mojo/public/js/bindings.js" ]
   }
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc
index a06068a..49f19a6 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -81,12 +81,14 @@
   // Don't completely empty the thread cache outside of low memory situations,
   // as there is periodic purge which makes sure that it doesn't take too much
   // space.
-  if (flags & PurgeFlags::kAggressiveReclaim)
+  if (flags & PurgeFlags::kAggressiveReclaim) {
     ThreadCacheRegistry::Instance().PurgeAll();
+  }
 #endif  // PA_CONFIG(THREAD_CACHE_SUPPORTED)
 
-  for (auto* partition : partitions_)
+  for (auto* partition : partitions_) {
     partition->PurgeMemory(flags);
+  }
 }
 
 void MemoryReclaimer::ResetForTesting() {
diff --git a/base/allocator/partition_allocator/partition_address_space.cc b/base/allocator/partition_allocator/partition_address_space.cc
index e140c42..f95b8ff 100644
--- a/base/allocator/partition_allocator/partition_address_space.cc
+++ b/base/allocator/partition_allocator/partition_address_space.cc
@@ -53,13 +53,15 @@
   using RtlGetVersion = LONG(WINAPI*)(OSVERSIONINFOEX*);
   const RtlGetVersion rtl_get_version = reinterpret_cast<RtlGetVersion>(
       ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "RtlGetVersion"));
-  if (!rtl_get_version)
+  if (!rtl_get_version) {
     return true;
+  }
 
   OSVERSIONINFOEX version_info = {};
   version_info.dwOSVersionInfoSize = sizeof(version_info);
-  if (rtl_get_version(&version_info) != ERROR_SUCCESS)
+  if (rtl_get_version(&version_info) != ERROR_SUCCESS) {
     return true;
+  }
 
   // Anything prior to Windows 8.1 is considered legacy for the allocator.
   // Windows 8.1 is major 6 with minor 3.
@@ -140,8 +142,9 @@
 
   auto has_suffix = [&](const char* suffix) -> bool {
     size_t suffix_length = std::char_traits<char>::length(suffix);
-    if (executable_path_length < suffix_length)
+    if (executable_path_length < suffix_length) {
       return false;
+    }
     return std::char_traits<char>::compare(
                executable_path + (executable_path_length - suffix_length),
                suffix, suffix_length) == 0;
@@ -170,8 +173,9 @@
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 
 void PartitionAddressSpace::Init() {
-  if (IsInitialized())
+  if (IsInitialized()) {
     return;
+  }
 
   size_t regular_pool_size = RegularPoolSize();
   size_t brp_pool_size = BRPPoolSize();
@@ -193,8 +197,9 @@
                  PageAccessibilityConfiguration(
                      PageAccessibilityConfiguration::kInaccessible),
                  PageTag::kPartitionAlloc, pools_fd);
-  if (!setup_.regular_pool_base_address_)
+  if (!setup_.regular_pool_base_address_) {
     HandlePoolAllocFailure();
+  }
   setup_.brp_pool_base_address_ =
       setup_.regular_pool_base_address_ + regular_pool_size;
 #else  // PA_CONFIG(GLUE_CORE_POOLS)
@@ -208,8 +213,9 @@
                  PageAccessibilityConfiguration(
                      PageAccessibilityConfiguration::kInaccessible),
                  PageTag::kPartitionAlloc, regular_pool_fd);
-  if (!setup_.regular_pool_base_address_)
+  if (!setup_.regular_pool_base_address_) {
     HandlePoolAllocFailure();
+  }
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 #endif
 
@@ -229,8 +235,9 @@
       PageAccessibilityConfiguration(
           PageAccessibilityConfiguration::kInaccessible),
       PageTag::kPartitionAlloc, brp_pool_fd);
-  if (!base_address)
+  if (!base_address) {
     HandlePoolAllocFailure();
+  }
   setup_.brp_pool_base_address_ = base_address + kForbiddenZoneSize;
 #endif  // PA_CONFIG(GLUE_CORE_POOLS)
 
@@ -326,8 +333,9 @@
   // It's possible that the pkey pool has been initialized first, in which case
   // the setup_ memory has been made read-only. Remove the protection
   // temporarily.
-  if (IsPkeyPoolInitialized())
+  if (IsPkeyPoolInitialized()) {
     TagGlobalsWithPkey(kDefaultPkey);
+  }
 #endif
 
   PA_CHECK(pool_base);
@@ -344,8 +352,9 @@
 
 #if BUILDFLAG(ENABLE_PKEYS)
   // Put the pkey protection back in place.
-  if (IsPkeyPoolInitialized())
+  if (IsPkeyPoolInitialized()) {
     TagGlobalsWithPkey(setup_.pkey_);
+  }
 #endif
 }
 
@@ -363,8 +372,9 @@
                  PageAccessibilityConfiguration(
                      PageAccessibilityConfiguration::kInaccessible),
                  PageTag::kPartitionAlloc);
-  if (!setup_.pkey_pool_base_address_)
+  if (!setup_.pkey_pool_base_address_) {
     HandlePoolAllocFailure();
+  }
 
   PA_DCHECK(!(setup_.pkey_pool_base_address_ & (pool_size - 1)));
   setup_.pkey_ = pkey;
@@ -413,16 +423,18 @@
   // It's possible that the pkey pool has been initialized first, in which case
   // the setup_ memory has been made read-only. Remove the protection
   // temporarily.
-  if (IsPkeyPoolInitialized())
+  if (IsPkeyPoolInitialized()) {
     TagGlobalsWithPkey(kDefaultPkey);
+  }
 #endif
   AddressPoolManager::GetInstance().Remove(kConfigurablePoolHandle);
   setup_.configurable_pool_base_address_ = kUninitializedPoolBaseAddress;
   setup_.configurable_pool_base_mask_ = 0;
 #if BUILDFLAG(ENABLE_PKEYS)
   // Put the pkey protection back in place.
-  if (IsPkeyPoolInitialized())
+  if (IsPkeyPoolInitialized()) {
     TagGlobalsWithPkey(setup_.pkey_);
+  }
 #endif
 }
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
index 7601049..e0c41cd3 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
@@ -79,11 +79,13 @@
   pthread_attr_init(&attributes);
 
   // Get a better default if available.
-  if (stack_size == 0)
+  if (stack_size == 0) {
     stack_size = base::GetDefaultThreadStackSize(attributes);
+  }
 
-  if (stack_size > 0)
+  if (stack_size > 0) {
     pthread_attr_setstacksize(&attributes, stack_size);
+  }
 
   std::unique_ptr<ThreadParams> params(new ThreadParams);
   params->delegate = delegate;
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 0643d89..284aacb 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -129,8 +129,9 @@
     for (int i = 0; i < kMaxRandomAddressTries; ++i) {
       if (!reserved_address ||
           AreAllowedSuperPagesForBRPPool(reserved_address,
-                                         reserved_address + requested_size))
+                                         reserved_address + requested_size)) {
         break;
+      }
       AddressPoolManager::GetInstance().UnreserveAndDecommit(
           pool, reserved_address, requested_size);
       // No longer try to honor |requested_address|, because it didn't work for
@@ -151,8 +152,9 @@
          address_to_try += kSuperPageSize) {
       if (!reserved_address ||
           AreAllowedSuperPagesForBRPPool(reserved_address,
-                                         reserved_address + requested_size))
+                                         reserved_address + requested_size)) {
         break;
+      }
       AddressPoolManager::GetInstance().UnreserveAndDecommit(
           pool, reserved_address, requested_size);
       // Reserve() can return a different pointer than attempted.
@@ -179,9 +181,10 @@
   // raw_ptr<T> object that points to non-PA memory in another thread.
   // If `MarkUsed` was called earlier, the other thread could incorrectly
   // determine that the allocation had come form PartitionAlloc.
-  if (reserved_address)
+  if (reserved_address) {
     AddressPoolManager::GetInstance().MarkUsed(pool, reserved_address,
                                                requested_size);
+  }
 #endif
 
   PA_DCHECK(!(reserved_address % kSuperPageSize));
@@ -203,8 +206,9 @@
 
   const bool return_null = flags & AllocFlags::kReturnNull;
   if (PA_UNLIKELY(raw_size > MaxDirectMapped())) {
-    if (return_null)
+    if (return_null) {
       return nullptr;
+    }
 
     // The lock is here to protect PA from:
     // 1. Concurrent calls
@@ -286,8 +290,9 @@
       reservation_start = ReserveMemoryFromPool(pool, 0, reservation_size);
     }
     if (PA_UNLIKELY(!reservation_start)) {
-      if (return_null)
+      if (return_null) {
         return nullptr;
+      }
 
       PartitionOutOfMemoryMappingFailure(root, reservation_size);
     }
@@ -460,8 +465,9 @@
 
   // Maintain the doubly-linked list of all direct mappings.
   map_extent->next_extent = root->direct_map_list;
-  if (map_extent->next_extent)
+  if (map_extent->next_extent) {
     map_extent->next_extent->prev_extent = map_extent;
+  }
   map_extent->prev_extent = nullptr;
   root->direct_map_list = map_extent;
 
@@ -504,8 +510,9 @@
        partition_page_count++) {
     size_t candidate_size = partition_page_count * PartitionPageSize();
     size_t waste = candidate_size % slot_size;
-    if (waste <= .02 * SystemPageSize())
+    if (waste <= .02 * SystemPageSize()) {
       return partition_page_count * NumSystemPagesPerPartitionPage();
+    }
   }
 
   size_t best_count = 0;
@@ -591,8 +598,9 @@
     // In case the waste is too large (more than 5% of a page), don't try to use
     // the "small" slot span formula. This happens when we have a lot of
     // buckets, in some cases the formula doesn't find a nice, small size.
-    if (waste <= .05 * SystemPageSize())
+    if (waste <= .05 * SystemPageSize()) {
       return system_page_count;
+    }
   }
 
   return ComputeSystemPagesPerSlotSpanInternal(slot_size);
@@ -736,8 +744,9 @@
   uintptr_t super_page_span_start = ReserveMemoryFromPool(
       pool, requested_address, super_page_count * kSuperPageSize);
   if (PA_UNLIKELY(!super_page_span_start)) {
-    if (flags & AllocFlags::kReturnNull)
+    if (flags & AllocFlags::kReturnNull) {
       return 0;
+    }
 
     // Didn't manage to get a new uncommitted super page -> address space issue.
     ::partition_alloc::internal::ScopedUnlockGuard unlock{root->lock_};
@@ -848,8 +857,9 @@
   // distributions will allocate the mapping directly before the last
   // successful mapping, which is far from random. So we just get fresh
   // randomness for the next mapping attempt.
-  if (requested_address && requested_address != super_page)
+  if (requested_address && requested_address != super_page) {
     root->next_super_page = 0;
+  }
 
   // We allocated a new super page so update super page metadata.
   // First check if this is a new extent or not.
@@ -1080,8 +1090,9 @@
 template <bool thread_safe>
 bool PartitionBucket<thread_safe>::SetNewActiveSlotSpan() {
   SlotSpanMetadata<thread_safe>* slot_span = active_slot_spans_head;
-  if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span())
+  if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()) {
     return false;
+  }
 
   SlotSpanMetadata<thread_safe>* next_slot_span;
 
@@ -1131,10 +1142,12 @@
         break;
       } else {
         // Keeping head and tail because we don't want to reverse the list.
-        if (!to_provision_head)
+        if (!to_provision_head) {
           to_provision_head = slot_span;
-        if (to_provision_tail)
+        }
+        if (to_provision_tail) {
           to_provision_tail->next_slot_span = slot_span;
+        }
         to_provision_tail = slot_span;
         slot_span->next_slot_span = nullptr;
       }
@@ -1188,8 +1201,9 @@
 template <bool thread_safe>
 void PartitionBucket<thread_safe>::MaintainActiveList() {
   SlotSpanMetadata<thread_safe>* slot_span = active_slot_spans_head;
-  if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span())
+  if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()) {
     return;
+  }
 
   SlotSpanMetadata<thread_safe>* new_active_slot_spans_head = nullptr;
   SlotSpanMetadata<thread_safe>* new_active_slot_spans_tail = nullptr;
@@ -1200,10 +1214,12 @@
 
     if (slot_span->is_active()) {
       // Ordering in the active slot span list matters, don't reverse it.
-      if (!new_active_slot_spans_head)
+      if (!new_active_slot_spans_head) {
         new_active_slot_spans_head = slot_span;
-      if (new_active_slot_spans_tail)
+      }
+      if (new_active_slot_spans_tail) {
         new_active_slot_spans_tail->next_slot_span = slot_span;
+      }
       new_active_slot_spans_tail = slot_span;
       slot_span->next_slot_span = nullptr;
     } else if (slot_span->is_empty()) {
@@ -1243,8 +1259,10 @@
     //
     // Besides saving CPU, this also avoids touching memory of fully idle slot
     // spans, which may required paging.
-    if (slot_span->num_allocated_slots > 0 && !slot_span->freelist_is_sorted())
+    if (slot_span->num_allocated_slots > 0 &&
+        !slot_span->freelist_is_sorted()) {
       slot_span->SortFreelist();
+    }
   }
 }
 
@@ -1378,13 +1396,15 @@
               SlotSpanMetadata<thread_safe>::get_sentinel_slot_span());
 
     // No fast path for direct-mapped allocations.
-    if (flags & AllocFlags::kFastPathOrReturnNull)
+    if (flags & AllocFlags::kFastPathOrReturnNull) {
       return 0;
+    }
 
     new_slot_span =
         PartitionDirectMap(root, flags, raw_size, slot_span_alignment);
-    if (new_slot_span)
+    if (new_slot_span) {
       new_bucket = new_slot_span->bucket;
+    }
     // Memory from PageAllocator is always zeroed.
     *is_already_zeroed = true;
   } else if (PA_LIKELY(!allocate_aligned_slot_span && SetNewActiveSlotSpan())) {
@@ -1422,8 +1442,9 @@
     if (PA_UNLIKELY(!new_slot_span) &&
         PA_LIKELY(decommitted_slot_spans_head != nullptr)) {
       // Commit can be expensive, don't do it.
-      if (flags & AllocFlags::kFastPathOrReturnNull)
+      if (flags & AllocFlags::kFastPathOrReturnNull) {
         return 0;
+      }
 
       new_slot_span = decommitted_slot_spans_head;
       PA_DCHECK(new_slot_span->bucket == this);
@@ -1451,8 +1472,9 @@
     PA_DCHECK(new_slot_span);
   } else {
     // Getting a new slot span is expensive, don't do it.
-    if (flags & AllocFlags::kFastPathOrReturnNull)
+    if (flags & AllocFlags::kFastPathOrReturnNull) {
       return 0;
+    }
 
     // Third. If we get here, we need a brand new slot span.
     // TODO(bartekn): For single-slot slot spans, we can use rounded raw_size
@@ -1466,8 +1488,9 @@
   if (PA_UNLIKELY(!new_slot_span)) {
     PA_DCHECK(active_slot_spans_head ==
               SlotSpanMetadata<thread_safe>::get_sentinel_slot_span());
-    if (flags & AllocFlags::kReturnNull)
+    if (flags & AllocFlags::kReturnNull) {
       return 0;
+    }
     // See comment in PartitionDirectMap() for unlocking.
     ScopedUnlockGuard unlock{root->lock_};
     root->OutOfMemory(raw_size);
@@ -1476,8 +1499,9 @@
 
   PA_DCHECK(new_bucket != &root->sentinel_bucket);
   new_bucket->active_slot_spans_head = new_slot_span;
-  if (new_slot_span->CanStoreRawSize())
+  if (new_slot_span->CanStoreRawSize()) {
     new_slot_span->SetRawSize(raw_size);
+  }
 
   // If we found an active slot span with free slots, or an empty slot span, we
   // have a usable freelist head.
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 390e200..40deaa4 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -97,14 +97,16 @@
     if (order == kNormal) {
       ThreadSafePartitionRoot* root;
       for (root = Head(partition_roots_); root != nullptr;
-           root = root->next_root)
+           root = root->next_root) {
         callback(root, in_child);
+      }
     } else {
       PA_DCHECK(order == kReverse);
       ThreadSafePartitionRoot* root;
       for (root = Tail(partition_roots_); root != nullptr;
-           root = root->prev_root)
+           root = root->prev_root) {
         callback(root, in_child);
+      }
     }
   }
 
@@ -112,8 +114,9 @@
     internal::ScopedGuard guard(ThreadSafePartitionRoot::GetEnumeratorLock());
     root->next_root = partition_roots_;
     root->prev_root = nullptr;
-    if (partition_roots_)
+    if (partition_roots_) {
       partition_roots_->prev_root = root;
+    }
     partition_roots_ = root;
   }
 
@@ -145,8 +148,9 @@
 
   ThreadSafePartitionRoot* Tail(ThreadSafePartitionRoot* roots)
       PA_NO_THREAD_SAFETY_ANALYSIS {
-    if (!roots)
+    if (!roots) {
       return nullptr;
+    }
     ThreadSafePartitionRoot* node = roots;
     for (; node->next_root != nullptr; node = node->next_root)
       ;
@@ -190,10 +194,11 @@
 void UnlockOrReinit(T& lock, bool in_child) PA_NO_THREAD_SAFETY_ANALYSIS {
   // Only re-init the locks in the child process, in the parent can unlock
   // normally.
-  if (in_child)
+  if (in_child) {
     lock.Reinit();
-  else
+  } else {
     lock.Release();
+  }
 }
 
 void UnlockOrReinitRoot(PartitionRoot<internal::ThreadSafe>* root,
@@ -236,8 +241,9 @@
   bool expected = false;
   // No need to block execution for potential concurrent initialization, merely
   // want to make sure this is only called once.
-  if (!g_global_init_called.compare_exchange_strong(expected, true))
+  if (!g_global_init_called.compare_exchange_strong(expected, true)) {
     return;
+  }
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   // When fork() is called, only the current thread continues to execute in the
@@ -308,8 +314,9 @@
   const internal::PartitionBucket<thread_safe>* bucket = slot_span->bucket;
   size_t slot_size = bucket->slot_size;
 
-  if (slot_size < MinPurgeableSlotSize() || !slot_span->num_allocated_slots)
+  if (slot_size < MinPurgeableSlotSize() || !slot_span->num_allocated_slots) {
     return 0;
+  }
 
   size_t bucket_num_slots = bucket->get_slots_per_span();
   size_t discardable_bytes = 0;
@@ -371,8 +378,9 @@
     // return the original content or 0. (Note that this optimization won't be
     // effective on big-endian machines because the masking function is
     // negation.)
-    if (entry->IsEncodedNextPtrZero())
+    if (entry->IsEncodedNextPtrZero()) {
       last_slot = slot_number;
+    }
 #endif
     entry = entry->GetNext(slot_size);
   }
@@ -425,8 +433,9 @@
       internal::PartitionFreelistEntry* back = head;
       size_t num_new_entries = 0;
       for (size_t slot_index = 0; slot_index < num_slots; ++slot_index) {
-        if (slot_usage[slot_index])
+        if (slot_usage[slot_index]) {
           continue;
+        }
 
         auto* entry = PartitionFreelistEntry::EmplaceAndInitNull(
             slot_span_start + (slot_size * slot_index));
@@ -587,8 +596,9 @@
   if (bucket->active_slot_spans_head ==
           internal::SlotSpanMetadata<thread_safe>::get_sentinel_slot_span() &&
       !bucket->empty_slot_spans_head && !bucket->decommitted_slot_spans_head &&
-      !bucket->num_full_slot_spans)
+      !bucket->num_full_slot_spans) {
     return;
+  }
 
   memset(stats_out, '\0', sizeof(*stats_out));
   stats_out->is_valid = true;
@@ -701,8 +711,9 @@
   PA_DEBUG_DATA_ON_STACK("commit", get_total_size_of_committed_pages());
   PA_DEBUG_DATA_ON_STACK("size", size);
 
-  if (internal::g_oom_handling_function)
+  if (internal::g_oom_handling_function) {
     (*internal::g_oom_handling_function)(size);
+  }
   OOM_CRASH(size);
 }
 
@@ -755,8 +766,9 @@
   // No need to block execution for potential concurrent initialization, merely
   // want to make sure this is only called once.
   if (!g_reserve_brp_guard_region_called.compare_exchange_strong(expected,
-                                                                 true))
+                                                                 true)) {
     return;
+  }
 
   size_t alignment = internal::PageAllocationGranularity();
   uintptr_t requested_address;
@@ -799,8 +811,9 @@
 #endif
 
     ::partition_alloc::internal::ScopedGuard guard{lock_};
-    if (initialized)
+    if (initialized) {
       return;
+    }
 
     // Swaps out the active no-op tagging intrinsics with MTE-capable ones, if
     // running on the right hardware.
@@ -937,8 +950,9 @@
     flags.with_thread_cache =
         (opts.thread_cache == PartitionOptions::ThreadCache::kEnabled);
 
-    if (flags.with_thread_cache)
+    if (flags.with_thread_cache) {
       ThreadCache::Init(this);
+    }
 #endif  // !PA_CONFIG(THREAD_CACHE_SUPPORTED)
 
 #if PA_CONFIG(USE_PARTITION_ROOT_ENUMERATOR)
@@ -968,8 +982,9 @@
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
 #if PA_CONFIG(USE_PARTITION_ROOT_ENUMERATOR)
-  if (initialized)
+  if (initialized) {
     internal::PartitionRootEnumerator::Instance().Unregister(this);
+  }
 #endif  // PA_CONFIG(USE_PARTITION_ALLOC_ENUMERATOR)
 }
 
@@ -1014,8 +1029,9 @@
 
   // If new reservation would be larger, there is nothing we can do to
   // reallocate in-place.
-  if (new_reservation_size > current_reservation_size)
+  if (new_reservation_size > current_reservation_size) {
     return false;
+  }
 
   // Don't reallocate in-place if new reservation size would be less than 80 %
   // of the current one, to avoid holding on to too much unused address space.
@@ -1023,15 +1039,17 @@
   // slot sizes we can save a lot if the original allocation was heavily padded
   // for alignment.
   if ((new_reservation_size >> internal::SystemPageShift()) * 5 <
-      (current_reservation_size >> internal::SystemPageShift()) * 4)
+      (current_reservation_size >> internal::SystemPageShift()) * 4) {
     return false;
+  }
 
   // Note that the new size isn't a bucketed size; this function is called
   // whenever we're reallocating a direct mapped allocation, so calculate it
   // the way PartitionDirectMap() would.
   size_t new_slot_size = GetDirectMapSlotSize(raw_size);
-  if (new_slot_size < internal::kMinDirectMappedDownsize)
+  if (new_slot_size < internal::kMinDirectMappedDownsize) {
     return false;
+  }
 
   // Past this point, we decided we'll attempt to reallocate without relocating,
   // so we have to honor the padding for alignment in front of the original
@@ -1201,8 +1219,9 @@
   }
 
   if (new_size > internal::MaxDirectMapped()) {
-    if (flags & AllocFlags::kReturnNull)
+    if (flags & AllocFlags::kReturnNull) {
       return nullptr;
+    }
     internal::PartitionExcessiveAllocationSize(new_size);
   }
 
@@ -1242,8 +1261,10 @@
     }
 
     if (PA_LIKELY(!tried_in_place_for_direct_map)) {
-      if (old_root->TryReallocInPlaceForNormalBuckets(ptr, slot_span, new_size))
+      if (old_root->TryReallocInPlaceForNormalBuckets(ptr, slot_span,
+                                                      new_size)) {
         return ptr;
+      }
     }
   }
 
@@ -1254,8 +1275,9 @@
                : AllocWithFlagsInternal(
                      flags, new_size, internal::PartitionPageSize(), type_name);
   if (!ret) {
-    if (flags & AllocFlags::kReturnNull)
+    if (flags & AllocFlags::kReturnNull) {
       return nullptr;
+    }
     internal::PartitionExcessiveAllocationSize(new_size);
   }
 
@@ -1274,28 +1296,33 @@
     // takes snapshot of all allocated pages, decommitting pages here (even
     // under the lock) is racy.
     // TODO(bikineev): Consider rescheduling the purging after PCScan.
-    if (PCScan::IsInProgress())
+    if (PCScan::IsInProgress()) {
       return;
+    }
 #endif  // BUILDFLAG(STARSCAN)
 
-    if (flags & PurgeFlags::kDecommitEmptySlotSpans)
+    if (flags & PurgeFlags::kDecommitEmptySlotSpans) {
       DecommitEmptySlotSpans();
+    }
     if (flags & PurgeFlags::kDiscardUnusedSystemPages) {
       for (Bucket& bucket : buckets) {
-        if (bucket.slot_size == internal::kInvalidBucketSize)
+        if (bucket.slot_size == internal::kInvalidBucketSize) {
           continue;
+        }
 
-        if (bucket.slot_size >= internal::MinPurgeableSlotSize())
+        if (bucket.slot_size >= internal::MinPurgeableSlotSize()) {
           internal::PartitionPurgeBucket(&bucket);
-        else
+        } else {
           bucket.SortSlotSpanFreelists();
+        }
 
         // Do it at the end, as the actions above change the status of slot
         // spans (e.g. empty -> decommitted).
         bucket.MaintainActiveList();
 
-        if (sort_active_slot_spans_)
+        if (sort_active_slot_spans_) {
           bucket.SortActiveSlotSpans();
+        }
       }
     }
   }
@@ -1317,8 +1344,9 @@
     // are unused, if global_empty_slot_span_ring_size is smaller than
     // kMaxFreeableSpans. It's simpler, and does not cost anything, since all
     // the pointers are going to be nullptr.
-    if (index == internal::kMaxFreeableSpans)
+    if (index == internal::kMaxFreeableSpans) {
       index = 0;
+    }
 
     // Went around the whole ring, since this is locked,
     // empty_slot_spans_dirty_bytes should be exactly 0.
@@ -1386,10 +1414,11 @@
       // Don't report the pseudo buckets that the generic allocator sets up in
       // order to preserve a fast size->bucket map (see
       // PartitionRoot::Init() for details).
-      if (!bucket->is_valid())
+      if (!bucket->is_valid()) {
         bucket_stats[i].is_valid = false;
-      else
+      } else {
         internal::PartitionDumpBucketStats(&bucket_stats[i], bucket);
+      }
       if (bucket_stats[i].is_valid) {
         stats.total_resident_bytes += bucket_stats[i].resident_bytes;
         stats.total_active_bytes += bucket_stats[i].active_bytes;
@@ -1406,8 +1435,9 @@
                 extent->next_extent->prev_extent == extent);
       size_t slot_size = extent->bucket->slot_size;
       direct_mapped_allocations_total_size += slot_size;
-      if (is_light_dump)
+      if (is_light_dump) {
         continue;
+      }
       direct_map_lengths[num_direct_mapped_allocations] = slot_size;
     }
 
@@ -1427,8 +1457,9 @@
   // Do not hold the lock when calling |dumper|, as it may allocate.
   if (!is_light_dump) {
     for (auto& stat : bucket_stats) {
-      if (stat.is_valid)
+      if (stat.is_valid) {
         dumper->PartitionsDumpBucketStats(partition_name, &stat);
+      }
     }
 
     for (size_t i = 0; i < num_direct_mapped_allocations; ++i) {
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 8387aa98..badc7a88 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -679,16 +679,19 @@
   }
 
   PA_ALWAYS_INLINE bool ShouldQuarantine(void* object) const {
-    if (PA_UNLIKELY(flags.quarantine_mode != QuarantineMode::kEnabled))
+    if (PA_UNLIKELY(flags.quarantine_mode != QuarantineMode::kEnabled)) {
       return false;
+    }
 #if PA_CONFIG(HAS_MEMORY_TAGGING)
-    if (PA_UNLIKELY(quarantine_always_for_testing))
+    if (PA_UNLIKELY(quarantine_always_for_testing)) {
       return true;
+    }
     // If quarantine is enabled and the tag overflows, move the containing slot
     // to quarantine, to prevent the attacker from exploiting a pointer that has
     // an old tag.
-    if (PA_LIKELY(IsMemoryTaggingEnabled()))
+    if (PA_LIKELY(IsMemoryTaggingEnabled())) {
       return internal::HasOverflowTag(object);
+    }
     // Default behaviour if MTE is not enabled for this PartitionRoot.
     return true;
 #else
@@ -763,8 +766,9 @@
     // be rather complex. Then there is also the fear of the unknown. The
     // existing cases were discovered through obscure, painful-to-debug crashes.
     // Better save ourselves trouble with not-yet-discovered cases.
-    if (PA_UNLIKELY(size == 0))
+    if (PA_UNLIKELY(size == 0)) {
       return 1;
+    }
     return size;
   }
 
@@ -967,8 +971,9 @@
 #else
   uintptr_t reservation_start = GetDirectMapReservationStart(address);
 #endif
-  if (!reservation_start)
+  if (!reservation_start) {
     return 0;
+  }
 
   // The direct map allocation may not start exactly from the first page, as
   // there may be padding for alignment. The first page metadata holds an offset
@@ -1017,8 +1022,9 @@
 
   uintptr_t directmap_slot_start =
       PartitionAllocGetDirectMapSlotStartInBRPPool(address);
-  if (PA_UNLIKELY(directmap_slot_start))
+  if (PA_UNLIKELY(directmap_slot_start)) {
     return directmap_slot_start;
+  }
   auto* slot_span = SlotSpanMetadata<ThreadSafe>::FromAddr(address);
   auto* root = PartitionRoot<ThreadSafe>::FromSlotSpan(slot_span);
   // Double check that ref-count is indeed present.
@@ -1152,8 +1158,9 @@
   } else {
     slot_start = bucket->SlowPathAlloc(this, flags, raw_size,
                                        slot_span_alignment, is_already_zeroed);
-    if (PA_UNLIKELY(!slot_start))
+    if (PA_UNLIKELY(!slot_start)) {
       return 0;
+    }
 
     slot_span = SlotSpan::FromSlotStart(slot_start);
     // TODO(crbug.com/1257655): See if we can afford to make this a CHECK.
@@ -1196,13 +1203,15 @@
     return;
   }
 #endif  // defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-  if (PA_UNLIKELY(!object))
+  if (PA_UNLIKELY(!object)) {
     return;
+  }
 
   if (PartitionAllocHooks::AreHooksEnabled()) {
     PartitionAllocHooks::FreeObserverHookIfEnabled(object);
-    if (PartitionAllocHooks::FreeOverrideHookIfEnabled(object))
+    if (PartitionAllocHooks::FreeOverrideHookIfEnabled(object)) {
       return;
+    }
   }
 
   FreeNoHooks(object);
@@ -1226,8 +1235,9 @@
 // static
 template <bool thread_safe>
 PA_ALWAYS_INLINE void PartitionRoot<thread_safe>::FreeNoHooks(void* object) {
-  if (PA_UNLIKELY(!object))
+  if (PA_UNLIKELY(!object)) {
     return;
+  }
   // Almost all calls to FreeNoNooks() will end up writing to |*object|, the
   // only cases where we don't would be delayed free() in PCScan, but |*object|
   // can be cold in cache.
@@ -1385,9 +1395,10 @@
     // immediately. Otherwise, defer the operation and zap the memory to turn
     // potential use-after-free issues into unexploitable crashes.
     if (PA_UNLIKELY(!ref_count->IsAliveWithNoKnownRefs() &&
-                    brp_zapping_enabled()))
+                    brp_zapping_enabled())) {
       internal::SecureMemset(object, internal::kQuarantinedByte,
                              slot_span->GetUsableSize(this));
+    }
 
     if (PA_UNLIKELY(!(ref_count->ReleaseFromAllocator()))) {
       total_size_of_brp_quarantined_bytes.fetch_add(
@@ -1719,8 +1730,9 @@
                                 accessibility_disposition);
   }
 
-  if (ok)
+  if (ok) {
     IncreaseCommittedPages(length);
+  }
 
   return ok;
 }
@@ -1739,8 +1751,9 @@
 template <bool thread_safe>
 PA_ALWAYS_INLINE size_t PartitionRoot<thread_safe>::GetUsableSize(void* ptr) {
   // malloc_usable_size() is expected to handle NULL gracefully and return 0.
-  if (!ptr)
+  if (!ptr) {
     return 0;
+  }
   auto* slot_span = SlotSpan::FromObjectInnerPtr(ptr);
   auto* root = FromSlotSpan(slot_span);
   return slot_span->GetUsableSize(root);
@@ -1750,8 +1763,9 @@
 PA_ALWAYS_INLINE size_t
 PartitionRoot<thread_safe>::GetUsableSizeWithMac11MallocSizeHack(void* ptr) {
   // malloc_usable_size() is expected to handle NULL gracefully and return 0.
-  if (!ptr)
+  if (!ptr) {
     return 0;
+  }
   auto* slot_span = SlotSpan::FromObjectInnerPtr(ptr);
   auto* root = FromSlotSpan(slot_span);
   size_t usable_size = slot_span->GetUsableSize(root);
@@ -1781,8 +1795,9 @@
   PageAccessibilityConfiguration::Permissions permissions =
       PageAccessibilityConfiguration::kReadWrite;
 #if PA_CONFIG(HAS_MEMORY_TAGGING)
-  if (IsMemoryTaggingEnabled())
+  if (IsMemoryTaggingEnabled()) {
     permissions = PageAccessibilityConfiguration::kReadWriteTagged;
+  }
 #endif
 #if BUILDFLAG(ENABLE_PKEYS)
   return PageAccessibilityConfiguration(permissions, flags.pkey);
@@ -1970,11 +1985,13 @@
                  &usable_size, &is_already_zeroed);
   }
 
-  if (PA_UNLIKELY(!slot_start))
+  if (PA_UNLIKELY(!slot_start)) {
     return nullptr;
+  }
 
-  if (PA_LIKELY(ThreadCache::IsValid(thread_cache)))
+  if (PA_LIKELY(ThreadCache::IsValid(thread_cache))) {
     thread_cache->RecordAllocation(usable_size);
+  }
 
   // Layout inside the slot:
   //   |[refcnt]|...object...|[empty]|[cookie]|[unused]|
@@ -2154,8 +2171,9 @@
 
     // Overflow check. adjusted_size must be larger or equal to requested_size.
     if (PA_UNLIKELY(adjusted_size < requested_size)) {
-      if (flags & AllocFlags::kReturnNull)
+      if (flags & AllocFlags::kReturnNull) {
         return nullptr;
+      }
       // OutOfMemoryDeathTest.AlignedAlloc requires
       // base::TerminateBecauseOutOfMemory (invoked by
       // PartitionExcessiveAllocationSize).
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index f275105..50c9de9 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-11.20230120.1.1
+11.20230122.0.1
diff --git a/chrome/VERSION b/chrome/VERSION
index 74d7a456..e30336f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=111
 MINOR=0
-BUILD=5551
+BUILD=5554
 PATCH=0
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index d1790e7..f1ac0ac218 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-111.0.5544.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-111.0.5550.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 07751bc..042472f4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -8320,10 +8320,6 @@
      FEATURE_VALUE_TYPE(
          password_manager::features::kRevampedPasswordManagementBubble)},
 
-    {"side-search", flag_descriptions::kSideSearchName,
-     flag_descriptions::kSideSearchDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kSideSearch)},
-
     {"search-web-in-side-panel", flag_descriptions::kSearchWebInSidePanelName,
      flag_descriptions::kSearchWebInSidePanelDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kSearchWebInSidePanel)},
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 56b682a..781291fc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -6293,11 +6293,6 @@
     "Enable the new password managment bubble triggered by clicking the key "
     "icon in the omnibox.";
 
-const char kSideSearchName[] = "Side search";
-const char kSideSearchDescription[] =
-    "Enables an easily accessible way to access your most recent Google search "
-    "results page embedded in a browser side panel";
-
 const char kSearchWebInSidePanelName[] = "Search web in side panel";
 const char kSearchWebInSidePanelDescription[] =
     "Displays right-click search results of a highlighted text in side panel";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3fac8b1..fa13bce7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -3626,9 +3626,6 @@
 extern const char kRevampedPasswordManagementBubbleName[];
 extern const char kRevampedPasswordManagementBubbleDescription[];
 
-extern const char kSideSearchName[];
-extern const char kSideSearchDescription[];
-
 extern const char kSearchWebInSidePanelName[];
 extern const char kSearchWebInSidePanelDescription[];
 #endif  // defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 370d3ef..65e2fcf 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -458,8 +458,8 @@
   }
 
  private:
-  raw_ptr<content::RenderFrameHost, DanglingUntriaged> frame_host_;
-  raw_ptr<content::WebContents, DanglingUntriaged> web_contents_;
+  raw_ptr<content::RenderFrameHost> frame_host_;
+  raw_ptr<content::WebContents> web_contents_;
   const int document_cookie_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   base::RepeatingClosure msg_callback_;
@@ -879,6 +879,9 @@
   }
 
   void TearDownOnMainThread() override {
+    // Remove map of objects pointing to //content objects before they go away.
+    frame_content_.clear();
+
     SetShowPrintErrorDialogForTest(base::NullCallback());
     InProcessBrowserTest::TearDownOnMainThread();
   }
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
index ad3281ba..c33bc12 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
@@ -24,7 +24,6 @@
     deps = [
       ":preprocess_generated",
       "../../../../../ui/webui/resources:library",
-      "../../../../../ui/webui/resources:preprocess",
       "../../../../../ui/webui/resources/cr_components/localized_link:build_ts",
     ]
 
diff --git a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
index 0d21f00..fa4988b 100644
--- a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
@@ -29,7 +29,6 @@
     deps = [
       ":preprocess_generated",
       "../../../../../ui/webui/resources:library",
-      "../../../../../ui/webui/resources:preprocess",
     ]
   }
 }
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
index 88dddc4..a8ae1bc8 100644
--- a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
@@ -34,7 +34,6 @@
       ":preprocess",
       ":preprocess_generated",
       "../../../../../ui/webui/resources:library",
-      "../../../../../ui/webui/resources:preprocess",
       "../../../../../ui/webui/resources/cr_components/localized_link:build_ts",
     ]
   }
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn b/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn
index 24aa887..d519d14 100644
--- a/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn
+++ b/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn
@@ -37,7 +37,6 @@
       ":preprocess",
       ":preprocess_generated",
       "../../../../../ui/webui/resources:library",
-      "../../../../../ui/webui/resources:preprocess",
     ]
   }
 }
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index fbc69af..2db13f4 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -52,10 +52,7 @@
     ]
     out_manifest = "$target_gen_dir/$build_manifest"
 
-    deps = [
-      ":build_ts",
-      "../../../../ui/webui/resources:preprocess",
-    ]
+    deps = [ ":build_ts" ]
     excludes = [
       "browser_api.js",
 
@@ -82,10 +79,7 @@
   js_module_in_files = [ "pdf_internal_plugin_wrapper.js" ]
   out_manifest = "$target_gen_dir/$build_internal_plugin_manifest"
 
-  deps = [
-    ":build_ts",
-    "../../../../ui/webui/resources:preprocess",
-  ]
+  deps = [ ":build_ts" ]
   excludes = [
     "browser_api.js",
     "chrome://resources/js/cr.js",
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index dd398aa..b7af3a2 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -39,7 +39,6 @@
     deps = [
       ":build_ts",
       "//chrome/browser/resources/nearby_share/shared:preprocess_v3",
-      "//ui/webui/resources:preprocess",
     ]
     excludes = [
       "chrome://resources/cr_components/app_management/app_management.mojom-webui.js",
diff --git a/chrome/browser/resources/tools/build_webui.gni b/chrome/browser/resources/tools/build_webui.gni
index 01657ac63..568fd44 100644
--- a/chrome/browser/resources/tools/build_webui.gni
+++ b/chrome/browser/resources/tools/build_webui.gni
@@ -243,10 +243,7 @@
       out_manifest = "$target_gen_dir/$bundle_manifest"
       excludes = invoker.optimize_webui_excludes
 
-      deps = [
-        ":build_ts",
-        "//ui/webui/resources:preprocess",
-      ]
+      deps = [ ":build_ts" ]
     }
   }
 
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
index 8f7b0ad..e46ea6c 100644
--- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -507,6 +507,43 @@
   run_loop->Run();
 }
 
+// A favicon update during drag shouldn't trigger the drag flow again. The test
+// passes if the favicon update does not cause a crash. (see
+// https://crbug.com/1364056)
+IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, FaviconChangeDuringBookmarkDrag) {
+  BookmarkModel* model = WaitForBookmarkModel(browser()->profile());
+  const std::u16string kPageTitle(u"foo");
+  const GURL kPageUrl("http://www.google.com");
+  const GURL kFaviconUrl("http://www.google.com/favicon.ico");
+  const BookmarkNode* root = model->bookmark_bar_node();
+  const BookmarkNode* node = model->AddURL(root, 0, kPageTitle, kPageUrl);
+  constexpr gfx::Point kExpectedPoint(100, 100);
+
+  auto run_loop = std::make_unique<base::RunLoop>();
+
+  chrome::DoBookmarkDragCallback cb = base::BindLambdaForTesting(
+      [&run_loop, model, kPageUrl, kFaviconUrl](
+          std::unique_ptr<ui::OSExchangeData> drag_data,
+          gfx::NativeView native_view, ui::mojom::DragEventSource source,
+          gfx::Point point, int operation) {
+        // Simulate a favicon change during the drag operation.
+        model->OnFaviconsChanged({kPageUrl}, kFaviconUrl);
+        run_loop->Quit();
+      });
+
+  constexpr int kDragNodeIndex = 0;
+  chrome::DragBookmarksForTest(
+      browser()->profile(),
+      {{node},
+       kDragNodeIndex,
+       browser()->tab_strip_model()->GetActiveWebContents(),
+       ui::mojom::DragEventSource::kMouse,
+       kExpectedPoint},
+      std::move(cb));
+
+  run_loop->Run();
+}
+
 // Provides coverage for the Bookmark Manager bookmark drag and drag image
 // generation for dragging multiple bookmarks.
 IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, DragMultipleBookmarks) {
diff --git a/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc b/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
index 1ce38949..32072b92 100644
--- a/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
+++ b/chrome/browser/ui/side_search/side_search_side_contents_helper_unittest.cc
@@ -67,7 +67,6 @@
 class SideSearchSideContentsHelperTest : public ::testing::Test {
  public:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures({features::kSideSearch}, {});
     side_contents_ =
         content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
     SideSearchSideContentsHelper::CreateForWebContents(side_contents());
diff --git a/chrome/browser/ui/side_search/side_search_tab_contents_helper_interactive_uitest.cc b/chrome/browser/ui/side_search/side_search_tab_contents_helper_interactive_uitest.cc
index 2f57ee08..3b2e2031 100644
--- a/chrome/browser/ui/side_search/side_search_tab_contents_helper_interactive_uitest.cc
+++ b/chrome/browser/ui/side_search/side_search_tab_contents_helper_interactive_uitest.cc
@@ -52,7 +52,6 @@
  public:
   // InProcessBrowserTest:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures({features::kSideSearch}, {});
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
     InProcessBrowserTest::SetUp();
   }
diff --git a/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc b/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
index 3a04197..24d0f6d91 100644
--- a/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
+++ b/chrome/browser/ui/side_search/side_search_tab_contents_helper_unittest.cc
@@ -37,7 +37,6 @@
 class SideSearchTabContentsHelperTest : public ::testing::Test {
  public:
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(features::kSideSearch);
     web_contents_ =
         content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
     SideSearchTabContentsHelper::CreateForWebContents(web_contents_.get());
diff --git a/chrome/browser/ui/side_search/side_search_utils.cc b/chrome/browser/ui/side_search/side_search_utils.cc
index e854540..1734ba0 100644
--- a/chrome/browser/ui/side_search/side_search_utils.cc
+++ b/chrome/browser/ui/side_search/side_search_utils.cc
@@ -131,6 +131,5 @@
 
 bool IsSideSearchEnabled(const Profile* profile) {
   return !profile->IsOffTheRecord() &&
-         base::FeatureList::IsEnabled(features::kSideSearch) &&
          profile->GetPrefs()->GetBoolean(side_search_prefs::kSideSearchEnabled);
 }
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 8e1049c28..1583416 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -91,10 +91,6 @@
              "QuickCommands",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enables the side search feature for Google Search. Presents recent Google
-// search results in a browser side panel.
-BASE_FEATURE(kSideSearch, "SideSearch", base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kSideSearchFeedback,
              "SideSearchFeedback",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 1d5d95a..e1e1534 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -76,7 +76,6 @@
 BASE_DECLARE_FEATURE(kSidePanelJourneysQueryless);
 BASE_DECLARE_FEATURE(kSidePanelSearchCompanion);
 
-BASE_DECLARE_FEATURE(kSideSearch);
 BASE_DECLARE_FEATURE(kSideSearchFeedback);
 BASE_DECLARE_FEATURE(kSearchWebInSidePanel);
 BASE_DECLARE_FEATURE(kClobberAllSideSearchSidePanels);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
index 21e1cb1..00ee6b2 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
@@ -257,6 +257,11 @@
 
   void OnBookmarkIconLoaded(const BookmarkNode* drag_node,
                             const ui::ImageModel& icon) {
+    // This function should not be called a second time, even if the icon
+    // changes repeatedly.
+    DCHECK(!icon_loaded_);
+    icon_loaded_ = true;
+
     auto weak_this = GetWeakPtr();
     if (web_contents_) {
       const auto& color_provider = web_contents_->GetColorProvider();
@@ -295,8 +300,9 @@
 
   void BookmarkNodeFaviconChanged(BookmarkModel* model,
                                   const BookmarkNode* node) override {
-    if (node->id() != drag_node_id_)
+    if (icon_loaded_ || node->id() != drag_node_id_) {
       return;
+    }
 
     const ui::ImageModel& image =
         ui::ImageModel::FromImage(model_->GetFavicon(node));
@@ -313,6 +319,7 @@
   ui::mojom::DragEventSource source_;
   const gfx::Point start_point_;
   int operation_;
+  bool icon_loaded_ = false;
 
   DoBookmarkDragCallback do_drag_callback_;
 
diff --git a/chrome/browser/ui/views/side_search/unified_side_search_controller_interactive_uitest.cc b/chrome/browser/ui/views/side_search/unified_side_search_controller_interactive_uitest.cc
index d5ff526..58b4c639 100644
--- a/chrome/browser/ui/views/side_search/unified_side_search_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/side_search/unified_side_search_controller_interactive_uitest.cc
@@ -42,8 +42,8 @@
 class SideSearchV2Test : public SideSearchBrowserTest {
  public:
   void SetUp() override {
-    scoped_feature_list_.InitWithFeatures(
-        {features::kSideSearch, features::kSearchWebInSidePanel}, {});
+    scoped_feature_list_.InitWithFeatures({features::kSearchWebInSidePanel},
+                                          {});
     SideSearchBrowserTest::SetUp();
   }
 
@@ -884,7 +884,6 @@
     base::FieldTrialParams params = {{kParam, kTriggerCount}};
 
     feature_list_.InitAndEnableFeaturesWithParameters({
-        {features::kSideSearch, {}},
         {features::kSideSearchAutoTriggering, params},
         {feature_engagement::kIPHSideSearchAutoTriggeringFeature,
          GetFeatureEngagementParams()},
@@ -1014,7 +1013,6 @@
  public:
   SideSearchPageActionLabelTriggerBrowserTest() {
     feature_list_.InitAndEnableFeaturesWithParameters({
-        {features::kSideSearch, {}},
         {feature_engagement::kIPHSideSearchPageActionLabelFeature,
          GetFeatureEngagementParams()},
     });
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 34618e53..43cf112 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1674258898-e51ce7a18af175124aee9060161cd22bfc53b401.profdata
+chrome-linux-main-1674366304-c57ca7c14d6a3d2a1b843c2b6ec5a3464226d8be.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 9633aae..4694923 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1674258898-881341a5011b36d8ea3e48c45b6af4eafa34f766.profdata
+chrome-mac-arm-main-1674366304-b2399fee78f350e2d332c9727e1c2f34777c8dc5.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 178b21b..f58d2f52 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1674258898-d14eb88f6b1eaa638cf4aa2b1cde339d61b2950f.profdata
+chrome-mac-main-1674366304-ab2cf75fe8bdc4238f19bd7b05d8704df769cb57.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 347441f..01bdc720 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1674233356-950956125d6b54eeb8a9d9a03917bb0b09e1a26a.profdata
+chrome-win32-main-1674353262-0383061da851b41875b38d747fe6f512de70fe84.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 2f0461f..16f76a6 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1674248070-d9e687ccca341b4bc57adadd2eef6c025409545d.profdata
+chrome-win64-main-1674353262-83ffa12c81f6e1f40f0bfa7cdc7aa886a5743701.profdata
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index ab10ca1..95766974 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-111-5481.32-1673869449-benchmark-111.0.5544.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-111-5481.32-1673869449-benchmark-111.0.5550.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 59670d9..2136203 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-111-5481.32-1673869449-benchmark-111.0.5544.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-111-5481.32-1673869449-benchmark-111.0.5550.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 2aa2d33..e12060a 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-111-5481.21-1673865504-benchmark-111.0.5544.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-111-5481.21-1673865504-benchmark-111.0.5550.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt
index 40fb852f..690ecac 100644
--- a/chromeos/profiles/orderfile.newest.txt
+++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@
-chromeos-chrome-orderfile-field-110-5447.0-1670842982-benchmark-110.0.5464.0-r2.orderfile.xz
+chromeos-chrome-orderfile-field-110-5481.21-1673266524-benchmark-110.0.5481.34-r1.orderfile.xz
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 8fd128b..96e970f14 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -579,6 +579,7 @@
       "//components/arc:unit_tests",
       "//components/desks_storage:unit_tests",
       "//components/guest_os:unit_tests",
+      "//components/live_caption:unit_tests",
       "//components/metrics/structured:unit_tests",
       "//components/metrics/structured/mojom:unit_tests",
       "//components/ownership:unit_tests",
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 6470a2e..67005d6 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "17.50",
-  "log_list_timestamp": "2023-01-20T12:54:50Z",
+  "version": "17.51",
+  "log_list_timestamp": "2023-01-21T12:54:26Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/heap_profiling/multi_process/test_driver.cc b/components/heap_profiling/multi_process/test_driver.cc
index d6af2ed0..2b79f48d 100644
--- a/components/heap_profiling/multi_process/test_driver.cc
+++ b/components/heap_profiling/multi_process/test_driver.cc
@@ -30,6 +30,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/tracing_controller.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace heap_profiling {
 
@@ -88,8 +89,8 @@
                          std::string name,
                          std::vector<int>* pids) {
   int num_processes = 0;
-  base::Value* events = dump_json->FindKey("traceEvents");
-  for (const base::Value& event : events->GetList()) {
+  base::Value::List* events = dump_json->GetDict().FindList("traceEvents");
+  for (const base::Value& event : *events) {
     const base::Value* found_name =
         event.FindKeyOfType("name", base::Value::Type::STRING);
     if (!found_name)
@@ -125,10 +126,10 @@
 base::Value* FindArgDump(base::ProcessId pid,
                          base::Value* dump_json,
                          const char* arg) {
-  base::Value* events = dump_json->FindKey("traceEvents");
+  base::Value::List* events = dump_json->GetDict().FindList("traceEvents");
   base::Value* dumps = nullptr;
   base::Value* heaps_v2 = nullptr;
-  for (base::Value& event : events->GetList()) {
+  for (base::Value& event : *events) {
     const base::Value* found_name =
         event.FindKeyOfType("name", base::Value::Type::STRING);
     if (!found_name)
@@ -161,29 +162,30 @@
 bool ParseTypes(base::Value* heaps_v2, NodeMap* output) {
   base::Value* types = heaps_v2->FindPath({"maps", "types"});
   for (const base::Value& type_value : types->GetList()) {
-    const base::Value* id = type_value.FindKey("id");
-    const base::Value* name_sid = type_value.FindKey("name_sid");
+    const absl::optional<int> id = type_value.GetDict().FindInt("id");
+    const absl::optional<int> name_sid =
+        type_value.GetDict().FindInt("name_sid");
     if (!id || !name_sid) {
       LOG(ERROR) << "Node missing id or name_sid field";
       return false;
     }
 
     Node node;
-    node.name_id = name_sid->GetInt();
-    (*output)[id->GetInt()] = node;
+    node.name_id = *name_sid;
+    (*output)[*id] = node;
   }
 
   base::Value* strings = heaps_v2->FindPath({"maps", "strings"});
-  for (const base::Value& string_value : strings->GetList()) {
-    const base::Value* id = string_value.FindKey("id");
-    const base::Value* string = string_value.FindKey("string");
+  for (const base::Value& string_dict : strings->GetList()) {
+    const absl::optional<int> id = string_dict.GetDict().FindInt("id");
+    const std::string* string = string_dict.GetDict().FindString("string");
     if (!id || !string) {
       LOG(ERROR) << "String struct missing id or string field";
       return false;
     }
     for (auto& pair : *output) {
-      if (pair.second.name_id == id->GetInt()) {
-        pair.second.name = string->GetString();
+      if (pair.second.name_id == id.value()) {
+        pair.second.name = *string;
         break;
       }
     }
@@ -295,11 +297,11 @@
 
 bool ValidateProcessMmaps(base::Value* process_mmaps,
                           bool should_have_contents) {
-  base::Value* vm_regions = nullptr;
+  base::Value::List* vm_regions = nullptr;
   size_t count = 0;
   if (process_mmaps) {
-    vm_regions = process_mmaps->FindKey("vm_regions");
-    count = vm_regions->GetList().size();
+    vm_regions = process_mmaps->GetDict().FindList("vm_regions");
+    count = vm_regions->size();
   }
   if (!should_have_contents) {
     if (count != 0) {
@@ -316,10 +318,10 @@
 
   // File paths may contain PII. Make sure that "mf" entries only contain the
   // basename, rather than a full path.
-  for (const base::Value& vm_region : vm_regions->GetList()) {
-    const base::Value* file_path_value = vm_region.FindKey("mf");
+  for (const base::Value& vm_region : *vm_regions) {
+    const std::string* file_path_value = vm_region.GetDict().FindString("mf");
     if (file_path_value) {
-      std::string file_path = file_path_value->GetString();
+      const std::string& file_path = *file_path_value;
 
       base::FilePath::StringType path(file_path.begin(), file_path.end());
       if (base::FilePath(path).BaseName().AsUTF8Unsafe() != file_path) {
diff --git a/components/live_caption/BUILD.gn b/components/live_caption/BUILD.gn
index 525cdf0..54e99ce 100644
--- a/components/live_caption/BUILD.gn
+++ b/components/live_caption/BUILD.gn
@@ -8,6 +8,8 @@
   static_library("live_caption") {
     sources = [
       "caption_bubble_context.h",
+      "caption_bubble_context_remote.cc",
+      "caption_bubble_context_remote.h",
       "caption_bubble_controller.h",
       "caption_bubble_session_observer.h",
       "live_caption_controller.cc",
@@ -26,6 +28,7 @@
       "//components/sync_preferences",
       "//media",
       "//media/mojo/mojom",
+      "//mojo/public/cpp/bindings",
       "//ui/native_theme",
     ]
 
@@ -79,6 +82,23 @@
       "//ui/native_theme",
     ]
   }
+
+  source_set("unit_tests") {
+    testonly = true
+
+    sources = [ "caption_bubble_context_remote_unittest.cc" ]
+
+    deps = [
+      ":live_caption",
+      "//base",
+      "//base/test:test_support",
+      "//media/mojo/mojom:speech_recognition",
+      "//mojo/public/cpp/bindings:bindings",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//ui/gfx/geometry:geometry",
+    ]
+  }
 }  # !is_android
 
 source_set("constants") {
diff --git a/components/live_caption/DEPS b/components/live_caption/DEPS
index be5a025..902ca3f 100644
--- a/components/live_caption/DEPS
+++ b/components/live_caption/DEPS
@@ -16,6 +16,8 @@
   "+net/http/http_request_headers.h",
   "+services/data_decoder/public",
   "+services/network/public",
+  "+testing/gmock",
+  "+testing/gtest",
   "+third_party/re2",
   "+ui/accessibility",
   "+ui/base",
diff --git a/components/live_caption/caption_bubble_context.h b/components/live_caption/caption_bubble_context.h
index c9bb566..503343d 100644
--- a/components/live_caption/caption_bubble_context.h
+++ b/components/live_caption/caption_bubble_context.h
@@ -53,9 +53,14 @@
   // in child classes, the child classes must set this to be true.
   virtual bool IsActivatable() const = 0;
 
-  // Gets the session observer for the caption bubble context. On Chrome
+  // Gets a session observer for the caption bubble context. On Chrome
   // browser, a caption bubble session is per-tab and resets when a user
   // navigates away or reloads the page.
+  //
+  // When this method is called, previously-created session observers are
+  // invalidated (i.e. they might not execute their session-end callback) but
+  // not destroyed.
+  //
   // TODO(launch/4200463): Implement this for Ash if necessary.
   virtual std::unique_ptr<CaptionBubbleSessionObserver>
   GetCaptionBubbleSessionObserver() = 0;
diff --git a/components/live_caption/caption_bubble_context_remote.cc b/components/live_caption/caption_bubble_context_remote.cc
new file mode 100644
index 0000000..eb55417
--- /dev/null
+++ b/components/live_caption/caption_bubble_context_remote.cc
@@ -0,0 +1,109 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/live_caption/caption_bubble_context_remote.h"
+
+#include <memory>
+#include <string>
+
+#include "base/functional/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "components/live_caption/caption_bubble_session_observer.h"
+#include "media/mojo/mojom/speech_recognition.mojom.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace captions {
+
+// Holds a callback to be run when a live captioning "session" (essentially,
+// caption generation for one page) ends for a fixed caption bubble context. The
+// context is responsible for signaling a session end when e.g. a navigation
+// occurs or the page is reloaded.
+//
+// In the Ash browser, the caption bubble controller creates and holds one of
+// these objects for each context. The object is then manually destroyed when
+// the context is invalidated.
+class CaptionBubbleSessionObserverRemote : public CaptionBubbleSessionObserver {
+ public:
+  explicit CaptionBubbleSessionObserverRemote(const std::string& session_id)
+      : session_id_(session_id) {}
+  ~CaptionBubbleSessionObserverRemote() override = default;
+  CaptionBubbleSessionObserverRemote(
+      const CaptionBubbleSessionObserverRemote&) = delete;
+  CaptionBubbleSessionObserverRemote& operator=(
+      const CaptionBubbleSessionObserverRemote&) = delete;
+
+  void SetEndSessionCallback(EndSessionCallback callback) override {
+    callback_ = std::move(callback);
+  }
+
+  void OnSessionEnded() {
+    if (callback_) {
+      std::move(callback_).Run(session_id_);
+    }
+  }
+
+  base::WeakPtr<CaptionBubbleSessionObserverRemote> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  const std::string session_id_;
+
+  EndSessionCallback callback_;
+
+  base::WeakPtrFactory<CaptionBubbleSessionObserverRemote> weak_ptr_factory_{
+      this};
+};
+
+CaptionBubbleContextRemote::CaptionBubbleContextRemote(
+    mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface,
+    const std::string& session_id)
+    : session_id_(session_id), surface_(std::move(surface)) {}
+
+CaptionBubbleContextRemote::~CaptionBubbleContextRemote() {
+  if (session_observer_) {
+    session_observer_->OnSessionEnded();
+  }
+}
+
+void CaptionBubbleContextRemote::GetBounds(GetBoundsCallback callback) const {
+  // Forwards the rect to our callback only if it is non-nullopt.
+  auto maybe_run_cb = [](GetBoundsCallback cb,
+                         const absl::optional<gfx::Rect>& bounds) {
+    if (bounds.has_value()) {
+      std::move(cb).Run(*bounds);
+    }
+  };
+
+  surface_->GetBounds(
+      base::BindOnce(std::move(maybe_run_cb), std::move(callback)));
+}
+
+const std::string CaptionBubbleContextRemote::GetSessionId() const {
+  return session_id_;
+}
+
+void CaptionBubbleContextRemote::Activate() {
+  surface_->Activate();
+}
+
+bool CaptionBubbleContextRemote::IsActivatable() const {
+  return true;
+}
+
+std::unique_ptr<CaptionBubbleSessionObserver>
+CaptionBubbleContextRemote::GetCaptionBubbleSessionObserver() {
+  auto session_observer =
+      std::make_unique<CaptionBubbleSessionObserverRemote>(session_id_);
+  session_observer_ = session_observer->GetWeakPtr();
+  return session_observer;
+}
+
+void CaptionBubbleContextRemote::OnSessionEnded() {
+  if (session_observer_) {
+    session_observer_->OnSessionEnded();
+  }
+}
+
+}  // namespace captions
diff --git a/components/live_caption/caption_bubble_context_remote.h b/components/live_caption/caption_bubble_context_remote.h
new file mode 100644
index 0000000..c2afa03
--- /dev/null
+++ b/components/live_caption/caption_bubble_context_remote.h
@@ -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.
+
+#ifndef COMPONENTS_LIVE_CAPTION_CAPTION_BUBBLE_CONTEXT_REMOTE_H_
+#define COMPONENTS_LIVE_CAPTION_CAPTION_BUBBLE_CONTEXT_REMOTE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "components/live_caption/caption_bubble_context.h"
+#include "media/mojo/mojom/speech_recognition.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace captions {
+
+class CaptionBubbleSessionObserver;
+class CaptionBubbleSessionObserverRemote;
+
+// The bubble context for captions generated in a remote process. Methods of
+// this class delegate to the remote implementation via Mojo.
+class CaptionBubbleContextRemote : public CaptionBubbleContext {
+ public:
+  CaptionBubbleContextRemote(
+      mojo::PendingRemote<media::mojom::SpeechRecognitionSurface> surface,
+      const std::string& session_id);
+  ~CaptionBubbleContextRemote() override;
+  CaptionBubbleContextRemote(const CaptionBubbleContextRemote&) = delete;
+  CaptionBubbleContextRemote& operator=(const CaptionBubbleContextRemote&) =
+      delete;
+
+  // CaptionBubbleContext:
+  void GetBounds(GetBoundsCallback callback) const override;
+  const std::string GetSessionId() const override;
+  void Activate() override;
+  bool IsActivatable() const override;
+  std::unique_ptr<CaptionBubbleSessionObserver>
+  GetCaptionBubbleSessionObserver() override;
+
+  // Triggers the end-of-session callback if there is an active caption bubble
+  // session observer.
+  void OnSessionEnded();
+
+ private:
+  const std::string session_id_;
+
+  base::WeakPtr<CaptionBubbleSessionObserverRemote> session_observer_;
+
+  mojo::Remote<media::mojom::SpeechRecognitionSurface> surface_;
+};
+
+}  // namespace captions
+
+#endif  // COMPONENTS_LIVE_CAPTION_CAPTION_BUBBLE_CONTEXT_REMOTE_H_
diff --git a/components/live_caption/caption_bubble_context_remote_unittest.cc b/components/live_caption/caption_bubble_context_remote_unittest.cc
new file mode 100644
index 0000000..2b910f6
--- /dev/null
+++ b/components/live_caption/caption_bubble_context_remote_unittest.cc
@@ -0,0 +1,149 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/live_caption/caption_bubble_context_remote.h"
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "media/mojo/mojom/speech_recognition.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace captions {
+namespace {
+
+using media::mojom::SpeechRecognitionSurface;
+using testing::_;
+using testing::Test;
+
+// A surface whose methods can have expectations placed on them.
+class MockSurface : public SpeechRecognitionSurface {
+ public:
+  explicit MockSurface(mojo::PendingReceiver<SpeechRecognitionSurface> receiver)
+      : receiver_(this, std::move(receiver)) {}
+  ~MockSurface() override = default;
+
+  MockSurface(const MockSurface&) = delete;
+  MockSurface& operator=(const MockSurface&) = delete;
+
+  // media::mojom::SpeechRecognitionSurface:
+  MOCK_METHOD(void, Activate, (), (override));
+  MOCK_METHOD(void,
+              GetBounds,
+              (SpeechRecognitionSurface::GetBoundsCallback),
+              (override));
+
+ private:
+  mojo::Receiver<SpeechRecognitionSurface> receiver_;
+};
+
+class CaptionBubbleContextRemoteTest : public Test {
+ public:
+  CaptionBubbleContextRemoteTest() = default;
+  ~CaptionBubbleContextRemoteTest() override = default;
+
+  CaptionBubbleContextRemoteTest(const CaptionBubbleContextRemoteTest&) =
+      delete;
+  CaptionBubbleContextRemoteTest& operator=(
+      const CaptionBubbleContextRemoteTest&) = delete;
+
+  void SetUp() override {
+    mojo::PendingReceiver<SpeechRecognitionSurface> receiver;
+    context_.emplace(receiver.InitWithNewPipeAndPassRemote(), "session-id");
+    surface_.emplace(std::move(receiver));
+  }
+
+ protected:
+  // Use optionals to delay initialization while keeping objects on the stack.
+  absl::optional<CaptionBubbleContextRemote> context_;
+  absl::optional<MockSurface> surface_;
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+};
+
+// Test that activate requests are forwarded to the remote process.
+TEST_F(CaptionBubbleContextRemoteTest, Activate) {
+  EXPECT_CALL(*surface_, Activate()).Times(2);
+
+  // Our expectation that the activate call is forwarded over Mojo should be
+  // met.
+  context_->Activate();
+  context_->Activate();
+  base::RunLoop().RunUntilIdle();
+}
+
+// Test that bounds requests are forwarded to the remote process.
+TEST_F(CaptionBubbleContextRemoteTest, GetBounds) {
+  // Note expectations are saturated from last to first.
+  const gfx::Rect expected_bounds_1 = gfx::Rect(1, 2, 3, 4);
+  const gfx::Rect expected_bounds_2 = gfx::Rect(5, 6, 7, 8);
+  EXPECT_CALL(*surface_, GetBounds(_))
+      .WillOnce([&](auto cb) { std::move(cb).Run(expected_bounds_2); })
+      .RetiresOnSaturation();
+  EXPECT_CALL(*surface_, GetBounds(_))
+      .WillOnce([&](auto cb) { std::move(cb).Run(expected_bounds_1); })
+      .RetiresOnSaturation();
+
+  // First call should correctly fetch first bounds.
+  gfx::Rect actual_bounds;
+  context_->GetBounds(base::BindLambdaForTesting(
+      [&](const gfx::Rect& bounds) { actual_bounds = bounds; }));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(expected_bounds_1, actual_bounds);
+
+  // Next call should correctly fetch updated bounds.
+  context_->GetBounds(base::BindLambdaForTesting(
+      [&](const gfx::Rect& bounds) { actual_bounds = bounds; }));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(expected_bounds_2, actual_bounds);
+}
+
+// Test that replacing an observer is handled gracefully.
+TEST_F(CaptionBubbleContextRemoteTest, DuplicateObservers) {
+  bool ended_1 = false;
+  bool ended_2 = false;
+
+  // This observer will be replaced before it can execute its callback.
+  auto observer_1 = context_->GetCaptionBubbleSessionObserver();
+  observer_1->SetEndSessionCallback(base::BindLambdaForTesting(
+      [&](const std::string& id) { ended_1 = id == "session-id"; }));
+
+  // Creating a new observer will invalidate the old one.
+  auto observer_2 = context_->GetCaptionBubbleSessionObserver();
+  observer_2->SetEndSessionCallback(base::BindLambdaForTesting(
+      [&](const std::string& id) { ended_2 = id == "session-id"; }));
+
+  // Trigger session end and make sure one callback is called.
+  context_->OnSessionEnded();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(ended_1);
+  EXPECT_TRUE(ended_2);
+}
+
+// If the observer is dead by the time the session is ended, it shouldn't be
+// exercised.
+TEST_F(CaptionBubbleContextRemoteTest, DeadObserver) {
+  auto observer = context_->GetCaptionBubbleSessionObserver();
+  observer->SetEndSessionCallback(base::BindLambdaForTesting(
+      [&](const std::string& id) { EXPECT_TRUE(false); }));
+  observer.reset();
+
+  // Trigger session end.
+  context_->OnSessionEnded();
+  base::RunLoop().RunUntilIdle();
+
+  // We shouldn't try to call methods on the destructed observer.
+}
+
+}  // namespace
+}  // namespace captions
diff --git a/components/webcrypto/jwk.cc b/components/webcrypto/jwk.cc
index 41dd57d..878face 100644
--- a/components/webcrypto/jwk.cc
+++ b/components/webcrypto/jwk.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <set>
+#include <utility>
 
 #include "base/base64url.h"
 #include "base/cxx17_backports.h"
@@ -14,8 +15,10 @@
 #include "base/json/json_writer.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
+#include "base/values.h"
 #include "components/webcrypto/algorithms/util.h"
 #include "components/webcrypto/status.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 // JSON Web Key Format (JWK) is defined by:
 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key
@@ -190,11 +193,9 @@
 
 }  // namespace
 
-JwkReader::JwkReader() {
-}
+JwkReader::JwkReader() = default;
 
-JwkReader::~JwkReader() {
-}
+JwkReader::~JwkReader() = default;
 
 Status JwkReader::Init(base::span<const uint8_t> bytes,
                        bool expected_extractable,
@@ -213,7 +214,7 @@
     if (!dict.has_value() || !dict->is_dict())
       return Status::ErrorJwkNotDictionary();
 
-    dict_ = std::move(dict.value());
+    dict_ = std::move(dict.value()).TakeDict();
   }
 
   // JWK "kty". Exit early if this required JWK parameter is missing.
@@ -244,16 +245,18 @@
 }
 
 bool JwkReader::HasMember(base::StringPiece member_name) const {
-  return !!dict_.FindKey(member_name);
+  return dict_.contains(member_name);
 }
 
 Status JwkReader::GetString(base::StringPiece member_name,
                             std::string* result) const {
-  const base::Value* value = dict_.FindKey(member_name);
-  if (!value)
+  const base::Value* value = dict_.Find(member_name);
+  if (!value) {
     return Status::ErrorJwkMemberMissing(member_name);
-  if (!value->is_string())
+  }
+  if (!value->is_string()) {
     return Status::ErrorJwkMemberWrongType(member_name, "string");
+  }
   *result = value->GetString();
   return Status::Success();
 }
@@ -262,12 +265,14 @@
                                     std::string* result,
                                     bool* member_exists) const {
   *member_exists = false;
-  const base::Value* value = dict_.FindKey(member_name);
-  if (!value)
+  const base::Value* value = dict_.Find(member_name);
+  if (!value) {
     return Status::Success();
+  }
 
-  if (!value->is_string())
+  if (!value->is_string()) {
     return Status::ErrorJwkMemberWrongType(member_name, "string");
+  }
 
   *result = value->GetString();
   *member_exists = true;
@@ -278,12 +283,14 @@
                                   const base::Value::List** result,
                                   bool* member_exists) const {
   *member_exists = false;
-  const base::Value* value = dict_.FindKey(member_name);
-  if (!value)
+  const base::Value* value = dict_.Find(member_name);
+  if (!value) {
     return Status::Success();
+  }
 
-  if (!value->is_list())
+  if (!value->is_list()) {
     return Status::ErrorJwkMemberWrongType(member_name, "list");
+  }
 
   *result = &value->GetList();
   *member_exists = true;
@@ -332,12 +339,14 @@
                                   bool* result,
                                   bool* member_exists) const {
   *member_exists = false;
-  const base::Value* value = dict_.FindKey(member_name);
-  if (!value)
+  const base::Value* value = dict_.Find(member_name);
+  if (!value) {
     return Status::Success();
+  }
 
-  if (!value->is_bool())
+  if (!value->is_bool()) {
     return Status::ErrorJwkMemberWrongType(member_name, "boolean");
+  }
 
   *result = value->GetBool();
   *member_exists = true;
@@ -364,18 +373,18 @@
 JwkWriter::JwkWriter(base::StringPiece algorithm,
                      bool extractable,
                      blink::WebCryptoKeyUsageMask usages,
-                     base::StringPiece kty)
-    : dict_(base::Value::Type::DICTIONARY) {
-  if (!algorithm.empty())
-    dict_.SetStringKey("alg", algorithm);
-  dict_.SetKey("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages));
-  dict_.SetBoolKey("ext", extractable);
-  dict_.SetStringKey("kty", kty);
+                     base::StringPiece kty) {
+  if (!algorithm.empty()) {
+    dict_.Set("alg", algorithm);
+  }
+  dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages));
+  dict_.Set("ext", extractable);
+  dict_.Set("kty", kty);
 }
 
 void JwkWriter::SetString(base::StringPiece member_name,
                           base::StringPiece value) {
-  dict_.SetStringKey(member_name, value);
+  dict_.Set(member_name, value);
 }
 
 void JwkWriter::SetBytes(base::StringPiece member_name,
@@ -388,7 +397,7 @@
                         value.size()),
       base::Base64UrlEncodePolicy::OMIT_PADDING, &base64url_encoded);
 
-  dict_.SetStringKey(member_name, base64url_encoded);
+  dict_.Set(member_name, std::move(base64url_encoded));
 }
 
 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const {
diff --git a/components/webcrypto/jwk.h b/components/webcrypto/jwk.h
index f823a52d..814b324 100644
--- a/components/webcrypto/jwk.h
+++ b/components/webcrypto/jwk.h
@@ -101,7 +101,7 @@
   Status VerifyAlg(base::StringPiece expected_alg) const;
 
  private:
-  base::Value dict_;
+  base::Value::Dict dict_;
 };
 
 // Helper class for building the JSON for a JWK.
@@ -126,7 +126,7 @@
   void ToJson(std::vector<uint8_t>* utf8_bytes) const;
 
  private:
-  base::Value dict_;
+  base::Value::Dict dict_;
 };
 
 // Converts a JWK "key_ops" array to the corresponding WebCrypto usages. Used by
diff --git a/content/browser/renderer_host/frame_tree.cc b/content/browser/renderer_host/frame_tree.cc
index f8852d1..fc4785fc 100644
--- a/content/browser/renderer_host/frame_tree.cc
+++ b/content/browser/renderer_host/frame_tree.cc
@@ -39,6 +39,7 @@
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/common/loader/loader_constants.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom.h"
 
 namespace content {
@@ -972,4 +973,23 @@
   }
 }
 
+void FrameTree::RegisterOriginForUnpartitionedSessionStorageAccess(
+    const url::Origin& origin) {
+  if (origin.opaque()) {
+    return;
+  }
+  unpartitioned_session_storage_origins_.insert(origin);
+}
+
+const blink::StorageKey FrameTree::GetSessionStorageKey(
+    const blink::StorageKey& storage_key) {
+  if (unpartitioned_session_storage_origins_.find(storage_key.origin()) !=
+      unpartitioned_session_storage_origins_.end()) {
+    // If the storage key matches a participating origin we need to return the
+    // first-party version for use in binding session storage.
+    return blink::StorageKey(storage_key.origin());
+  }
+  return storage_key;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/frame_tree.h b/content/browser/renderer_host/frame_tree.h
index efb8e074..b8f8cdc 100644
--- a/content/browser/renderer_host/frame_tree.h
+++ b/content/browser/renderer_host/frame_tree.h
@@ -31,6 +31,7 @@
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-forward.h"
+#include "url/origin.h"
 
 namespace blink {
 namespace mojom {
@@ -39,6 +40,7 @@
 }  // namespace mojom
 
 struct FramePolicy;
+class StorageKey;
 }  // namespace blink
 
 namespace content {
@@ -537,6 +539,20 @@
   // each inner FrameTree is attached.
   void FocusOuterFrameTrees();
 
+  // This should only be called by NavigationRequest when it detects that an
+  // origin is participating in the deprecation trial.
+  //
+  // TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
+  void RegisterOriginForUnpartitionedSessionStorageAccess(
+      const url::Origin& origin);
+
+  // This should be used for all session storage related bindings as it adjusts
+  // the storage key used depending on the deprecation trial.
+  //
+  // TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
+  const blink::StorageKey GetSessionStorageKey(
+      const blink::StorageKey& storage_key);
+
  private:
   friend class FrameTreeTest;
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostImplBrowserTest, RemoveFocusedFrame);
@@ -635,6 +651,13 @@
   // For that reason, we want to destroy |root_| before any other fields.
   FrameTreeNode root_;
 
+  // Origins in this set have enabled a deprecation trial that prevents the
+  // partitioning of session storage when embedded as a third-party iframe.
+  // This list persists for the lifetime of the associated tab.
+  //
+  // TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
+  std::set<url::Origin> unpartitioned_session_storage_origins_;
+
   base::WeakPtrFactory<FrameTree> weak_ptr_factory_{this};
 };
 
diff --git a/content/browser/renderer_host/frame_tree_browsertest.cc b/content/browser/renderer_host/frame_tree_browsertest.cc
index 1bf961e..ec88cbb 100644
--- a/content/browser/renderer_host/frame_tree_browsertest.cc
+++ b/content/browser/renderer_host/frame_tree_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
 #include "base/test/scoped_feature_list.h"
@@ -24,6 +25,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/content_mock_cert_verifier.h"
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -36,10 +38,12 @@
 #include "net/test/embedded_test_server/default_handlers.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
+#include "services/network/public/cpp/network_switches.h"
 #include "services/network/public/cpp/web_sandbox_flags.h"
 #include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
 #include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
 #include "url/url_constants.h"
 
@@ -1586,4 +1590,144 @@
                          "window.credentialless"));
 }
 
+// TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
+class FrameTreeSessionStorageDeprecationTrialBrowserTest
+    : public ContentBrowserTest {
+ public:
+  FrameTreeSessionStorageDeprecationTrialBrowserTest()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
+    feature_list_.InitAndEnableFeature(
+        net::features::kThirdPartyStoragePartitioning);
+  }
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    https_server_.ServeFilesFromSourceDirectory("content/test/data");
+    // EmbeddedTestServer::InitializeAndListen() initializes its `base_url_`
+    // which is required below. This cannot invoke Start() however as that kicks
+    // off the "EmbeddedTestServer IO Thread" which then races with
+    // initialization in ContentBrowserTest::SetUp(), http://crbug.com/674545.
+    ASSERT_TRUE(https_server_.InitializeAndListen());
+
+    // Add a host resolver rule to map all outgoing requests to the test server.
+    // This allows us to use "real" hostnames in URLs, which we can use to
+    // create arbitrary SiteInstances.
+    command_line->AppendSwitchASCII(
+        network::switches::kHostResolverRules,
+        "MAP * " +
+            net::HostPortPair::FromURL(https_server_.base_url()).ToString() +
+            ",EXCLUDE localhost");
+    mock_cert_verifier_.SetUpCommandLine(command_line);
+  }
+
+  void SetUp() override { ContentBrowserTest::SetUp(); }
+
+  void SetUpOnMainThread() override {
+    // Complete the manual Start() after ContentBrowserTest's own
+    // initialization, ref. comment on InitializeAndListen() above.
+    https_server_.StartAcceptingConnections();
+    mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
+  }
+
+  void TearDownInProcessBrowserTestFixture() override {
+    mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  content::ContentMockCertVerifier mock_cert_verifier_;
+  net::EmbeddedTestServer https_server_;
+};
+
+IN_PROC_BROWSER_TEST_F(FrameTreeSessionStorageDeprecationTrialBrowserTest,
+                       RegisterOriginForUnpartitionedSessionStorageAccess) {
+  const url::Origin origin = url::Origin::Create(GURL("https://example.com"));
+  const blink::StorageKey first_party = blink::StorageKey(origin);
+  const blink::StorageKey third_party =
+      blink::StorageKey::CreateWithOptionalNonce(
+          origin, net::SchemefulSite(GURL("https://notexample.com")), nullptr,
+          blink::mojom::AncestorChainBit::kSameSite);
+  const url::Origin opaque_origin = url::Origin();
+  const blink::StorageKey opaque_first_party = blink::StorageKey(opaque_origin);
+  const blink::StorageKey opaque_third_party =
+      blink::StorageKey::CreateWithOptionalNonce(
+          opaque_origin, net::SchemefulSite(GURL("https://notexample.com")),
+          nullptr, blink::mojom::AncestorChainBit::kSameSite);
+  EXPECT_NE(first_party, third_party);
+  EXPECT_NE(opaque_first_party, opaque_third_party);
+  FrameTree& frame_tree = static_cast<WebContentsImpl*>(shell()->web_contents())
+                              ->GetPrimaryFrameTree();
+
+  // Before registering any origins we expect partitioned access for both keys.
+  EXPECT_EQ(third_party, frame_tree.GetSessionStorageKey(third_party));
+  EXPECT_EQ(opaque_third_party,
+            frame_tree.GetSessionStorageKey(opaque_third_party));
+
+  // We then register both origins.
+  frame_tree.RegisterOriginForUnpartitionedSessionStorageAccess(origin);
+  frame_tree.RegisterOriginForUnpartitionedSessionStorageAccess(opaque_origin);
+
+  // After registration the non-opaque key is unpartitioned but the opaque one
+  // is still partitioned.
+  EXPECT_EQ(first_party, frame_tree.GetSessionStorageKey(third_party));
+  EXPECT_EQ(opaque_third_party,
+            frame_tree.GetSessionStorageKey(opaque_third_party));
+}
+
+IN_PROC_BROWSER_TEST_F(FrameTreeSessionStorageDeprecationTrialBrowserTest,
+                       GetSessionStorageKey) {
+  const blink::StorageKey dt_third_party =
+      blink::StorageKey::CreateWithOptionalNonce(
+          url::Origin::Create(GURL("https://example.com")),
+          net::SchemefulSite(GURL("https://notexample.com")), nullptr,
+          blink::mojom::AncestorChainBit::kSameSite);
+  const blink::StorageKey dt_first_party =
+      blink::StorageKey::CreateFromStringForTesting("https://example.com");
+  const blink::StorageKey random_third_party =
+      blink::StorageKey::CreateWithOptionalNonce(
+          url::Origin::Create(GURL("https://otherexample.com")),
+          net::SchemefulSite(GURL("https://notexample.com")), nullptr,
+          blink::mojom::AncestorChainBit::kSameSite);
+  EXPECT_NE(dt_third_party, dt_first_party);
+
+  // Load a page without the origin trial token.
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.com/empty.html")));
+  // We should be able to get a partitioned storage key for example.com.
+  EXPECT_EQ(dt_third_party,
+            static_cast<WebContentsImpl*>(shell()->web_contents())
+                ->GetPrimaryFrameTree()
+                .GetSessionStorageKey(dt_third_party));
+
+  // Load a page with the origin trial token.
+  EXPECT_TRUE(NavigateToURL(shell(), GURL("https://example.com/session_storage/"
+                                          "partition_deprecation_trial.html")));
+  // We shouldn't be able to get a partitioned storage key for example.com.
+  EXPECT_EQ(dt_first_party,
+            static_cast<WebContentsImpl*>(shell()->web_contents())
+                ->GetPrimaryFrameTree()
+                .GetSessionStorageKey(dt_third_party));
+  // Other origins can still get partitioned storage keys.
+  EXPECT_EQ(random_third_party,
+            static_cast<WebContentsImpl*>(shell()->web_contents())
+                ->GetPrimaryFrameTree()
+                .GetSessionStorageKey(random_third_party));
+
+  // Load a page without the token after having loaded a page with the token.
+  EXPECT_TRUE(
+      NavigateToURL(shell(), GURL("https://otherexample.com/empty.html")));
+  // We shouldn't be able to get a partitioned storage key for example.com.
+  EXPECT_EQ(dt_first_party,
+            static_cast<WebContentsImpl*>(shell()->web_contents())
+                ->GetPrimaryFrameTree()
+                .GetSessionStorageKey(dt_third_party));
+  // Other origins can still get partitioned storage keys.
+  EXPECT_EQ(random_third_party,
+            static_cast<WebContentsImpl*>(shell()->web_contents())
+                ->GetPrimaryFrameTree()
+                .GetSessionStorageKey(random_third_party));
+}
 }  // namespace content
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index b968784..b63a287 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -40,6 +40,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/common/content_navigation_policy.h"
+#include "content/common/features.h"
 #include "content/common/frame_messages.mojom.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -22171,22 +22172,61 @@
   EXPECT_TRUE(b1_navigation.GetNavigationHandle());
 
   // 4) Start a same-RFH navigation to A3 after B1 gets to "pending commit"
-  // stage, which won't cancel the previous cross-RFH navigation to B1, as B1's
-  // NavigationRequest had moved.
+  // stage. The behavior depends on whether
+  // the kAvoidUnnecessaryNavigationCancellations flag is enabled or not:
+  // - If the flag is enabled, A3's navigation won't cancel the previous
+  //  cross-RFH navigation to B1, as B1's NavigationRequest had moved.
+  // - If the flag is disabled,  A3's navigation will cancel the previous
+  // cross-RFH navigation to B1, because when a same-RFH navigation starts
+  // it will delete the speculative RFH.
   TestNavigationManager a3_navigation(shell()->web_contents(), url_a3);
   EXPECT_TRUE(b1_navigation.WaitForResponse());
   StartNavigationOnReadyToCommit(shell(), b1_navigation, url_a3);
 
-  // Assert that the navigation to B1 didn't get cancelled, and finish
-  // committing B1. This shouldn't cancel the navigation to A3.
-  ASSERT_TRUE(b1_navigation.WaitForNavigationFinished());
-  EXPECT_TRUE(b1_navigation.was_successful());
+  if (base::FeatureList::IsEnabled(kAvoidUnnecessaryNavigationCancellations)) {
+    // Assert that the navigation to B1 didn't get cancelled, and finish
+    // committing B1. This shouldn't cancel the navigation to A3.
+    ASSERT_TRUE(b1_navigation.WaitForNavigationFinished());
+    EXPECT_TRUE(b1_navigation.was_successful());
 
-  // B1's navigation commit didn't cancel A3's navigation.
-  EXPECT_TRUE(a3_navigation.WaitForResponse());
-  EXPECT_TRUE(a3_navigation.GetNavigationHandle());
-  ASSERT_TRUE(a3_navigation.WaitForNavigationFinished());
-  EXPECT_TRUE(a3_navigation.was_successful());
+    // B1's navigation commit didn't cancel A3's navigation.
+    EXPECT_TRUE(a3_navigation.WaitForResponse());
+    EXPECT_TRUE(a3_navigation.GetNavigationHandle());
+    ASSERT_TRUE(a3_navigation.WaitForNavigationFinished());
+    EXPECT_TRUE(a3_navigation.was_successful());
+  } else {
+    EXPECT_TRUE(a3_navigation.WaitForResponse());
+    EXPECT_EQ(url_a3, a3_navigation.GetNavigationHandle()->GetURL());
+    EXPECT_EQ(root->navigation_request(), a3_navigation.GetNavigationHandle());
+
+    // Assert that the navigation to B1 gets cancelled.
+    EXPECT_TRUE(b1_navigation.WaitForNavigationFinished());
+    EXPECT_FALSE(b1_navigation.was_committed());
+
+    // 5) Start a cross-RFH navigation to B2 after A3 gets to "pending commit"
+    // stage, which will cancel the previous same-RFH navigation to A3 when B2
+    // commits first, because when the previous RFH gets unloaded it will
+    // cancel all ongoing navigations in the pending deletion RFH.
+    TestNavigationManager b2_navigation(shell()->web_contents(), url_b2);
+    // Ignore A3's commit so that B2's navigation can start and finish
+    // committing before A3 finishes committing.
+    DidCommitNavigationCanceller ignore_a3_commit(
+        shell()->web_contents(), url_a3,
+        base::BindLambdaForTesting([&]() { shell()->LoadURL(url_b2); }));
+    // Continue the A3 navigation, but its commit will be dropped.
+    a3_navigation.ResumeNavigation();
+    // The navigation to B2 will start, but won't cancel A3's navigation just
+    // yet.
+    EXPECT_TRUE(b2_navigation.WaitForResponse());
+    EXPECT_TRUE(a3_navigation.GetNavigationHandle());
+
+    // The navigation to B2 finished committing, and cancels A3's navigation.
+    EXPECT_TRUE(b2_navigation.WaitForNavigationFinished());
+    EXPECT_TRUE(b2_navigation.was_successful());
+    // Assert A3's navigation finished but didn't get committed.
+    EXPECT_TRUE(a3_navigation.WaitForNavigationFinished());
+    EXPECT_FALSE(a3_navigation.was_committed());
+  }
 }
 
 // Tests that calling FrameTreeNode::ResetNavigationRequest() cancels the
@@ -22252,6 +22292,9 @@
 // cancel other navigations happening in the same FrameTreeNode.
 IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
                        UnloadingPreviousRFHOnCommitWontCancelNavigation) {
+  if (!base::FeatureList::IsEnabled(kAvoidUnnecessaryNavigationCancellations)) {
+    return;
+  }
   GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
   GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index b28dcec..77f0dc26 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -159,6 +159,7 @@
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/navigation/navigation_params_mojom_traits.h"
 #include "third_party/blink/public/common/navigation/navigation_policy.h"
+#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
 #include "third_party/blink/public/common/permissions_policy/document_policy.h"
 #include "third_party/blink/public/common/permissions_policy/permissions_policy_features.h"
 #include "third_party/blink/public/common/permissions_policy/policy_helper_public.h"
@@ -6779,6 +6780,10 @@
   ready_to_commit_time_ = base::TimeTicks::Now();
   RestartCommitTimeout();
 
+  if (!IsSameDocument()) {
+    MaybeRegisterOriginForUnpartitionedSessionStorageAccess();
+  }
+
   if (!IsSameDocument() && !IsPageActivation())
     UpdatePrivateNetworkRequestPolicy();
 
@@ -8662,4 +8667,21 @@
   }
 }
 
+void NavigationRequest::
+    MaybeRegisterOriginForUnpartitionedSessionStorageAccess() {
+  if (!common_params_ || !response_head_ || !response_head_->headers) {
+    return;
+  }
+  if (!blink::TrialTokenValidator().RequestEnablesFeature(
+          common_params_->url, response_head_->headers.get(),
+          "DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning",
+          base::Time::Now())) {
+    return;
+  }
+  frame_tree_node()
+      ->frame_tree()
+      .RegisterOriginForUnpartitionedSessionStorageAccess(
+          url::Origin::Create(common_params_->url));
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 6fb5ad13..b141ffcf 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -1726,6 +1726,16 @@
   // NavigationRequest associated with the same FrameTreeNode is destroyed.
   void ResumeCommitIfNeeded();
 
+  // Used to detect if the page being navigated to is participating in the
+  // related deprecation trial and recording that in NavigationControllerImpl.
+  //
+  // Not called for same-document navigation requests nor for requests served
+  // from the back-forward cache or from prerendered pages as work would be
+  // redundant.
+  //
+  // TODO(crbug.com/1407150): Remove this when deprecation trial is complete.
+  void MaybeRegisterOriginForUnpartitionedSessionStorageAccess();
+
   // Never null. The pointee node owns this navigation request instance.
   FrameTreeNode* const frame_tree_node_;
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index c06e1c7..82ae8e38 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -1661,6 +1661,8 @@
 }
 
 RenderFrameHostImpl::~RenderFrameHostImpl() {
+  SCOPED_CRASH_KEY_STRING256("Bug1407526", "lifecycle",
+                             LifecycleStateImplToString(lifecycle_state()));
   TRACE_EVENT("navigation", "~RenderFrameHostImpl()",
               ChromeTrackEvent::kRenderFrameHost, this);
   // See https://crbug.com/1276535
@@ -1706,10 +1708,15 @@
   g_token_frame_map.Get().erase(frame_token_);
 
   auto* process = GetProcess();
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "si_exists", !!site_instance_);
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "sig_exists", !!site_instance_->group());
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "process_exists", !!process);
   site_instance_->group()->RemoveObserver(this);
   process->UnregisterRenderFrameHost(GetGlobalId());
 
   const bool was_created = is_render_frame_created();
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "was_created", !!was_created);
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "delegate_exists", !!delegate_);
   render_frame_state_ = RenderFrameState::kDeleted;
   if (was_created)
     delegate_->RenderFrameDeleted(this);
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index e678cc3..8bdf561b2 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -1043,10 +1043,17 @@
   // in the long run. For now, and to avoid complex edge cases, we simply reuse
   // it to preserve the understood logic in CommitPending.
 
-  // There should be no speculative RFH at this point. With BackForwardCache, it
+  // When the kAvoidUnnecessaryNavigationCancellations flag is disabled, there
+  // should be no speculative RFH at this point. With BackForwardCache, it
   // should have never been created, and with prerender activation, it should
   // have been cleared out earlier.
-  DCHECK(!speculative_render_frame_host_);
+  // TODO(https://crbug.com/1220337): Ensure we aren't deleting a pending commit
+  // RFH.
+  DCHECK(
+      base::FeatureList::IsEnabled(kAvoidUnnecessaryNavigationCancellations) ||
+      !speculative_render_frame_host_);
+  SCOPED_CRASH_KEY_BOOL("Bug1407526", "spec_rfh_exists",
+                        !!speculative_render_frame_host_);
   speculative_render_frame_host_ = stored_page->TakeRenderFrameHost();
   // Now |stored_page| is destroyed and thus does not monitor cookie changes any
   // more. This is okay as eviction would not happen from this point.
diff --git a/content/common/features.cc b/content/common/features.cc
index 8637dc0c..086167d 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -10,7 +10,7 @@
 
 BASE_FEATURE(kAvoidUnnecessaryNavigationCancellations,
              "AvoidUnnecessaryNavigationCancellations",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 #if BUILDFLAG(IS_ANDROID)
 BASE_FEATURE(kOnShowWithPageVisibility,
diff --git a/content/common/features.h b/content/common/features.h
index a249357..e0e1c68 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -7,6 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/feature_list.h"
+#include "content/common/content_export.h"
 
 namespace content {
 
@@ -14,9 +15,10 @@
 
 // When enabled, stops canceling navigation when another navigation commits or
 // starts. This supports the same goal as kQueueNavigationsWhileWaitingForCommit
-// but for the non-queueing parts, and is enabled by default.
+// but for the non-queueing parts, and is disabled by default.
 // See https://crbug.com/838348 and https://crbug.com/1220337.
-BASE_DECLARE_FEATURE(kAvoidUnnecessaryNavigationCancellations);
+// Exported for tests.
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kAvoidUnnecessaryNavigationCancellations);
 
 #if BUILDFLAG(IS_ANDROID)
 // Unifies RenderWidgetHostViewAndroid with the other platforms in their usage
diff --git a/content/test/data/session_storage/partition_deprecation_trial.html b/content/test/data/session_storage/partition_deprecation_trial.html
new file mode 100644
index 0000000..3ece83b1
--- /dev/null
+++ b/content/test/data/session_storage/partition_deprecation_trial.html
@@ -0,0 +1,4 @@
+<html>
+<!-- Generate token in mock headers file with the command:
+generate_token.py https://example.com DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning --expire-timestamp=2000000000 -->
+</html>
diff --git a/content/test/data/session_storage/partition_deprecation_trial.html.mock-http-headers b/content/test/data/session_storage/partition_deprecation_trial.html.mock-http-headers
new file mode 100644
index 0000000..d737112
--- /dev/null
+++ b/content/test/data/session_storage/partition_deprecation_trial.html.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Origin-Trial: A6u5/IBR5ZDfNUu7lY+u2TwCFa3gf8e/wW4+ug/4l0ulEeOIl62b7Hj/IVeqVjcZ5NP0jeAIIwL19UdBCLfQJwQAAACNeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJEaXNhYmxlVGhpcmRQYXJ0eVNlc3Npb25TdG9yYWdlUGFydGl0aW9uaW5nQWZ0ZXJHZW5lcmFsUGFydGl0aW9uaW5nIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9
+Content-Type: text/html
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index a9f803e..9cc74ea 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -298,7 +298,7 @@
 crbug.com/1230619 [ android android-pixel-6 angle-disabled no-passthrough ] Pixel_WebGLFloat [ Failure ]
 crbug.com/1230619 [ android android-SM-A135M ] Pixel_WebGLFloat [ Failure ]
 crbug.com/1230619 [ android android-SM-A235M ] Pixel_WebGLFloat [ Failure ]
-crbug.com/1230619 [ linux intel display-server-wayland  ] Pixel_WebGLFloat [ Failure ]
+crbug.com/1230619 [ angle-disabled display-server-wayland intel linux no-passthrough ] Pixel_WebGLFloat [ Failure ]
 
 # HDR rendering with PQ color space appears to be broken on Windows RS2.
 # TODO(sunnyps): Revert this temporary suppression after ensuring pixel tests
@@ -372,15 +372,9 @@
 crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrame [ Failure ]
 crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ]
 crbug.com/1395227 [ amd-0x7340 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ]
-crbug.com/1395227 [ debug-x64 nvidia-0x2184 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ]
-crbug.com/1395227 [ intel-0x9bc5 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ]
 crbug.com/1395227 [ win ] Pixel_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ]
 crbug.com/1395227 [ amd-0x7340 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrame [ Failure ]
-crbug.com/1395227 [ debug-x64 nvidia-0x2184 target-cpu-64 win ] Pixel_WebGPUImportVideoFrame [ Failure ]
-crbug.com/1395227 [ intel-0x9bc5 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrame [ Failure ]
 crbug.com/1395227 [ amd-0x7340 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ]
-crbug.com/1395227 [ debug-x64 nvidia-0x2184 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ]
-crbug.com/1395227 [ intel-0x9bc5 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ]
 crbug.com/1395227 [ linux renderer-skia-vulkan ] Pixel_VulkanSwiftShader_WebGPUImportVideoFrame [ Failure ]
 crbug.com/1395227 [ linux renderer-skia-vulkan ] Pixel_VulkanSwiftShader_WebGPUImportVideoFrameOffscreenCanvas [ Failure ]
 crbug.com/1395227 [ linux renderer-skia-vulkan ] Pixel_VulkanSwiftShader_WebGPUImportVideoFrameUnaccelerated [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 7111f35..b9f18bb 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -92,20 +92,10 @@
 
 
 # TexImage2d tests crashes GPU on Sherlock devices.
-crbug.com/1400465 [ fuchsia fuchsia-board-sherlock ] WebCodecs_TexImage2d_* [ Failure ]
 
 # EncodeDecode tests fail to call flush on the decoder.
-crbug.com/1400465 [ fuchsia fuchsia-board-sherlock ] WebCodecs_EncodeDecode_* [ Failure ]
 
 # Camera tests fail with NotFoundError on Sherlock devices.
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_DrawImage_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_Encode_camera_* [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_GPUExternalTexture_expired_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_GPUExternalTexture_expired_worker_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_TexImage2d_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_copyTo_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_device_destroy_expired_texture_camera [ Failure ]
-crbug.com/1400512 [ fuchsia fuchsia-board-sherlock ] WebCodecs_texture_expired_from_destroyed_device_camera [ Failure ]
 
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index fd7bfe12..ea001da4 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -215,7 +215,6 @@
 
 crbug.com/891953 [ mac ] WebglExtension_OVR_multiview2 [ Failure ]
 crbug.com/891953 [ android ] WebglExtension_OVR_multiview2 [ Failure ]
-crbug.com/891953 [ linux display-server-wayland ] WebglExtension_OVR_multiview2 [ Failure ]
 
 # ========================
 # Conformance expectations
@@ -229,7 +228,6 @@
 # Failing at least on Pixel 4, both validating and passthrough
 crbug.com/1336010 [ android angle-disabled no-passthrough ] conformance2/extensions/oes-draw-buffers-indexed.html [ Failure ]
 # Failing on at least NVIDIA and Intel
-crbug.com/1336010 [ angle-disabled display-server-wayland intel-0x9bc5 linux no-passthrough ] conformance2/extensions/oes-draw-buffers-indexed.html [ Failure ]
 crbug.com/1336010 [ angle-disabled chromeos chromeos-board-amd64-generic no-passthrough ] conformance2/extensions/oes-draw-buffers-indexed.html [ Failure ]
 
 # The validating command decoder suppressions here will not be fixed.
@@ -549,8 +547,6 @@
 # Linux failures   #
 ####################
 
-crbug.com/1060012 [ linux no-passthrough ] conformance/extensions/webgl-compressed-texture-astc.html [ Failure ]
-crbug.com/angleproject/4417 [ linux no-passthrough ] conformance2/rendering/framebuffer-render-to-layer.html [ Failure ]
 
 # Mesa issues
 # Driver tag doesn't work on the passthrough command decoder because the detected driver version is ANGLE's version.
@@ -686,18 +682,10 @@
 # Lacros-like Linux Failures #
 ##############################
 
-crbug.com/1210240 [ linux intel display-server-wayland no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-3d* [ Failure ]
-crbug.com/1210240 [ linux intel display-server-wayland no-passthrough ] conformance2/textures/webgl_canvas/tex-2d-r8ui-red_integer-unsigned_byte.html [ Failure ]
-crbug.com/1210240 [ linux intel display-server-wayland no-passthrough ] conformance2/textures/canvas_sub_rectangle/tex-2d-r8ui-red_integer-unsigned_byte.html [ Failure ]
-crbug.com/1210240 [ linux intel display-server-wayland no-passthrough ] conformance2/textures/webgl_canvas/tex-3d* [ Failure ]
-crbug.com/1215700 [ linux intel display-server-wayland no-passthrough ] deqp/functional/gles3/negativetextureapi.html [ Failure ]
-crbug.com/1218607 [ linux intel display-server-wayland no-passthrough ] conformance2/reading/read-pixels-from-fbo-test.html [ Failure ]
-crbug.com/1231736 [ linux intel display-server-wayland no-passthrough ] deqp/functional/gles3/clipping.html [ Failure ]
 crbug.com/1399117 [ linux intel display-server-wayland no-passthrough ] WebglExtension_WEBGL_provoking_vertex [ Skip ]
 
 
 # Failures on validating command decoder only; won't fix.
-crbug.com/angleproject/5038 [ linux intel display-server-wayland no-passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ]
 
 # Conflicting expectations to test that the
 # "Expectations have no collisions" unittest works.
diff --git a/docs/webui_build_configuration.md b/docs/webui_build_configuration.md
index 7d36a73..b5d8b73 100644
--- a/docs/webui_build_configuration.md
+++ b/docs/webui_build_configuration.md
@@ -240,7 +240,7 @@
               by optimize_webui(). Useful for generating grds.
 deps: Targets generating any files being bundled. Note that this should include
       targets generating shared resources that are expected to be bundled in
-      the UI, e.g. //ui/webui/resources:preprocess.
+      the UI, e.g. //ui/webui/resources:library.
 excludes: Paths of files that are not bundled. Often used for large mojo files
           that would otherwise be in many bundles, and for cr.js which relies
           on global variables.
@@ -264,7 +264,7 @@
     # build_ts.
     deps = [
       ":build_ts",
-      "//ui/webui/resources:preprocess",
+      "//ui/webui/resources:library",
     ]
     excludes = [
       "chrome://resources/js/cr.js",
diff --git a/fuchsia_web/shell/BUILD.gn b/fuchsia_web/shell/BUILD.gn
index e2ba49f..5fb4cd7 100644
--- a/fuchsia_web/shell/BUILD.gn
+++ b/fuchsia_web/shell/BUILD.gn
@@ -56,6 +56,16 @@
   data_deps = [ ":web_engine_shell_exec" ]
 }
 
+# WebInstanceHost needs to serve capabilities to web_instance. Since the
+# primary web_engine_shell component is a test component, it is not able to do
+# this directly. Instead, it launches this here component to start instances via
+# WebInstanceHost.
+fuchsia_component("web_engine_shell_for_web_instance_host_component") {
+  testonly = true
+  manifest = "web_engine_shell_for_web_instance_host.cml"
+  data_deps = [ ":web_engine_shell_exec" ]
+}
+
 fuchsia_component("web_engine_shell_component_v1") {
   testonly = true
   manifest = "web_engine_shell.cmx"
@@ -70,6 +80,7 @@
   deps = [
     ":web_engine_shell_component",
     ":web_engine_shell_component_v1",
+    ":web_engine_shell_for_web_instance_host_component",
   ]
 }
 
@@ -101,8 +112,13 @@
     "//base",
     "//components/fuchsia_component_support:annotations_manager",
     "//fuchsia_web/common",
-    "//fuchsia_web/webinstance_host:webinstance_host_v1",
+    "//fuchsia_web/webinstance_host:webinstance_host",
+    "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component",
+    "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component.decl",
+    "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.web",
     "//third_party/fuchsia-sdk/sdk/pkg/fdio",
+    "//third_party/fuchsia-sdk/sdk/pkg/fidl_cpp",
+    "//third_party/fuchsia-sdk/sdk/pkg/sys_component_cpp_testing",
     "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
     "//third_party/widevine/cdm:buildflags",
     "//url",
diff --git a/fuchsia_web/shell/web_engine_shell.cc b/fuchsia_web/shell/web_engine_shell.cc
index 1356ee9..5b78eb0 100644
--- a/fuchsia_web/shell/web_engine_shell.cc
+++ b/fuchsia_web/shell/web_engine_shell.cc
@@ -2,16 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <fuchsia/component/cpp/fidl.h>
 #include <fuchsia/element/cpp/fidl.h>
 #include <fuchsia/sys/cpp/fidl.h>
 #include <fuchsia/web/cpp/fidl.h>
 #include <lib/fdio/directory.h>
+#include <lib/fidl/cpp/interface_ptr.h>
+#include <lib/sys/component/cpp/testing/realm_builder.h>
 #include <lib/sys/cpp/component_context.h>
-#include <lib/vfs/cpp/pseudo_file.h>
+#include <lib/sys/cpp/service_directory.h>
+
 #include <iostream>
 #include <utility>
 
 #include "base/base_paths.h"
+#include "base/check.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/fuchsia/file_utils.h"
@@ -21,6 +26,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/path_service.h"
+#include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_executor.h"
@@ -30,7 +36,7 @@
 #include "fuchsia_web/common/init_logging.h"
 #include "fuchsia_web/shell/present_frame.h"
 #include "fuchsia_web/shell/remote_debugging_port.h"
-#include "fuchsia_web/webinstance_host/web_instance_host_v1.h"
+#include "fuchsia_web/webinstance_host/web_instance_host.h"
 #include "third_party/widevine/cdm/buildflags.h"
 #include "url/gurl.h"
 
@@ -42,6 +48,7 @@
 constexpr char kEnableProtectedMediaIdentifier[] =
     "enable-protected-media-identifier";
 constexpr char kWebEnginePackageName[] = "web-engine-package-name";
+constexpr char kFromLauncher[] = "from-launcher";
 constexpr char kUseWebInstance[] = "use-web-instance";
 constexpr char kEnableWebInstanceTmp[] = "enable-web-instance-tmp";
 
@@ -111,17 +118,87 @@
   return web_engine_service_dir.Connect<fuchsia::web::ContextProvider>();
 }
 
+// Appends the arguments of `command_line` (ignoring the program name at
+// position zero) to the command line for the realm.
+void AppendCommandLineArguments(component_testing::RealmBuilder& realm_builder,
+                                const base::CommandLine& command_line) {
+  auto decl = realm_builder.GetRealmDecl();
+
+  // Find the "args" list in the program declaration.
+  fuchsia::data::DictionaryEntry* args_entry = nullptr;
+  auto* entries = decl.mutable_program()->mutable_info()->mutable_entries();
+  for (auto& entry : *entries) {
+    if (entry.key == "args") {
+      DCHECK(entry.value->is_str_vec());
+      args_entry = &entry;
+      break;
+    }
+  }
+  if (!args_entry) {
+    // Create a new "args" list and insert it at the proper location in the
+    // program's entries.
+    auto lower_bound = base::ranges::lower_bound(
+        *entries, "args", /*comp=*/{},
+        [](const fuchsia::data::DictionaryEntry& entry) { return entry.key; });
+    auto it = entries->emplace(lower_bound);
+    it->key = "args";
+    it->value = fuchsia::data::DictionaryValue::New();
+    it->value->set_str_vec({});
+    args_entry = &*it;
+  }
+
+  // Append all args following the program name in `command_line` to the
+  // program's args.
+  args_entry->value->str_vec().insert(args_entry->value->str_vec().end(),
+                                      command_line.argv().begin() + 1,
+                                      command_line.argv().end());
+  realm_builder.ReplaceRealmDecl(std::move(decl));
+}
+
+// web_engine_shell needs to provide capabilities to children it launches (via
+// WebInstanceHost, for example). Test components are not able to do this, so
+// use RealmBuilder to relaunch web_engine_shell via
+// `web_engine_shell_for_web_instance_host_component` (which includes
+// `--from-launcher` on its command line) with the contents of this process's
+// command line.
+int RelaunchForWebInstanceHost(const base::CommandLine& command_line) {
+  auto realm_builder = component_testing::RealmBuilder::CreateFromRelativeUrl(
+      "#meta/web_engine_shell_for_web_instance_host.cm");
+  AppendCommandLineArguments(realm_builder, command_line);
+
+  auto realm = realm_builder.Build();
+
+  fuchsia::component::BinderPtr binder_proxy =
+      realm.Connect<fuchsia::component::Binder>();
+
+  // Wait for binder_proxy to be closed.
+  base::RunLoop run_loop;
+  binder_proxy.set_error_handler(
+      [quit_closure = run_loop.QuitClosure()](zx_status_t status) {
+        std::move(quit_closure).Run();
+      });
+  run_loop.Run();
+
+  // Nothing depends on the process exit code of web_engine_shell today, so
+  // simply return success in all cases.
+  return 0;
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
+  base::CommandLine::Init(argc, argv);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  CHECK(InitLoggingFromCommandLine(*command_line));
+
   base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
 
-  // Parse the command line arguments and set up logging.
-  CHECK(base::CommandLine::Init(argc, argv));
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-  CHECK(InitLoggingFromCommandLineDefaultingToStderrForTest(  // IN-TEST
-      command_line));
+  const bool is_run_from_launcher = command_line->HasSwitch(kFromLauncher);
+  const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
+  if (!is_run_from_launcher && !use_context_provider) {
+    return RelaunchForWebInstanceHost(*command_line);
+  }
 
   absl::optional<uint16_t> remote_debugging_port =
       GetRemoteDebuggingPort(*command_line);
@@ -133,7 +210,6 @@
   const bool is_headless = command_line->HasSwitch(kHeadlessSwitch);
   const bool enable_protected_media_identifier_access =
       command_line->HasSwitch(kEnableProtectedMediaIdentifier);
-  const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
   const bool enable_web_instance_tmp =
       command_line->HasSwitch(kEnableWebInstanceTmp);
 
@@ -205,12 +281,9 @@
 
   base::RunLoop run_loop;
 
-  // Create the browser |context|.
-  fuchsia::web::ContextPtr context;
-
-  // Keep alive in run_loop scope.
   fuchsia::web::ContextProviderPtr web_context_provider;
-  std::unique_ptr<WebInstanceHostV1> web_instance_host;
+  std::unique_ptr<WebInstanceHost> web_instance_host;
+  fuchsia::web::ContextPtr context;
   fuchsia::io::DirectoryHandle tmp_directory;
 
   if (use_context_provider) {
@@ -220,7 +293,7 @@
     web_context_provider->Create(std::move(create_context_params),
                                  context.NewRequest());
   } else {
-    web_instance_host = std::make_unique<WebInstanceHostV1>();
+    web_instance_host = std::make_unique<WebInstanceHost>();
     if (enable_web_instance_tmp) {
       const zx_status_t status = fdio_open(
           "/tmp",
@@ -324,6 +397,8 @@
 
   LOG(INFO) << "Launched browser at URL " << url.spec();
 
+  base::ComponentContextForProcess()->outgoing()->ServeFromStartupInfo();
+
   // Run until the process is killed with CTRL-C or the connections to Web
   // Engine interfaces are dropped.
   run_loop.Run();
diff --git a/fuchsia_web/shell/web_engine_shell.cml b/fuchsia_web/shell/web_engine_shell.cml
index 057f6d1..e89e965 100644
--- a/fuchsia_web/shell/web_engine_shell.cml
+++ b/fuchsia_web/shell/web_engine_shell.cml
@@ -10,6 +10,7 @@
     // to function correctly.
     "//build/config/fuchsia/test/chromium_test_facet.shard.test-cml",
     "//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml",
+    "sys/component/realm_builder_absolute.shard.cml",
     "syslog/client.shard.cml",
   ],
   program: {
@@ -18,7 +19,6 @@
   use: [
     {
       protocol: [
-        "fuchsia.element.GraphicalPresenter",
         "fuchsia.feedback.ComponentDataRegister",
         "fuchsia.feedback.CrashReportingProductRegister",
         "fuchsia.sys.Environment",
@@ -33,10 +33,14 @@
       protocol: "fuchsia.web.ContextProvider",
       availability: "optional",
     },
+
+    // Used to hold the cdm_data directory passed to web_instance.
     {
       storage: "data",
       path: "/data",
     },
+
+    // Needed when launched with --enable-web-instance-tmp.
     {
       storage: "tmp",
       path: "/tmp",
@@ -80,6 +84,7 @@
     {
       protocol: [
         "fuchsia.accessibility.semantics.SemanticsManager",
+        "fuchsia.element.GraphicalPresenter",
         "fuchsia.tracing.provider.Registry",
         "fuchsia.ui.composition.Allocator",
         "fuchsia.ui.composition.Flatland",
@@ -94,8 +99,92 @@
       availability: "optional",
     },
   ],
+  offer: [
+    {
+      storage: [
+        "data",
+        "tmp",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+    },
+    {
+      directory: [
+        "config-data",
+        "root-ssl-certificates",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+    },
+
+    // Offers for web_instance.cm.
+    {
+      protocol: [
+        "fuchsia.buildinfo.Provider",
+        "fuchsia.device.NameProvider",
+        "fuchsia.feedback.ComponentDataRegister",
+        "fuchsia.feedback.CrashReportingProductRegister",
+        "fuchsia.fonts.Provider",
+        "fuchsia.hwinfo.Product",
+        "fuchsia.input.virtualkeyboard.ControllerCreator",
+        "fuchsia.intl.PropertyProvider",
+        "fuchsia.kernel.VmexResource",
+        "fuchsia.media.Audio",
+        "fuchsia.media.AudioDeviceEnumerator",
+        "fuchsia.media.ProfileProvider",
+        "fuchsia.media.SessionAudioConsumerFactory",
+        "fuchsia.mediacodec.CodecFactory",
+        "fuchsia.memorypressure.Provider",
+        "fuchsia.net.interfaces.State",
+        "fuchsia.net.name.Lookup",
+        "fuchsia.posix.socket.Provider",
+        "fuchsia.process.Launcher",
+        "fuchsia.sysmem.Allocator",
+        "fuchsia.ui.input3.Keyboard",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+    },
+
+    // Used conditionally based on the value of `enable_widevine` at build time.
+    // TODO(crbug.com/1379411): Use a shard to conditionally use based on
+    // build-time config.
+    {
+      protocol: "fuchsia.media.drm.Widevine",
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+
+    // Used conditionally based on the absence of `--headless` on the command
+    // line at runtime.
+    {
+      protocol: [
+        "fuchsia.accessibility.semantics.SemanticsManager",
+        "fuchsia.element.GraphicalPresenter",
+        "fuchsia.tracing.provider.Registry",
+        "fuchsia.ui.composition.Allocator",
+        "fuchsia.ui.composition.Flatland",
+        "fuchsia.ui.policy.Presenter",
+        "fuchsia.ui.scenic.Scenic",
+        "fuchsia.vulkan.loader.Loader",
+      ],
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+
+    // Optional capabilities, dependent on availability of tracing services.
+    {
+      protocol: "fuchsia.tracing.perfetto.ProducerConnector",
+      from: "parent",
+      to: "#realm_builder",
+      availability: "optional",
+    },
+  ],
   facets: {
     "fuchsia.test.deprecated-allowed-packages": [
+      "test_manager",
       "web_engine",
       "web_engine_with_webui",
     ],
diff --git a/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml b/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
new file mode 100644
index 0000000..5f377f25
--- /dev/null
+++ b/fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+  include: [
+    "//fuchsia_web/webinstance_host/web_instance_host.shard.cml",
+    "syslog/client.shard.cml",
+    "vulkan/client.shard.cml",
+  ],
+  program: {
+    runner: "elf",
+    binary: "web_engine_shell_exec",
+    args: [
+      // Inform web_engine_shell that it is running as the sub-process in which
+      // WebInstanceHost may be used. In this scenario, the main test component
+      // is running only as a launcher of this child.
+      "--from-launcher",
+    ],
+
+    // Required to allow JIT in child processes such as renderers.
+    // Known as 'deprecated-ambient-replace-as-executable' in CFv1.
+    job_policy_ambient_mark_vmo_exec: "true",
+  },
+  use: [
+    // Required if not run with --headless.
+    {
+      protocol: [
+        "fuchsia.element.GraphicalPresenter",
+        "fuchsia.ui.policy.Presenter",
+      ],
+      availability: "optional",
+    },
+
+    // Used to hold the cdm_data directory passed to web_instance.
+    {
+      storage: "data",
+      path: "/data",
+    },
+
+    // Needed when launched with --enable-web-instance-tmp.
+    {
+      storage: "tmp",
+      path: "/tmp",
+    },
+  ],
+  facets: {
+    "fuchsia.test.deprecated-allowed-packages": [
+      "web_engine",
+      "web_engine_with_webui",
+    ],
+  },
+}
diff --git a/fuchsia_web/webengine/BUILD.gn b/fuchsia_web/webengine/BUILD.gn
index b087d73..4775e29 100644
--- a/fuchsia_web/webengine/BUILD.gn
+++ b/fuchsia_web/webengine/BUILD.gn
@@ -512,6 +512,7 @@
   # TODO(fxbug.dev/100944): Add appropriate visibility when fixed.
   deps = [
     ":context_provider_v1_with_webui_component",
+    ":web_instance_component",
     ":web_instance_component_cfv1",
     ":webui_resources",
   ]
diff --git a/fuchsia_web/webengine/web_instance.cml b/fuchsia_web/webengine/web_instance.cml
index 4d884f4..8085c72 100644
--- a/fuchsia_web/webengine/web_instance.cml
+++ b/fuchsia_web/webengine/web_instance.cml
@@ -75,6 +75,13 @@
       path: "/config/command-line",
       availability: "optional",
     },
+    // Temporary directory specified by WebInstanceHost.set_tmp_dir.
+    {
+      directory: "tmp",
+      path: "/tmp",
+      rights: [ "rw*" ],
+      availability: "optional",
+    },
     {
       // Required capabilities for all configurations.
       protocol: [
@@ -153,10 +160,5 @@
       ],
       availability: "optional",
     },
-    {
-      storage: "cache",
-      path: "/cache",
-      availability: "optional",
-    },
   ]
 }
diff --git a/fuchsia_web/webinstance_host/web_instance_host.cc b/fuchsia_web/webinstance_host/web_instance_host.cc
index 75b75c7..0e8f39a4 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.cc
+++ b/fuchsia_web/webinstance_host/web_instance_host.cc
@@ -43,6 +43,10 @@
 constexpr char kWebInstanceComponentUrl[] =
     "fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cm";
 
+// Test-only URL for web hosting Component instances with WebUI resources.
+const char kWebInstanceWithWebUiComponentUrl[] =
+    "fuchsia-pkg://fuchsia.com/web_engine_with_webui#meta/web_instance.cm";
+
 // The name of the component collection hosting the instances.
 constexpr char kCollectionName[] = "web_instances";
 
@@ -58,7 +62,8 @@
   return base::StrCat({kCollectionName, "_", id.AsLowercaseString()});
 }
 
-void DestroyChild(fuchsia::component::Realm& realm, const std::string& name) {
+void DestroyInstance(fuchsia::component::Realm& realm,
+                     const std::string& name) {
   realm.DestroyChild(
       fcdecl::ChildRef{.name = name, .collection = kCollectionName},
       [](::fuchsia::component::Realm_DestroyChild_Result destroy_result) {
@@ -67,8 +72,8 @@
       });
 }
 
-void DestroyChildDirectory(vfs::PseudoDir* instances_dir,
-                           const std::string& name) {
+void DestroyInstanceDirectory(vfs::PseudoDir* instances_dir,
+                              const std::string& name) {
   zx_status_t status = instances_dir->RemoveEntry(name);
   ZX_DCHECK(status == ZX_OK, status);
 }
@@ -191,7 +196,7 @@
 
 InstanceBuilder::~InstanceBuilder() {
   if (instance_dir_) {
-    DestroyChildDirectory(GetWebInstancesCollectionDir(), name_);
+    DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name_);
   }
 }
 
@@ -263,7 +268,14 @@
 
   fcdecl::Child child_decl;
   child_decl.set_name(name_);
-  child_decl.set_url(kWebInstanceComponentUrl);
+  // TODO(crbug.com/1010222): Make kWebInstanceComponentUrl a relative
+  // component URL and remove this workaround.
+  // TODO(crbug.com/1395054): Better yet, replace the with_webui component with
+  // direct routing of the resources from web_engine_shell.
+  child_decl.set_url(
+      base::CommandLine::ForCurrentProcess()->HasSwitch("with-webui")
+          ? kWebInstanceWithWebUiComponentUrl
+          : kWebInstanceComponentUrl);
   child_decl.set_startup(fcdecl::StartupMode::LAZY);
 
   ::fuchsia::component::CreateChildArgs create_child_args;
@@ -412,7 +424,7 @@
 
 WebInstanceHost::~WebInstanceHost() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(instances_.empty());
+  Uninitialize();
 }
 
 zx_status_t WebInstanceHost::CreateInstanceForContextWithCopiedArgs(
@@ -494,28 +506,29 @@
 
 void WebInstanceHost::Uninitialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(instances_.empty());
+
+  // Destroy all child instances and each one's outgoing directory subtree.
+  auto* const instances_dir = GetWebInstancesCollectionDir();
+  for (auto& [id, binder_ptr] : instances_) {
+    const std::string name(InstanceNameFromId(id));
+    if (realm_) {
+      DestroyInstance(*realm_, name);
+    }
+    DestroyInstanceDirectory(instances_dir, name);
+    binder_ptr.Unbind();
+  }
+  instances_.clear();
 
   realm_.Unbind();
 
   // Note: the entry in the outgoing directory for the top-level instances dir
-  // is leaked in case multiple hosts are active in the same process.
+  // is leaked in support of having multiple hosts active in a single process.
 }
 
 void WebInstanceHost::OnRealmError(zx_status_t status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ZX_LOG(ERROR, status) << "RealmBuilder channel error";
-
-  // Disconnect from all children and remove their directories.
-  auto* const instances_dir = GetWebInstancesCollectionDir();
-  for (auto& [id, binder_ptr] : instances_) {
-    DestroyChildDirectory(instances_dir, InstanceNameFromId(id));
-    binder_ptr.Unbind();
-  }
-  instances_.clear();
-
-  // Go back to the initial state.
   Uninitialize();
 }
 
@@ -525,10 +538,10 @@
 
   // Destroy the child instance.
   const std::string name(InstanceNameFromId(id));
-  DestroyChild(*realm_, name);
+  DestroyInstance(*realm_, name);
 
   // Drop the directory subtree for the child instance.
-  DestroyChildDirectory(GetWebInstancesCollectionDir(), name);
+  DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name);
 
   // Drop the hold on the instance's Binder. Note: destroying the InterfacePtr
   // here also deletes the lambda into which `id` was bound, so `id` must not
diff --git a/fuchsia_web/webinstance_host/web_instance_host.h b/fuchsia_web/webinstance_host/web_instance_host.h
index 442aa95..7a07a32 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.h
+++ b/fuchsia_web/webinstance_host/web_instance_host.h
@@ -82,8 +82,8 @@
   // Connects to the fuchsia.component/Realm protocol.
   void Initialize();
 
-  // Unbinds from the fuchsia.component/Realm protocol. May only be called once
-  // all web_instances have terminated.
+  // Destroys all child instances and associated resources and unbinds from the
+  // fuchsia.component/Realm protocol.
   void Uninitialize();
 
   // Error handler for the channel to RealmBuilder.
diff --git a/fuchsia_web/webinstance_host/web_instance_host.shard.cml b/fuchsia_web/webinstance_host/web_instance_host.shard.cml
index 888bd5a..8235922 100644
--- a/fuchsia_web/webinstance_host/web_instance_host.shard.cml
+++ b/fuchsia_web/webinstance_host/web_instance_host.shard.cml
@@ -35,12 +35,10 @@
   ],
   offer: [
     {
-      directory: "config-data",
-      from: "parent",
-      to: "#web_instances",
-    },
-    {
-      directory: "root-ssl-certificates",
+      directory: [
+        "config-data",
+        "root-ssl-certificates",
+      ],
       from: "parent",
       to: "#web_instances",
     },
@@ -56,7 +54,6 @@
         "fuchsia.memorypressure.Provider",
         "fuchsia.process.Launcher",
         "fuchsia.sysmem.Allocator",
-        "fuchsia.tracing.provider.Registry",
       ],
       from: "parent",
       to: "#web_instances",
@@ -74,16 +71,13 @@
 
         // Optionally used by the tracing service.
         "fuchsia.tracing.perfetto.ProducerConnector",
+
+        // Required by Vulkan when not run with --headless.
+        "fuchsia.tracing.provider.Registry",
       ],
       from: "parent",
       to: "#web_instances",
       availability: "optional",
-      source_availability: "unknown",
-    },
-    {
-      storage: "cache",
-      from: "parent",
-      to: "#web_instances",
     },
   ],
 }
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index bc23cae..22b28ef 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-237b445d0adc0052ab34d71a5421ed9d89b70160
\ No newline at end of file
+174d86048824661e92d9e745b1aef9417739b2a7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 15dc960..f9519cc 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-8c9146b7f0c4cccb964f68c36a85c540f11fea79
\ No newline at end of file
+56172c51ff6f319273c64875f6a2536721557366
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index a1fd9b6..246b6d7 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-90657c20d7a019ae88c855da920b27924eba5904
\ No newline at end of file
+3e09e4888c2a4d309c839f91b1169648f80a1f35
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 69eadde..c4a9840 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-88db85b77da057c8c89ef3a8dddddeac84ce75d4
\ No newline at end of file
+6845643aaaa2ff8c92fdb2226f31a648ec6b2829
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 0993656..8edb0177 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-eaefaaa812ef6fb5318cccac1310bcd7661805e2
\ No newline at end of file
+141f83963e1840faf10bd17b82d4a25f03589324
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 3fcc8f2..03ae340 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-2843a4d30103292c4a11117d4e738cc3ae98949f
\ No newline at end of file
+88b102567c63d173f17d3ffbc2f1823b64a59376
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index df2e4661..975b5365 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3bb441c5ffa62ffcd55f3853169e1d847e26050d
\ No newline at end of file
+592c6709f61df3f2acfdb7b552ceb4709bb5dfca
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 9a0d4fa2..974c78e9 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-e8f14b6b44d6942092495ca4fed57b46ef875ec4
\ No newline at end of file
+a2c3c5544b8d43fe6c6c0f5a2235956d4f9ea7fb
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 35f7e1d..706b8ce 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-34e69e6da2bcec8e4211e1e0888204989627dc2b
\ No newline at end of file
+930bbd5fca444e728a1585cad012471c7cfd1bbf
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 0812561a..0f29a78 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b76fc121780ee661a1e0f75c0d0c61cc7d2349bf
\ No newline at end of file
+d13188c1bb3277635198582a90d66e9cfd848c3e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 1d15f89..c9a48e9 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-59e0d70d16e76a87861572c0ce4e031323c3669c
\ No newline at end of file
+95d3397d713c7ce1c9f107129a86f59d55b65aa0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 7914a70..6e5a230 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-48aa2fe2de5fe1ecaa6d6edf127076a29e2a093b
\ No newline at end of file
+995e29235f28de26928ff1a6910d12fc778df57a
\ No newline at end of file
diff --git a/media/gpu/windows/d3d11_texture_wrapper.cc b/media/gpu/windows/d3d11_texture_wrapper.cc
index 2088bcd..c6ab7a34 100644
--- a/media/gpu/windows/d3d11_texture_wrapper.cc
+++ b/media/gpu/windows/d3d11_texture_wrapper.cc
@@ -269,9 +269,12 @@
 }
 
 DefaultTexture2DWrapper::GpuResources::~GpuResources() {
-  // Destroy shared images with a current context.
-  if (!helper_ || !helper_->MakeContextCurrent())
-    return;
+  // Destroy shared images with a current context, otherwise mark context lost.
+  if (!helper_ || !helper_->MakeContextCurrent()) {
+    for (auto& shared_image_rep : shared_images_) {
+      shared_image_rep->OnContextLost();
+    }
+  }
   shared_images_.clear();
 }
 
diff --git a/media/muxers/webm_muxer.cc b/media/muxers/webm_muxer.cc
index 28fdea0..763e4f4 100644
--- a/media/muxers/webm_muxer.cc
+++ b/media/muxers/webm_muxer.cc
@@ -14,7 +14,6 @@
 #include "base/containers/circular_deque.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_math.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
@@ -244,32 +243,6 @@
 WebmMuxer::~WebmMuxer() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   Flush();
-
-  if (has_audio_ && !has_video_) {
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.AudioOnly.Muxer",
-        did_adjust_muxer_timestamp_);
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.AudioOnly.Audio",
-        did_adjust_audio_timestamp_);
-  } else if (!has_audio_ && has_video_) {
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.VideoOnly.Muxer",
-        did_adjust_muxer_timestamp_);
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.VideoOnly.Video",
-        did_adjust_video_timestamp_);
-  } else {
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.AudioVideo.Muxer",
-        did_adjust_muxer_timestamp_);
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.AudioVideo.Audio",
-        did_adjust_audio_timestamp_);
-    base::UmaHistogramBoolean(
-        "Media.WebmMuxer.DidAdjustTimestamp.AudioVideo.Video",
-        did_adjust_video_timestamp_);
-  }
 }
 
 void WebmMuxer::SetMaximumDurationToForceDataOutput(base::TimeDelta interval) {
@@ -304,7 +277,11 @@
     video_codec_ = params.codec;
     AddVideoTrack(params.visible_rect_size, GetFrameRate(params),
                   params.color_space);
-
+    if (first_frame_timestamp_video_.is_null()) {
+      // Compensate for time in pause spent before the first frame.
+      first_frame_timestamp_video_ = timestamp - total_time_in_pause_;
+      last_frame_timestamp_video_ = first_frame_timestamp_video_;
+    }
     // Add codec private for AV1.
     if (params.codec == VideoCodec::kAV1 &&
         !segment_.GetTrackByNumber(video_track_index_)
@@ -318,17 +295,11 @@
     if (is_key_frame)  // Upon Key frame reception, empty the encoded queue.
       video_frames_.clear();
   }
-
-  // Compensate for time in pause spent before the first frame.
-  auto timestamp_minus_paused = timestamp - total_time_in_pause_;
-  if (!video_timestamp_source_.has_value()) {
-    video_timestamp_source_.emplace(timestamp_minus_paused,
-                                    did_adjust_video_timestamp_);
-  }
+  const base::TimeTicks recorded_timestamp =
+      UpdateLastTimestampMonotonically(timestamp, &last_frame_timestamp_video_);
   video_frames_.push_back(EncodedFrame{
       std::move(encoded_data), std::move(encoded_alpha),
-      video_timestamp_source_->UpdateAndGetNext(timestamp_minus_paused),
-      is_key_frame});
+      recorded_timestamp - first_frame_timestamp_video_, is_key_frame});
   return PartiallyFlushQueues();
 }
 
@@ -342,18 +313,19 @@
   MaybeForceNewCluster();
   if (!audio_track_index_) {
     AddAudioTrack(params);
+    if (first_frame_timestamp_audio_.is_null()) {
+      // Compensate for time in pause spent before the first frame.
+      first_frame_timestamp_audio_ = timestamp - total_time_in_pause_;
+      last_frame_timestamp_audio_ = first_frame_timestamp_audio_;
+    }
   }
 
-  // Compensate for time in pause spent before the first frame.
-  auto timestamp_minus_paused = timestamp - total_time_in_pause_;
-  if (!audio_timestamp_source_.has_value()) {
-    audio_timestamp_source_.emplace(timestamp_minus_paused,
-                                    did_adjust_audio_timestamp_);
-  }
-  audio_frames_.push_back(EncodedFrame{
-      encoded_data, std::string(),
-      audio_timestamp_source_->UpdateAndGetNext(timestamp_minus_paused),
-      /*is_keyframe=*/true});
+  const base::TimeTicks recorded_timestamp =
+      UpdateLastTimestampMonotonically(timestamp, &last_frame_timestamp_audio_);
+  audio_frames_.push_back(
+      EncodedFrame{encoded_data, std::string(),
+                   recorded_timestamp - first_frame_timestamp_audio_,
+                   /*is_keyframe=*/true});
   return PartiallyFlushQueues();
 }
 
@@ -372,7 +344,7 @@
   DVLOG(1) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!elapsed_time_in_pause_)
-    elapsed_time_in_pause_.emplace();
+    elapsed_time_in_pause_ = std::make_unique<base::ElapsedTimer>();
 }
 
 void WebmMuxer::Resume() {
@@ -515,27 +487,20 @@
 
 bool WebmMuxer::FlushNextFrame() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::TimeTicks min_timestamp = base::TimeTicks::Max();
+  base::TimeDelta min_timestamp = base::TimeDelta::Max();
   base::circular_deque<EncodedFrame>* queue = &video_frames_;
   uint8_t track_index = video_track_index_;
   if (!video_frames_.empty())
-    min_timestamp = video_frames_.front().timestamp_minus_paused_;
+    min_timestamp = video_frames_.front().relative_timestamp;
 
   if (!audio_frames_.empty() &&
-      audio_frames_.front().timestamp_minus_paused_ < min_timestamp) {
+      audio_frames_.front().relative_timestamp < min_timestamp) {
     queue = &audio_frames_;
     track_index = audio_track_index_;
   }
 
   EncodedFrame frame = std::move(queue->front());
   queue->pop_front();
-
-  // Update the first timestamp if necessary so we can write relative timestamps
-  // into the muxer.
-  if (first_timestamp_.is_null()) {
-    first_timestamp_ = frame.timestamp_minus_paused_;
-  }
-
   // The logic tracking live-and-enabled that temporarily relaxes the strict
   // timestamp sorting allows for draining a track's queue completely in the
   // presence of the other track being muted. When the muted track becomes
@@ -543,15 +508,10 @@
   // data before live-and-enabled transitions to true. This can lead to us
   // emitting non-monotonic timestamps to the muxer, which results in an error
   // return. Fix this by enforcing monotonicity by rewriting timestamps.
-  // TODO(crbug.com/1145203): If this causes audio glitches in the field,
-  // reconsider this solution. For example, consider auto-marking a track
-  // live-and-enabled when media appears and remove this catch-all.
-  base::TimeDelta relative_timestamp =
-      frame.timestamp_minus_paused_ - first_timestamp_;
+  base::TimeDelta relative_timestamp = frame.relative_timestamp;
   DLOG_IF(WARNING, relative_timestamp < last_timestamp_written_)
       << "Enforced a monotonically increasing timestamp. Last written "
       << last_timestamp_written_ << " new " << relative_timestamp;
-  did_adjust_muxer_timestamp_ |= (relative_timestamp < last_timestamp_written_);
   relative_timestamp = std::max(relative_timestamp, last_timestamp_written_);
   last_timestamp_written_ = relative_timestamp;
   auto recorded_timestamp = relative_timestamp.InMicroseconds() *
@@ -581,6 +541,20 @@
   return result;
 }
 
+base::TimeTicks WebmMuxer::UpdateLastTimestampMonotonically(
+    base::TimeTicks timestamp,
+    base::TimeTicks* last_timestamp) {
+  base::TimeTicks compensated_timestamp = timestamp - total_time_in_pause_;
+  // In theory, time increases monotonically. In practice, it does not.
+  // See http://crbug/618407.
+  DLOG_IF(WARNING, compensated_timestamp < *last_timestamp)
+      << "Encountered a non-monotonically increasing timestamp. Was: "
+      << *last_timestamp << ", compensated: " << compensated_timestamp
+      << ", uncompensated: " << timestamp;
+  *last_timestamp = std::max(*last_timestamp, compensated_timestamp);
+  return *last_timestamp;
+}
+
 void WebmMuxer::MaybeForceNewCluster() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -598,23 +572,4 @@
   }
 }
 
-WebmMuxer::MonotonicTimestampSequence::MonotonicTimestampSequence(
-    base::TimeTicks first_timestamp,
-    bool& did_adjust_timestamp)
-    : last_timestamp_(first_timestamp),
-      did_adjust_timestamp_(did_adjust_timestamp) {}
-
-base::TimeTicks WebmMuxer::MonotonicTimestampSequence::UpdateAndGetNext(
-    base::TimeTicks timestamp) {
-  DVLOG(3) << __func__ << " ts " << timestamp << " last " << last_timestamp_;
-  // In theory, time increases monotonically. In practice, it does not.
-  // See http://crbug/618407.
-  DLOG_IF(WARNING, timestamp < last_timestamp_)
-      << "Encountered a non-monotonically increasing timestamp. Was: "
-      << last_timestamp_ << ", timestamp: " << timestamp;
-  did_adjust_timestamp_ |= (timestamp < last_timestamp_);
-  last_timestamp_ = std::max(last_timestamp_, timestamp);
-  return last_timestamp_;
-}
-
 }  // namespace media
diff --git a/media/muxers/webm_muxer.h b/media/muxers/webm_muxer.h
index a8c62be..0013962 100644
--- a/media/muxers/webm_muxer.h
+++ b/media/muxers/webm_muxer.h
@@ -14,7 +14,6 @@
 #include "base/numerics/safe_math.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
-#include "base/timer/elapsed_timer.h"
 #include "media/base/audio_codecs.h"
 #include "media/base/media_export.h"
 #include "media/base/video_codecs.h"
@@ -131,33 +130,6 @@
  private:
   friend class WebmMuxerTest;
 
-  struct EncodedFrame {
-    // Audio or Video frame data.
-    std::string data;
-    // Alpha frame data if Video, empty if Audio.
-    std::string alpha_data;
-    // Timestamp of frame minus the total time in pause at the time.
-    base::TimeTicks timestamp_minus_paused_;
-    // Always true for Audio.
-    bool is_keyframe;
-  };
-
-  // Class for ensuring a monotonically increasing timestamp sequence, despite
-  // incoming non-monotonically increasing timestamps.
-  class MonotonicTimestampSequence {
-   public:
-    MonotonicTimestampSequence(base::TimeTicks first_timestamp,
-                               bool& did_adjust_timestamp);
-
-    // Returns the next timestamp. This may be adjusted to enforce a
-    // monotonically increasing history.
-    base::TimeTicks UpdateAndGetNext(base::TimeTicks timestamp);
-
-   private:
-    base::TimeTicks last_timestamp_;
-    bool& did_adjust_timestamp_;
-  };
-
   // Methods for creating and adding video and audio tracks, called upon
   // receiving the first frame of a given Track.
   // AddVideoTrack adds |frame_size| and |frame_rate| to the Segment
@@ -185,6 +157,13 @@
   //
   // Note: it's assumed that at least one video or audio frame is queued.
   bool FlushNextFrame();
+  // Calculates a monotonically increasing timestamp from an input |timestamp|
+  // and a pointer to a previously stored |last_timestamp| by taking the maximum
+  // of |timestamp| and *|last_timestamp|. Updates *|last_timestamp| if
+  // |timestamp| is greater.
+  base::TimeTicks UpdateLastTimestampMonotonically(
+      base::TimeTicks timestamp,
+      base::TimeTicks* last_timestamp);
   // Forces data output from |segment_| on the next frame if recording video,
   // and |min_data_output_interval_| was configured and has passed since the
   // last received video frame.
@@ -200,15 +179,14 @@
   uint8_t video_track_index_;
   uint8_t audio_track_index_;
 
-  absl::optional<MonotonicTimestampSequence> video_timestamp_source_;
-  absl::optional<MonotonicTimestampSequence> audio_timestamp_source_;
-
-  // The timestamp of the lowest timestamp audio or video sample, compensated
-  // for the total time in pause at the time.
-  base::TimeTicks first_timestamp_;
+  // Origin of times for frame timestamps.
+  base::TimeTicks first_frame_timestamp_video_;
+  base::TimeTicks last_frame_timestamp_video_;
+  base::TimeTicks first_frame_timestamp_audio_;
+  base::TimeTicks last_frame_timestamp_audio_;
 
   // Variables to measure and accumulate, respectively, the time in pause state.
-  absl::optional<base::ElapsedTimer> elapsed_time_in_pause_;
+  std::unique_ptr<base::ElapsedTimer> elapsed_time_in_pause_;
   base::TimeDelta total_time_in_pause_;
 
   // TODO(ajose): Change these when support is added for multiple tracks.
@@ -233,6 +211,14 @@
   // Flag to force the next call to a |segment_| method to return false.
   bool force_one_libwebm_error_;
 
+  struct EncodedFrame {
+    std::string data;
+    std::string alpha_data;
+    base::TimeDelta
+        relative_timestamp;  // relative to first_frame_timestamp_xxx_
+    bool is_keyframe;
+  };
+
   // The following two queues hold frames to ensure that monotonically
   // increasing timestamps are stored in the resulting webm file without
   // modifying the timestamps.
@@ -241,11 +227,6 @@
   // frame appears.
   base::circular_deque<EncodedFrame> video_frames_;
 
-  // Source data for UMA histograms.
-  bool did_adjust_muxer_timestamp_ = false;
-  bool did_adjust_video_timestamp_ = false;
-  bool did_adjust_audio_timestamp_ = false;
-
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
diff --git a/media/muxers/webm_muxer_unittest.cc b/media/muxers/webm_muxer_unittest.cc
index db4ebc7..e603797 100644
--- a/media/muxers/webm_muxer_unittest.cc
+++ b/media/muxers/webm_muxer_unittest.cc
@@ -404,12 +404,12 @@
   const std::string encoded_audio("thisisanencodedaudiopacket");
 
   // Timestamped frames should come as:
-  // [video origin, video origin + X, video origin + X + Y, audio origin]
+  // [video origin, audio origin, video origin + X, video origin + X + Y]
   Sequence s;
   EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
-  EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
-  EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
   EXPECT_CALL(*this, WriteCallback(Eq(encoded_audio))).Times(1).InSequence(s);
+  EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
+  EXPECT_CALL(*this, WriteCallback(Eq(encoded_video))).Times(1).InSequence(s);
 
   // We'll also get lots of other header-related stuff.
   EXPECT_CALL(*this, WriteCallback(
@@ -590,9 +590,10 @@
   AddAudioAtOffsetWithDuration(234 + 321, 10);
   AddVideoAtOffset(234 + 315, /*is_key_frame=*/false);
   EXPECT_TRUE(Parse());
-  EXPECT_THAT(buffer_timestamps_ms_,
-              UnorderedElementsAre(Pair(1, ElementsAre(0, /*321 - 300=*/21)),
-                                   Pair(2, ElementsAre(1, /*315 - 300=*/15))));
+  EXPECT_THAT(
+      buffer_timestamps_ms_,
+      UnorderedElementsAre(Pair(1, ElementsAre(0, /*321 - 300=*/21)),
+                           Pair(2, ElementsAre(0, /*315 - 300 - 1=*/14))));
 }
 
 TEST_F(WebmMuxerTestUnparametrized,
@@ -607,7 +608,7 @@
   EXPECT_TRUE(Parse());
   EXPECT_THAT(buffer_timestamps_ms_,
               UnorderedElementsAre(Pair(1, ElementsAre(0, 10)),
-                                   Pair(2, ElementsAre(15, 20))));
+                                   Pair(2, ElementsAre(0, 5))));
 }
 
 TEST_F(WebmMuxerTestUnparametrized, HoldsDataUntilDurationExpiry) {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index db0bb5d9..bdf597f 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5839,9 +5839,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -5853,8 +5853,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -6010,9 +6010,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6024,8 +6024,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -6162,9 +6162,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -6176,8 +6176,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c16cd8a3..a48f6c4d0 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -80772,9 +80772,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -80786,8 +80786,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -80913,9 +80913,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -80927,8 +80927,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -81040,9 +81040,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -81054,8 +81054,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -82388,9 +82388,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82401,8 +82401,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -82559,9 +82559,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82572,8 +82572,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -82711,9 +82711,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -82724,8 +82724,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -84249,9 +84249,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84262,8 +84262,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -84420,9 +84420,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84433,8 +84433,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -84572,9 +84572,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -84585,8 +84585,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -85358,9 +85358,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -85371,8 +85371,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 4417dac..f1641ca 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18532,12 +18532,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18549,8 +18549,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -18723,12 +18723,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18740,8 +18740,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
@@ -18890,12 +18890,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 111.0.5550.0",
+        "description": "Run with ash-chrome version 111.0.5552.0",
         "isolate_profile_data": true,
         "merge": {
           "args": [],
@@ -18907,8 +18907,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v111.0.5550.0",
-              "revision": "version:111.0.5550.0"
+              "location": "lacros_version_skew_tests_v111.0.5552.0",
+              "revision": "version:111.0.5552.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 281fd70..45debe6 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1324,7 +1324,7 @@
       {
         "args": [],
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R108-15183.78.0",
+        "cros_img": "strongbad-release/R109-15236.66.0",
         "name": "lacros_all_tast_tests STRONGBAD_RELEASE_STABLE",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
@@ -1413,7 +1413,7 @@
       {
         "args": [],
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R108-15183.78.0",
+        "cros_img": "strongbad-release/R109-15236.66.0",
         "name": "ozone_unittests STRONGBAD_RELEASE_STABLE",
         "swarming": {},
         "test": "ozone_unittests",
@@ -1501,7 +1501,7 @@
       {
         "args": [],
         "cros_board": "strongbad",
-        "cros_img": "strongbad-release/R108-15183.78.0",
+        "cros_img": "strongbad-release/R109-15236.66.0",
         "name": "viz_unittests STRONGBAD_RELEASE_STABLE",
         "swarming": {},
         "test": "viz_unittests",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 384dc68..f9da711 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5550.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5552.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 111.0.5550.0',
+    'description': 'Run with ash-chrome version 111.0.5552.0',
     'identifier': 'Lacros version skew testing ash canary',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v111.0.5550.0',
-          'revision': 'version:111.0.5550.0',
+          'location': 'lacros_version_skew_tests_v111.0.5552.0',
+          'revision': 'version:111.0.5552.0',
         },
       ],
     },
@@ -726,8 +726,8 @@
   'CROS_STRONGBAD_RELEASE_STABLE': {
     'skylab': {
       'cros_board': 'strongbad',
-      'cros_chrome_version': '108.0.5359.172',
-      'cros_img': 'strongbad-release/R108-15183.78.0',
+      'cros_chrome_version': '109.0.5414.94',
+      'cros_img': 'strongbad-release/R109-15236.66.0',
     },
     'enabled': True,
     'identifier': 'STRONGBAD_RELEASE_STABLE',
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
index a640b7d..ef4e16c9 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -554,7 +554,7 @@
       if (layers[i].type == HighlightLayerType::kOriginating) {
         layers_.push_back(LayerPaintState{
             layers[i],
-            WrapRefCounted(&originating_style_),
+            &originating_style_,
             originating_text_style_,
         });
       } else {
@@ -562,17 +562,33 @@
             layers[i],
             HighlightPaintingUtils::HighlightPseudoStyle(
                 node_, originating_style_, layers[i].PseudoId(),
-                layers[i].PseudoArgument()),
+                layers[i].PseudoArgument())
+                .get(),
             HighlightPaintingUtils::HighlightPaintingStyle(
                 document, originating_style_, node_, layers[i].PseudoId(),
                 layers_[i - 1].text_style, paint_info_,
                 layers[i].PseudoArgument()),
         });
       }
-      if (layers_[i].style) {
-        decoration_painter_.UpdateDecorationInfo(layers_[i].decoration_info,
-                                                 *layers_[i].style,
-                                                 layers_[i].text_style);
+      if (layers_[i].decorations_in_effect != TextDecorationLine::kNone) {
+        // Cache the TextDecorationInfo for up to two highlight layers that have
+        // line decorations, e.g. originating content might have a line-through
+        // and underline, and spelling error might have a spelling decoration.
+        //
+        // Since highlights can break text into many parts that are painted in
+        // overlay order, and within each part the decorations are ordered by
+        // type *then* by overlay, computing TextDecorationInfo on the fly can
+        // be very wasteful.
+        for (CachedDecorationInfo& cached_decorations : decoration_cache_) {
+          if (!cached_decorations.id.has_value()) {
+            cached_decorations.id = layers_[i].id;
+            decoration_painter_.UpdateDecorationInfo(cached_decorations.info,
+                                                     *layers_[i].style,
+                                                     layers_[i].text_style);
+            DCHECK(cached_decorations.info);
+            break;
+          }
+        }
       }
     }
   }
@@ -1116,9 +1132,9 @@
 
     // Clipping the canvas unnecessarily is expensive, so avoid doing it if
     // there are no decorations of the given |lines_to_paint|.
-    if (!decoration_layer.decoration_info ||
-        !decoration_layer.decoration_info->HasAnyLine(lines_to_paint))
+    if (!EnumHasFlags(decoration_layer.decorations_in_effect, lines_to_paint)) {
       continue;
+    }
 
     // SVG painting currently ignores ::selection styles, and will malfunction
     // or crash if asked to paint decorations introduced by highlight pseudos.
@@ -1129,6 +1145,10 @@
       continue;
     }
 
+    absl::optional<TextDecorationInfo> decoration_info_if_cache_miss{};
+    TextDecorationInfo& decoration_info =
+        DecorationInfoForLayer(decoration_layer, decoration_info_if_cache_miss);
+
     if (!state_saver.Saved()) {
       state_saver.Save();
       ClipToPartDecorations(part);
@@ -1137,13 +1157,13 @@
     if (part.layer.type != HighlightLayerType::kOriginating) {
       if (decoration_layer_id.type == HighlightLayerType::kOriginating) {
         wtf_size_t part_layer_index = layers_.Find(part.layer);
-        decoration_layer.decoration_info->SetHighlightOverrideColor(
+        decoration_info.SetHighlightOverrideColor(
             layers_[part_layer_index].text_style.current_color);
       } else {
-        decoration_layer.decoration_info->SetHighlightOverrideColor(
+        decoration_info.SetHighlightOverrideColor(
             HighlightPaintingUtils::ResolveColor(
                 layout_object_->GetDocument(), originating_style_,
-                decoration_layer.style.get(), decoration_layer.id.PseudoId(),
+                decoration_layer.style, decoration_layer.id.PseudoId(),
                 GetCSSPropertyTextDecorationColor(),
                 layers_[decoration_layer_index - 1].text_style.current_color));
       }
@@ -1152,7 +1172,7 @@
     text_painter_.PaintDecorationsExceptLineThrough(
         fragment_paint_info_.Slice(part.from, part.to), fragment_item_,
         paint_info_, *decoration_layer.style, decoration_layer.text_style,
-        *decoration_layer.decoration_info, lines_to_paint, decoration_rect_);
+        decoration_info, lines_to_paint, decoration_rect_);
   }
 }
 
@@ -1168,10 +1188,10 @@
 
     // Clipping the canvas unnecessarily is expensive, so avoid doing it if
     // there are no ‘line-through’ decorations.
-    if (!decoration_layer.decoration_info ||
-        !decoration_layer.decoration_info->HasAnyLine(
-            TextDecorationLine::kLineThrough))
+    if (!EnumHasFlags(decoration_layer.decorations_in_effect,
+                      TextDecorationLine::kLineThrough)) {
       continue;
+    }
 
     // SVG painting currently ignores ::selection styles, and will malfunction
     // or crash if asked to paint decorations introduced by highlight pseudos.
@@ -1182,6 +1202,10 @@
       continue;
     }
 
+    absl::optional<TextDecorationInfo> decoration_info_if_cache_miss{};
+    TextDecorationInfo& decoration_info =
+        DecorationInfoForLayer(decoration_layer, decoration_info_if_cache_miss);
+
     if (!state_saver.Saved()) {
       state_saver.Save();
       ClipToPartDecorations(part);
@@ -1190,13 +1214,13 @@
     if (part.layer.type != HighlightLayerType::kOriginating) {
       if (decoration_layer_id.type == HighlightLayerType::kOriginating) {
         wtf_size_t part_layer_index = layers_.Find(part.layer);
-        decoration_layer.decoration_info->SetHighlightOverrideColor(
+        decoration_info.SetHighlightOverrideColor(
             layers_[part_layer_index].text_style.current_color);
       } else {
-        decoration_layer.decoration_info->SetHighlightOverrideColor(
+        decoration_info.SetHighlightOverrideColor(
             HighlightPaintingUtils::ResolveColor(
                 layout_object_->GetDocument(), originating_style_,
-                decoration_layer.style.get(), decoration_layer.id.PseudoId(),
+                decoration_layer.style, decoration_layer.id.PseudoId(),
                 GetCSSPropertyTextDecorationColor(),
                 layers_[decoration_layer_index - 1].text_style.current_color));
       }
@@ -1204,8 +1228,7 @@
 
     text_painter_.PaintDecorationsOnlyLineThrough(
         fragment_item_, paint_info_, *decoration_layer.style,
-        decoration_layer.text_style, *decoration_layer.decoration_info,
-        decoration_rect_);
+        decoration_layer.text_style, decoration_info, decoration_rect_);
   }
 }
 
@@ -1257,6 +1280,29 @@
   }
 }
 
+TextDecorationInfo& NGHighlightPainter::DecorationInfoForLayer(
+    const LayerPaintState& layer,
+    absl::optional<TextDecorationInfo>& result_if_cache_miss) {
+  for (CachedDecorationInfo& cached_decorations : decoration_cache_) {
+    if (cached_decorations.id == layer.id) {
+      return cached_decorations.info.value();
+    }
+  }
+  decoration_painter_.UpdateDecorationInfo(result_if_cache_miss, *layer.style,
+                                           layer.text_style);
+  return result_if_cache_miss.value();
+}
+
+NGHighlightPainter::LayerPaintState::LayerPaintState(
+    NGHighlightOverlay::HighlightLayer id,
+    const ComputedStyle* style,
+    TextPaintStyle text_style)
+    : id(id),
+      style(style),
+      text_style(text_style),
+      decorations_in_effect(style ? style->TextDecorationsInEffect()
+                                  : TextDecorationLine::kNone) {}
+
 bool NGHighlightPainter::LayerPaintState::operator==(
     const HighlightLayer& other) const {
   return id == other;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
index b6c3893..2f18b69 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -203,9 +203,8 @@
 
    public:
     LayerPaintState(NGHighlightOverlay::HighlightLayer id,
-                    scoped_refptr<const ComputedStyle> style,
-                    TextPaintStyle text_style)
-        : id(id), style(std::move(style)), text_style(text_style) {}
+                    const ComputedStyle* style,
+                    TextPaintStyle text_style);
 
     // Equality on HighlightLayer id only, for Vector::Find.
     bool operator==(const LayerPaintState&) const = delete;
@@ -214,12 +213,16 @@
     bool operator!=(const NGHighlightOverlay::HighlightLayer&) const;
 
     const NGHighlightOverlay::HighlightLayer id;
-    const scoped_refptr<const ComputedStyle> style;
+    const ComputedStyle* style;
     const TextPaintStyle text_style;
-    // TextDecorationInfo is stack allocated only type, but we're using it
-    // as a stored type here, which shouldn't be permitted.
-    GC_PLUGIN_IGNORE("crbug.com/1404921")
-    absl::optional<TextDecorationInfo> decoration_info{};
+    const TextDecorationLine decorations_in_effect;
+  };
+  struct CachedDecorationInfo {
+    STACK_ALLOCATED();
+
+   public:
+    absl::optional<NGHighlightOverlay::HighlightLayer> id{};
+    absl::optional<TextDecorationInfo> info{};
   };
 
   Case ComputePaintCase() const;
@@ -248,6 +251,9 @@
       const NGHighlightOverlay::HighlightPart&);
   void PaintSpellingGrammarDecorations(
       const NGHighlightOverlay::HighlightPart&);
+  TextDecorationInfo& DecorationInfoForLayer(
+      const LayerPaintState&,
+      absl::optional<TextDecorationInfo>&);
 
   const NGTextFragmentPaintInfo& fragment_paint_info_;
   NGTextPainter& text_painter_;
@@ -272,6 +278,7 @@
   DocumentMarkerVector custom_;
   Vector<LayerPaintState> layers_;
   Vector<NGHighlightOverlay::HighlightPart> parts_;
+  CachedDecorationInfo decoration_cache_[2];
   const bool skip_backgrounds_;
   Case paint_case_;
 };
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 337d5de..a301e9a 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -554,35 +554,6 @@
   back_forward_cache_restoration_buffer_size_limit_ = size;
 }
 
-bool Performance::IsResponseSameOriginWithInitiator(
-    const ResourceResponse& response,
-    const SecurityOrigin& initiator_security_origin) {
-  scoped_refptr<const SecurityOrigin> response_origin =
-      SecurityOrigin::Create(response.ResponseUrl());
-  bool is_same_origin =
-      response_origin->IsSameOriginWith(&initiator_security_origin);
-  return is_same_origin;
-}
-
-bool Performance::PassesCORSConditions(
-    const ResourceResponse& final_response,
-    const SecurityOrigin& initiator_security_origin,
-    const network::mojom::RequestMode request_mode,
-    const Vector<ResourceResponse>& redirect_chain) {
-  if (request_mode != network::mojom::RequestMode::kNavigate) {
-    return final_response.IsCorsSameOrigin();
-  }
-
-  for (const ResourceResponse& response : redirect_chain) {
-    if (!IsResponseSameOriginWithInitiator(response,
-                                           initiator_security_origin)) {
-      return false;
-    }
-  }
-  return IsResponseSameOriginWithInitiator(final_response,
-                                           initiator_security_origin);
-}
-
 void Performance::GenerateAndAddResourceTiming(
     const ResourceTimingInfo& info,
     const AtomicString& initiator_type) {
@@ -625,23 +596,8 @@
 
   result->allow_timing_details = final_response.TimingAllowPassed();
 
-  const Vector<ResourceResponse>& redirect_chain = info.RedirectChain();
-  if (!redirect_chain.empty()) {
-    result->allow_redirect_details = result->allow_timing_details;
-
-    // TODO(https://crbug.com/817691): is |last_chained_timing| being null a bug
-    // or is this if statement reasonable?
-    if (ResourceLoadTiming* last_chained_timing =
-            redirect_chain.back().GetResourceLoadTiming()) {
-      result->last_redirect_end_time = last_chained_timing->ReceiveHeadersEnd();
-    } else {
-      result->allow_redirect_details = false;
-      result->last_redirect_end_time = base::TimeTicks();
-    }
-  } else {
-    result->allow_redirect_details = false;
-    result->last_redirect_end_time = base::TimeTicks();
-  }
+  result->last_redirect_end_time = info.LastRedirectEndTime();
+  result->allow_redirect_details = result->allow_timing_details;
 
   result->cache_state = info.CacheState();
   result->did_reuse_connection = final_response.ConnectionReused();
@@ -665,12 +621,18 @@
 
   result->content_type = g_empty_string;
 
-  bool passes_cors = PassesCORSConditions(final_response, destination_origin,
-                                          info.RequestMode(), redirect_chain);
+  bool passes_cors =
+      info.RequestMode() == network::mojom::RequestMode::kNavigate
+          ? (!info.HasCrossOriginRedirects() &&
+             destination_origin.CanAccess(
+                 SecurityOrigin::Create(final_response.ResponseUrl())))
+          : final_response.IsCorsSameOrigin();
 
   if (passes_cors) {
     result->response_status = final_response.HttpStatusCode();
-    result->content_type = final_response.HttpContentType();
+    if (!final_response.HttpContentType().IsNull()) {
+      result->content_type = final_response.HttpContentType();
+    }
   }
 
   bool expose_body_sizes =
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index 68c24f3..849d027 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -32,7 +32,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_H_
 
-#include <list>
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
@@ -75,7 +74,6 @@
 class PerformanceNavigation;
 class PerformanceObserver;
 class PerformanceTiming;
-class ResourceResponse;
 class ResourceTimingInfo;
 class ScriptPromise;
 class ScriptState;
@@ -311,17 +309,6 @@
   void SuspendObserver(PerformanceObserver&);
 
   bool HasObserverFor(PerformanceEntry::EntryType) const;
-
-  static bool IsResponseSameOriginWithInitiator(
-      const ResourceResponse& response,
-      const SecurityOrigin& initiator_security_origin);
-
-  static bool PassesCORSConditions(
-      const ResourceResponse& final_response,
-      const SecurityOrigin& initiator_security_origin,
-      const network::mojom::RequestMode request_mode,
-      const Vector<ResourceResponse>& redirect_chain);
-
   // Determine whether a given Node can be exposed via a Web Perf API.
   static bool CanExposeNode(Node*);
 
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index bb08b6c..0068f8c 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -22,35 +22,6 @@
 
 namespace blink {
 
-namespace {
-
-bool PassesSameOriginCheck(const ResourceResponse& response,
-                           const SecurityOrigin& initiator_security_origin) {
-  const KURL& response_url = response.ResponseUrl();
-  scoped_refptr<const SecurityOrigin> resource_origin =
-      SecurityOrigin::Create(response_url);
-  return resource_origin->IsSameOriginWith(&initiator_security_origin);
-}
-
-bool AllowNavigationTimingRedirect(
-    const Vector<ResourceResponse>& redirect_chain,
-    const ResourceResponse& final_response,
-    const SecurityOrigin& initiator_security_origin) {
-  if (!PassesSameOriginCheck(final_response, initiator_security_origin)) {
-    return false;
-  }
-
-  for (const ResourceResponse& response : redirect_chain) {
-    if (!PassesSameOriginCheck(response, initiator_security_origin)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-}  // namespace
-
 PerformanceNavigationTiming::PerformanceNavigationTiming(
     LocalDOMWindow& window,
     ResourceTimingInfo& info,
@@ -64,7 +35,8 @@
                                 std::move(server_timing),
                                 window),
       ExecutionContextClient(&window) {
-  Info()->SetAllowRedirectDetails(AllowNavigationRedirectDetails());
+  Info()->SetAllowRedirectDetails(
+      !GetDocumentLoadTiming()->HasCrossOriginRedirect());
 }
 
 PerformanceNavigationTiming::~PerformanceNavigationTiming() = default;
@@ -117,19 +89,6 @@
   return "navigate";
 }
 
-bool PerformanceNavigationTiming::AllowNavigationRedirectDetails() const {
-  if (!GetExecutionContext()) {
-    return false;
-  }
-  // TODO(sunjian): Think about how to make this flag deterministic.
-  // crbug/693183.
-  const blink::SecurityOrigin* security_origin =
-      GetExecutionContext()->GetSecurityOrigin();
-
-  return AllowNavigationTimingRedirect(
-      Info()->RedirectChain(), Info()->FinalResponse(), *security_origin);
-}
-
 DOMHighResTimeStamp PerformanceNavigationTiming::unloadEventStart() const {
   DocumentLoadTiming* timing = GetDocumentLoadTiming();
   if (!Info()->AllowRedirectDetails() || !timing ||
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.h b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
index 3d110a9..7e5c09f 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.h
@@ -75,8 +75,6 @@
 
   DocumentLoadTiming* GetDocumentLoadTiming() const;
 
-  bool AllowNavigationRedirectDetails() const;
-
   ScriptValue NotRestoredReasonsBuilder(
       ScriptState* script_state,
       const mojom::blink::BackForwardCacheNotRestoredReasonsPtr& reasons) const;
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index b732670..531810c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -5894,9 +5894,9 @@
       return WebGLAny(script_state, GL_RENDERBUFFER);
     case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
       return WebGLAny(script_state, attachment_object);
+    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
     case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
     case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
-    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
       if (!attachment_object->IsTexture())
         break;
       [[fallthrough]];
@@ -5915,7 +5915,7 @@
       if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
         SynthesizeGLError(
             GL_INVALID_OPERATION, kFunctionName,
-            "COMPONENT_TYPE can't be queried for DEPTH_STENCIL_ATTACHMENT");
+            "component type cannot be queried for DEPTH_STENCIL_ATTACHMENT");
         return ScriptValue::CreateNull(script_state->GetIsolate());
       }
       [[fallthrough]];
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index ececfd4..7bde2e81 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -3351,19 +3351,20 @@
     GLenum target,
     GLenum attachment,
     GLenum pname) {
+  const char kFunctionName[] = "getFramebufferAttachmentParameter";
   if (isContextLost() ||
-      !ValidateFramebufferFuncParameters("getFramebufferAttachmentParameter",
-                                         target, attachment))
+      !ValidateFramebufferFuncParameters(kFunctionName, target, attachment)) {
     return ScriptValue::CreateNull(script_state->GetIsolate());
+  }
 
   if (!framebuffer_binding_ || !framebuffer_binding_->Object()) {
-    SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
+    SynthesizeGLError(GL_INVALID_OPERATION, kFunctionName,
                       "no framebuffer bound");
     return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   if (framebuffer_binding_ && framebuffer_binding_->Opaque()) {
-    SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
+    SynthesizeGLError(GL_INVALID_OPERATION, kFunctionName,
                       "cannot query parameters of an opaque framebuffer");
     return ScriptValue::CreateNull(script_state->GetIsolate());
   }
@@ -3375,62 +3376,60 @@
       return WebGLAny(script_state, GL_NONE);
     // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
     // specifies INVALID_OPERATION.
-    SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
-                      "invalid parameter name");
+    SynthesizeGLError(GL_INVALID_ENUM, kFunctionName, "invalid parameter name");
     return ScriptValue::CreateNull(script_state->GetIsolate());
   }
 
   DCHECK(attachment_object->IsTexture() || attachment_object->IsRenderbuffer());
-  if (attachment_object->IsTexture()) {
-    switch (pname) {
-      case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+  switch (pname) {
+    case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+      if (attachment_object->IsTexture()) {
         return WebGLAny(script_state, GL_TEXTURE);
-      case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
-        return WebGLAny(script_state, attachment_object);
-      case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
-      case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
+      }
+      return WebGLAny(script_state, GL_RENDERBUFFER);
+    case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+      return WebGLAny(script_state, attachment_object);
+    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+    case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+      if (attachment_object->IsTexture()) {
         GLint value = 0;
         ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
                                                          pname, &value);
         return WebGLAny(script_state, value);
       }
-      case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
-        if (ExtensionEnabled(kEXTsRGBName)) {
-          GLint value = 0;
-          ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
-                                                           pname, &value);
-          return WebGLAny(script_state, static_cast<unsigned>(value));
+      break;
+    case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
+      if (ExtensionEnabled(kEXTsRGBName)) {
+        GLint value = 0;
+        ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
+                                                         pname, &value);
+        return WebGLAny(script_state, static_cast<unsigned>(value));
+      }
+      SynthesizeGLError(GL_INVALID_ENUM, kFunctionName,
+                        "invalid parameter name, EXT_sRGB not enabled");
+      return ScriptValue::CreateNull(script_state->GetIsolate());
+    case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT:
+      if (ExtensionEnabled(kEXTColorBufferHalfFloatName) ||
+          ExtensionEnabled(kWebGLColorBufferFloatName)) {
+        if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
+          SynthesizeGLError(
+              GL_INVALID_OPERATION, kFunctionName,
+              "component type cannot be queried for DEPTH_STENCIL_ATTACHMENT");
+          return ScriptValue::CreateNull(script_state->GetIsolate());
         }
-        SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
-                          "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state->GetIsolate());
-      default:
-        SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
-                          "invalid parameter name for texture attachment");
-        return ScriptValue::CreateNull(script_state->GetIsolate());
-    }
-  } else {
-    switch (pname) {
-      case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
-        return WebGLAny(script_state, GL_RENDERBUFFER);
-      case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
-        return WebGLAny(script_state, attachment_object);
-      case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
-        if (ExtensionEnabled(kEXTsRGBName)) {
-          GLint value = 0;
-          ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
-                                                           pname, &value);
-          return WebGLAny(script_state, value);
-        }
-        SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
-                          "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state->GetIsolate());
-      default:
-        SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
-                          "invalid parameter name for renderbuffer attachment");
-        return ScriptValue::CreateNull(script_state->GetIsolate());
-    }
+        GLint value = 0;
+        ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
+                                                         pname, &value);
+        return WebGLAny(script_state, static_cast<unsigned>(value));
+      }
+      SynthesizeGLError(
+          GL_INVALID_ENUM, kFunctionName,
+          "invalid parameter name, EXT_color_buffer_half_float or "
+          "WEBGL_color_buffer_float not enabled");
+      return ScriptValue::CreateNull(script_state->GetIsolate());
   }
+  SynthesizeGLError(GL_INVALID_ENUM, kFunctionName, "invalid parameter name");
+  return ScriptValue::CreateNull(script_state->GetIsolate());
 }
 
 namespace {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
index 6fe1071..d827880 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
@@ -7,6 +7,7 @@
 #include "base/notreached.h"
 #include "services/network/public/mojom/url_response_head.mojom-blink-forward.h"
 #include "third_party/blink/renderer/platform/loader/fetch/delivery_type_names.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 namespace blink {
 using network::mojom::blink::NavigationDeliveryType;
@@ -35,7 +36,7 @@
       render_blocking_status_(info.render_blocking_status
                                   ? RenderBlockingStatusType::kBlocking
                                   : RenderBlockingStatusType::kNonBlocking),
-      content_type_(static_cast<String>(info.content_type)),
+      content_type_(info.content_type),
       context_type_(info.context_type),
       request_destination_(info.request_destination),
       load_response_end_(info.response_end),
@@ -55,9 +56,17 @@
       allow_timing_details_(info.allow_timing_details),
       allow_redirect_details_(info.allow_redirect_details),
       is_secure_transport_(info.is_secure_transport) {}
+
 void ResourceTimingInfo::AddRedirect(const ResourceResponse& redirect_response,
                                      const KURL& new_url) {
-  redirect_chain_.push_back(redirect_response);
+  const ResourceLoadTiming* timing = redirect_response.GetResourceLoadTiming();
+  if (timing) {
+    last_redirect_end_time_ = timing->ReceiveHeadersEnd();
+  }
+  if (!SecurityOrigin::Create(new_url)->CanAccess(
+          SecurityOrigin::Create(redirect_response.CurrentRequestUrl()))) {
+    has_cross_origin_redirects_ = true;
+  }
 }
 
 void ResourceTimingInfo::SetDeliveryType(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
index eeb7ac8c..adf7e54 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
@@ -99,9 +99,6 @@
   void AddRedirect(const ResourceResponse& redirect_response,
                    const KURL& new_url);
 
-  const Vector<ResourceResponse>& RedirectChain() const {
-    return redirect_chain_;
-  }
   mojom::blink::CacheState CacheState() const { return cache_state_; }
 
   const AtomicString& ContentType() const { return content_type_; }
@@ -136,7 +133,9 @@
 
   network::mojom::RequestMode RequestMode() const { return request_mode_; }
 
-  base::TimeTicks LastRedirectEndTime() { return last_redirect_end_time_; }
+  base::TimeTicks LastRedirectEndTime() const {
+    return last_redirect_end_time_;
+  }
 
   base::TimeTicks ResponseEnd() const { return load_response_end_; }
 
@@ -160,6 +159,8 @@
 
   bool AllowRedirectDetails() { return allow_redirect_details_; }
 
+  bool HasCrossOriginRedirects() const { return has_cross_origin_redirects_; }
+
   bool IsSecureTransport() { return is_secure_transport_; }
 
   void SetName(const AtomicString& name) { name_ = name; }
@@ -230,8 +231,7 @@
   KURL initial_url_;
   ResourceResponse final_response_;
   uint16_t response_status_ = 0;
-  Vector<ResourceResponse> redirect_chain_;
-  bool has_cross_origin_redirect_ = false;
+  bool has_cross_origin_redirects_ = false;
   bool negative_allowed_ = false;
 
   AtomicString delivery_type_;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 219b8d5..b6034c8 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1064,8 +1064,8 @@
     // trial it isn't possible to set a `depends_on`.
     {
       name: "DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning",
+      origin_trial_feature_name: "DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning",
       status: "experimental",
-      browser_process_read_write_access: true,
     },
     // This feature will represent the deprecation trial that allows first
     // parties to temporarily use unpartitioned storage in embeds loaded
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 2fde2cf..bd6fd98 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -601,7 +601,9 @@
 crbug.com/874695 media/encrypted-media/encrypted-media-onencrypted.html [ Slow ]
 crbug.com/874695 [ Debug Mac12 ] media/encrypted-media/encrypted-media-setmediakeys-at-same-time.html [ Slow ]
 crbug.com/874695 [ Release ] media/encrypted-media/encrypted-media-setmediakeys-at-same-time.html [ Slow ]
-crbug.com/874695 media/media-controls-tap-show-controls-without-activating.html [ Slow ]
+crbug.com/874695 [ Linux Release ] media/media-controls-tap-show-controls-without-activating.html [ Slow ]
+crbug.com/874695 [ Mac ] media/media-controls-tap-show-controls-without-activating.html [ Slow ]
+crbug.com/874695 [ Release Win ] media/media-controls-tap-show-controls-without-activating.html [ Slow ]
 crbug.com/874695 [ Debug Mac12 ] media/media-ended.html [ Slow ]
 crbug.com/874695 [ Release ] media/media-ended.html [ Slow ]
 crbug.com/874695 media/remoteplayback/prompt-twice-throws.html [ Slow ]
@@ -940,7 +942,6 @@
 crbug.com/1043356 [ Linux Release ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
 crbug.com/1043356 [ Mac10.15 Release ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
 crbug.com/1043356 [ Mac11 Release ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
-crbug.com/1043356 [ Mac11-arm64 Release ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
 crbug.com/1043356 [ Mac12 Release ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
 crbug.com/1043356 [ Release Win ] http/tests/devtools/elements/styles-4/keyframes-source-offsets.js [ Slow ]
 crbug.com/1043354 [ Linux Release ] http/tests/devtools/service-workers/service-worker-pause.js [ Slow ]
@@ -1032,7 +1033,6 @@
 crbug.com/1044518 [ Release Win ] http/tests/devtools/bindings/suspendtarget-navigator.js [ Slow ]
 crbug.com/1044518 [ Mac10.15 Release ] http/tests/devtools/bindings/suspendtarget-navigator.js [ Slow ]
 crbug.com/1044518 [ Mac11 Release ] http/tests/devtools/bindings/suspendtarget-navigator.js [ Slow ]
-crbug.com/1044518 [ Mac11-arm64 Release ] http/tests/devtools/bindings/suspendtarget-navigator.js [ Slow ]
 crbug.com/1044518 [ Mac12 Release ] http/tests/devtools/bindings/suspendtarget-navigator.js [ Slow ]
 crbug.com/1044544 [ Linux Release ] http/tests/devtools/network/network-disable-cache-preloads-twice.js [ Slow ]
 crbug.com/1044544 [ Mac10.15 Release ] http/tests/devtools/network/network-disable-cache-preloads-twice.js [ Slow ]
@@ -1075,7 +1075,6 @@
 crbug.com/1044823 [ Mac10.15 Release ] http/tests/devtools/extensions/extensions-timeline-api.js [ Slow ]
 crbug.com/1044823 [ Mac11 Release ] http/tests/devtools/extensions/extensions-timeline-api.js [ Slow ]
 crbug.com/1044823 [ Mac12 Release ] http/tests/devtools/extensions/extensions-timeline-api.js [ Slow ]
-crbug.com/1044823 [ Mac12-arm64 Release ] http/tests/devtools/extensions/extensions-timeline-api.js [ Slow ]
 crbug.com/1044823 [ Release Win ] http/tests/devtools/extensions/extensions-timeline-api.js [ Slow ]
 crbug.com/1044829 [ Release Win ] http/tests/devtools/cache-storage/cache-deletion.js [ Slow ]
 crbug.com/1044829 [ Mac10.15 Release ] http/tests/devtools/cache-storage/cache-deletion.js [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f5bcf1c..1502b52 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -202,9 +202,6 @@
 
 # The tests happened to pass with two bugs canceled each other. Now they fail
 # with the first bug fixed. Will be fixed when the second bug is fixed (crrev.com/c/3752748).
-crbug.com/881555 [ Debug Mac12 ] external/wpt/css/css-position/sticky/position-sticky-fixed-ancestor.html [ Failure ]
-crbug.com/881555 [ Mac11-arm64 Release ] external/wpt/css/css-position/sticky/position-sticky-fixed-ancestor.html [ Failure ]
-crbug.com/881555 [ Mac12-arm64 Release ] external/wpt/css/css-position/sticky/position-sticky-fixed-ancestor.html [ Failure ]
 
 # --- Skia roll test suppressions
 # --- END Skia roll test suppresions
@@ -492,7 +489,6 @@
 
 crbug.com/980969 http/tests/input/discard-events-to-unstable-iframe.html [ Failure Pass ]
 
-crbug.com/1002049 [ Mac12-arm64 Release ] external/wpt/css/mediaqueries/aspect-ratio-006.html [ Failure ]
 crbug.com/1343368 external/wpt/css/mediaqueries/viewport-script-dynamic.html [ Failure ]
 
 crbug.com/815111 external/wpt/css/css-fill-stroke/paint-order-001.tentative.html [ Failure ]
@@ -3076,7 +3072,6 @@
 crbug.com/626703 [ Linux ] external/wpt/webxr/hit-test/ar_hittest_subscription_transientInputSources.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/webxr/render_state_update.https.html [ Timeout ]
-crbug.com/626703 [ Linux ] external/wpt/webxr/render_state_vertical_fov_immersive.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/webxr/webxr_feature_policy.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/webxr/xrDevice_requestSession_optionalFeatures.https.html [ Timeout ]
 crbug.com/626703 [ Linux ] external/wpt/webxr/xrInputSource_getPose_targetRay_grip.https.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 6f3ca65..c3adee0 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -73961,7 +73961,7 @@
       ]
      ],
      "root-element-opacity.html": [
-      "4885d805ad3f3b59d60ccbf3047e8694d7be0f18",
+      "a8195bc552e5270c45716cc34ad6063769fd5581",
       [
        null,
        [
@@ -73970,7 +73970,23 @@
          "=="
         ]
        ],
-       {}
+       {
+        "fuzzy": [
+         [
+          null,
+          [
+           [
+            0,
+            1
+           ],
+           [
+            0,
+            480000
+           ]
+          ]
+         ]
+        ]
+       }
       ]
      ],
      "svg": {
@@ -95637,7 +95653,7 @@
       ]
      ],
      "t32-opacity-offscreen-with-alpha-c.xht": [
-      "57e5e3cc860cd2600dd4723831d29fb39f684782",
+      "035609e8a46aea92633b7b71f9bc40ba58a13569",
       [
        null,
        [
@@ -95646,7 +95662,23 @@
          "=="
         ]
        ],
-       {}
+       {
+        "fuzzy": [
+         [
+          null,
+          [
+           [
+            0,
+            1
+           ],
+           [
+            0,
+            5120
+           ]
+          ]
+         ]
+        ]
+       }
       ]
      ],
      "t32-opacity-zorder-c.xht": [
@@ -158017,7 +158049,7 @@
       ]
      ],
      "backdrop-animate-002.html": [
-      "6fd153becdee39018031586d82186cd2bac67f11",
+      "910807a7a63081e0bedaffd262bb261bccf611aa",
       [
        null,
        [
@@ -158037,7 +158069,7 @@
            ],
            [
             0,
-            472272
+            472500
            ]
           ]
          ]
@@ -284364,7 +284396,7 @@
        []
       ],
       "color-computed-color-mix-function-expected.txt": [
-       "9fc84406d5e1fe4b64e49e150b923684c2419779",
+       "7a0db87255b80b88aa5feb9cbd439085cedf1028",
        []
       ],
       "color-computed-color-mix-function.html.ini": [
@@ -372876,7 +372908,7 @@
        []
       ],
       "mime-charset.py": [
-       "46d8252e0c90a7a63c5a814c4332ad18a2c7e19e",
+       "bcc3dc3a838d0ded351a3628058c5dcc0c50c7fd",
        []
       ],
       "mime-groups.json": [
@@ -379667,7 +379699,7 @@
       []
      ],
      "orientation-utils.js": [
-      "630aca2d1f9facf245f7f1d062474c5d8bf2e611",
+      "95383750f16e1a47d39e514627e03f2ba8c3b8ca",
       []
      ],
      "sandboxed-iframe-locking.html": [
@@ -437704,7 +437736,7 @@
        ]
       ],
       "color-computed-color-mix-function.html": [
-       "a2682eaacafc8322f1ead865083cd8fd2c904fde",
+       "50f01bcc35f1e1c4205be9d4c4070433ead1a82c",
        [
         null,
         {}
@@ -592059,7 +592091,7 @@
      ]
     ],
     "hidden_document.html": [
-     "4d018a882a114aa6a29db60c2403e78734cdd034",
+     "349539628a3718920384ae6faca36844041ecdc8",
      [
       null,
       {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
index 9fc8440..7a0db87 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 474 tests; 400 PASS, 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 450 tests; 400 PASS, 50 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Property color value 'color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))'
 PASS Property color value 'color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))'
 PASS Property color value 'color-mix(in hsl, 25% hsl(120deg 10% 20%), hsl(30deg 30% 40%))'
@@ -48,12 +48,6 @@
 PASS Property color value 'color-mix(in hsl decreasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))'
 PASS Property color value 'color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))'
 PASS Property color value 'color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))'
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' is a supported value for color. expected true got false
 PASS Property color value 'color-mix(in hsl, hsl(none none none), hsl(none none none))'
 PASS Property color value 'color-mix(in hsl, hsl(none none none), hsl(30deg 40% 80%))'
 PASS Property color value 'color-mix(in hsl, hsl(120deg 20% 40%), hsl(none none none))'
@@ -120,12 +114,6 @@
 PASS Property color value 'color-mix(in hwb decreasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))'
 PASS Property color value 'color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))'
 PASS Property color value 'color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))'
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' is a supported value for color. expected true got false
 PASS Property color value 'color-mix(in hwb, hwb(none none none), hwb(none none none))'
 PASS Property color value 'color-mix(in hwb, hwb(none none none), hwb(30deg 30% 40%))'
 PASS Property color value 'color-mix(in hwb, hwb(120deg 10% 20%), hwb(none none none))'
@@ -192,12 +180,6 @@
 PASS Property color value 'color-mix(in lch decreasing hue, lch(100 0 330deg), lch(100 0 50deg))'
 PASS Property color value 'color-mix(in lch decreasing hue, lch(100 0 20deg), lch(100 0 320deg))'
 PASS Property color value 'color-mix(in lch decreasing hue, lch(100 0 320deg), lch(100 0 20deg))'
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 40deg), lch(100 0 60deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 40deg), lch(100 0 60deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 60deg), lch(100 0 40deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 60deg), lch(100 0 40deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 50deg), lch(100 0 330deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 50deg), lch(100 0 330deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 330deg), lch(100 0 50deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 330deg), lch(100 0 50deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 20deg), lch(100 0 320deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 20deg), lch(100 0 320deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 320deg), lch(100 0 20deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 320deg), lch(100 0 20deg))' is a supported value for color. expected true got false
 PASS Property color value 'color-mix(in lch, lch(none none none), lch(none none none))'
 PASS Property color value 'color-mix(in lch, lch(none none none), lch(50 60 70deg))'
 PASS Property color value 'color-mix(in lch, lch(10 20 30deg), lch(none none none))'
@@ -255,12 +237,6 @@
 PASS Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 330deg), oklch(100 0 50deg))'
 PASS Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 20deg), oklch(100 0 320deg))'
 PASS Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 320deg), oklch(100 0 20deg))'
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 40deg), oklch(100 0 60deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 40deg), oklch(100 0 60deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 60deg), oklch(100 0 40deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 60deg), oklch(100 0 40deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 50deg), oklch(100 0 330deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 50deg), oklch(100 0 330deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 330deg), oklch(100 0 50deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 330deg), oklch(100 0 50deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 20deg), oklch(100 0 320deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 20deg), oklch(100 0 320deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 320deg), oklch(100 0 20deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 320deg), oklch(100 0 20deg))' is a supported value for color. expected true got false
 PASS Property color value 'color-mix(in oklch, oklch(none none none), oklch(none none none))'
 PASS Property color value 'color-mix(in oklch, oklch(none none none), oklch(50 60 70deg))'
 PASS Property color value 'color-mix(in oklch, oklch(10 20 30deg), oklch(none none none))'
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html
index a2682eaa..50f01bc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-computed-color-mix-function.html
@@ -81,13 +81,6 @@
     test_computed_value(`color`, `color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, canonicalize(`hsl(350deg 50% 50%)`));
     test_computed_value(`color`, `color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, canonicalize(`hsl(170deg 50% 50%)`));
 
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, canonicalize(`hsl(50deg 50% 50%)`));
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, canonicalize(`hsl(50deg 50% 50%)`));
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, canonicalize(`hsl(190deg 50% 50%)`));
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, canonicalize(`hsl(190deg 50% 50%)`));
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, canonicalize(`hsl(170deg 50% 50%)`));
-    test_computed_value(`color`, `color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, canonicalize(`hsl(170deg 50% 50%)`));
-
     test_computed_value(`color`, `color-mix(in hsl, hsl(none none none), hsl(none none none))`, canonicalize(`hsl(none none none)`));
     test_computed_value(`color`, `color-mix(in hsl, hsl(none none none), hsl(30deg 40% 80%))`, canonicalize(`hsl(30deg 40% 80%)`));
     test_computed_value(`color`, `color-mix(in hsl, hsl(120deg 20% 40%), hsl(none none none))`, canonicalize(`hsl(120deg 20% 40%)`));
@@ -165,13 +158,6 @@
     test_computed_value(`color`, `color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, canonicalize(`hwb(350deg 30% 40%)`));
     test_computed_value(`color`, `color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, canonicalize(`hwb(170deg 30% 40%)`));
 
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, canonicalize(`hwb(50deg 30% 40%)`));
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, canonicalize(`hwb(50deg 30% 40%)`));
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, canonicalize(`hwb(190deg 30% 40%)`));
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, canonicalize(`hwb(190deg 30% 40%)`));
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, canonicalize(`hwb(170deg 30% 40%)`));
-    test_computed_value(`color`, `color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, canonicalize(`hwb(170deg 30% 40%)`));
-
     test_computed_value(`color`, `color-mix(in hwb, hwb(none none none), hwb(none none none))`, canonicalize(`hwb(none none none)`));
     test_computed_value(`color`, `color-mix(in hwb, hwb(none none none), hwb(30deg 30% 40%))`, canonicalize(`hwb(30deg 30% 40%)`));
     test_computed_value(`color`, `color-mix(in hwb, hwb(120deg 10% 20%), hwb(none none none))`, canonicalize(`hwb(120deg 10% 20%)`));
@@ -248,13 +234,6 @@
         test_computed_value(`color`, `color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100 0 20deg), ${colorSpace}(100 0 320deg))`, `${colorSpace}(100 0 350)`);
         test_computed_value(`color`, `color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100 0 320deg), ${colorSpace}(100 0 20deg))`, `${colorSpace}(100 0 170)`);
 
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 40deg), ${colorSpace}(100 0 60deg))`, `${colorSpace}(100 0 50)`);
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 60deg), ${colorSpace}(100 0 40deg))`, `${colorSpace}(100 0 50)`);
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 50deg), ${colorSpace}(100 0 330deg))`, `${colorSpace}(100 0 190)`);
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 330deg), ${colorSpace}(100 0 50deg))`, `${colorSpace}(100 0 190)`);
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 20deg), ${colorSpace}(100 0 320deg))`, `${colorSpace}(100 0 170)`);
-        test_computed_value(`color`, `color-mix(in ${colorSpace} specified hue, ${colorSpace}(100 0 320deg), ${colorSpace}(100 0 20deg))`, `${colorSpace}(100 0 170)`);
-
         test_computed_value(`color`, `color-mix(in ${colorSpace}, ${colorSpace}(none none none), ${colorSpace}(none none none))`, `${colorSpace}(none none none)`);
         test_computed_value(`color`, `color-mix(in ${colorSpace}, ${colorSpace}(none none none), ${colorSpace}(50 60 70deg))`, `${colorSpace}(50 60 70)`);
         test_computed_value(`color`, `color-mix(in ${colorSpace}, ${colorSpace}(10 20 30deg), ${colorSpace}(none none none))`, `${colorSpace}(10 20 30)`);
diff --git a/third_party/blink/web_tests/external/wpt/mimesniff/mime-types/resources/mime-charset.py b/third_party/blink/web_tests/external/wpt/mimesniff/mime-types/resources/mime-charset.py
index 46d8252e..bcc3dc3 100644
--- a/third_party/blink/web_tests/external/wpt/mimesniff/mime-types/resources/mime-charset.py
+++ b/third_party/blink/web_tests/external/wpt/mimesniff/mime-types/resources/mime-charset.py
@@ -12,6 +12,7 @@
     output = b"HTTP/1.1 200 OK\r\n"
     output += b"Content-Length: " + isomorphic_encode(str(len(content))) + b"\r\n"
     output += b"Content-Type: " + request.GET.first(b"type") + b"\r\n"
+    output += b"Connection: close\r\n"
     output += b"\r\n"
     output += content
     response.writer.write(output)
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/hidden_document.html b/third_party/blink/web_tests/external/wpt/screen-orientation/hidden_document.html
index 4d018a88..3495396 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/hidden_document.html
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/hidden_document.html
@@ -14,7 +14,6 @@
 
   promise_test(async (t) => {
     const { minimize, restore } = window_state_context(t);
-    t.add_cleanup(restore);
 
     await minimize();
 
@@ -24,7 +23,6 @@
 
   promise_test(async (t) => {
     const { minimize, restore } = window_state_context(t);
-    t.add_cleanup(restore);
 
     await minimize();
 
@@ -34,7 +32,6 @@
 
   promise_test(async (t) => {
     const { minimize, restore } = window_state_context(t);
-    t.add_cleanup(restore);
     t.add_cleanup(makeCleanup());
     await screen.orientation.lock(getOppositeOrientation());
 
@@ -46,7 +43,6 @@
 
   promise_test(async (t) => {
     const { minimize, restore } = window_state_context(t);
-    t.add_cleanup(restore);
     t.add_cleanup(makeCleanup());
     await screen.orientation.lock(getOppositeOrientation());
 
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
index 630aca2d..9538375 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
@@ -38,7 +38,9 @@
 ) {
   return async () => {
     if (initialOrientation) {
-      await screen.orientation.lock(initialOrientation);
+      try {
+        await screen.orientation.lock(initialOrientation);
+      } catch {}
     }
     screen.orientation.unlock();
     requestAnimationFrame(async () => {
diff --git a/third_party/blink/web_tests/virtual/stable/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt b/third_party/blink/web_tests/virtual/stable/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
index 78784ba..21de010 100644
--- a/third_party/blink/web_tests/virtual/stable/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/external/wpt/css/css-color/parsing/color-computed-color-mix-function-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 474 tests; 0 PASS, 474 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 450 tests; 0 PASS, 450 FAIL, 0 TIMEOUT, 0 NOTRUN.
 FAIL Property color value 'color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))' assert_true: 'color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))' assert_true: 'color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl, 25% hsl(120deg 10% 20%), hsl(30deg 30% 40%))' assert_true: 'color-mix(in hsl, 25% hsl(120deg 10% 20%), hsl(30deg 30% 40%))' is a supported value for color. expected true got false
@@ -48,12 +48,6 @@
 FAIL Property color value 'color-mix(in hsl decreasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' assert_true: 'color-mix(in hsl decreasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' assert_true: 'color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' assert_true: 'color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' assert_true: 'color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl, hsl(none none none), hsl(none none none))' assert_true: 'color-mix(in hsl, hsl(none none none), hsl(none none none))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl, hsl(none none none), hsl(30deg 40% 80%))' assert_true: 'color-mix(in hsl, hsl(none none none), hsl(30deg 40% 80%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hsl, hsl(120deg 20% 40%), hsl(none none none))' assert_true: 'color-mix(in hsl, hsl(120deg 20% 40%), hsl(none none none))' is a supported value for color. expected true got false
@@ -120,12 +114,6 @@
 FAIL Property color value 'color-mix(in hwb decreasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' assert_true: 'color-mix(in hwb decreasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' assert_true: 'color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' assert_true: 'color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' assert_true: 'color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hwb, hwb(none none none), hwb(none none none))' assert_true: 'color-mix(in hwb, hwb(none none none), hwb(none none none))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hwb, hwb(none none none), hwb(30deg 30% 40%))' assert_true: 'color-mix(in hwb, hwb(none none none), hwb(30deg 30% 40%))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in hwb, hwb(120deg 10% 20%), hwb(none none none))' assert_true: 'color-mix(in hwb, hwb(120deg 10% 20%), hwb(none none none))' is a supported value for color. expected true got false
@@ -192,12 +180,6 @@
 FAIL Property color value 'color-mix(in lch decreasing hue, lch(100 0 330deg), lch(100 0 50deg))' assert_true: 'color-mix(in lch decreasing hue, lch(100 0 330deg), lch(100 0 50deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in lch decreasing hue, lch(100 0 20deg), lch(100 0 320deg))' assert_true: 'color-mix(in lch decreasing hue, lch(100 0 20deg), lch(100 0 320deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in lch decreasing hue, lch(100 0 320deg), lch(100 0 20deg))' assert_true: 'color-mix(in lch decreasing hue, lch(100 0 320deg), lch(100 0 20deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 40deg), lch(100 0 60deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 40deg), lch(100 0 60deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 60deg), lch(100 0 40deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 60deg), lch(100 0 40deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 50deg), lch(100 0 330deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 50deg), lch(100 0 330deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 330deg), lch(100 0 50deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 330deg), lch(100 0 50deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 20deg), lch(100 0 320deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 20deg), lch(100 0 320deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in lch specified hue, lch(100 0 320deg), lch(100 0 20deg))' assert_true: 'color-mix(in lch specified hue, lch(100 0 320deg), lch(100 0 20deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in lch, lch(none none none), lch(none none none))' assert_true: 'color-mix(in lch, lch(none none none), lch(none none none))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in lch, lch(none none none), lch(50 60 70deg))' assert_true: 'color-mix(in lch, lch(none none none), lch(50 60 70deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in lch, lch(10 20 30deg), lch(none none none))' assert_true: 'color-mix(in lch, lch(10 20 30deg), lch(none none none))' is a supported value for color. expected true got false
@@ -255,12 +237,6 @@
 FAIL Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 330deg), oklch(100 0 50deg))' assert_true: 'color-mix(in oklch decreasing hue, oklch(100 0 330deg), oklch(100 0 50deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 20deg), oklch(100 0 320deg))' assert_true: 'color-mix(in oklch decreasing hue, oklch(100 0 20deg), oklch(100 0 320deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in oklch decreasing hue, oklch(100 0 320deg), oklch(100 0 20deg))' assert_true: 'color-mix(in oklch decreasing hue, oklch(100 0 320deg), oklch(100 0 20deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 40deg), oklch(100 0 60deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 40deg), oklch(100 0 60deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 60deg), oklch(100 0 40deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 60deg), oklch(100 0 40deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 50deg), oklch(100 0 330deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 50deg), oklch(100 0 330deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 330deg), oklch(100 0 50deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 330deg), oklch(100 0 50deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 20deg), oklch(100 0 320deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 20deg), oklch(100 0 320deg))' is a supported value for color. expected true got false
-FAIL Property color value 'color-mix(in oklch specified hue, oklch(100 0 320deg), oklch(100 0 20deg))' assert_true: 'color-mix(in oklch specified hue, oklch(100 0 320deg), oklch(100 0 20deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in oklch, oklch(none none none), oklch(none none none))' assert_true: 'color-mix(in oklch, oklch(none none none), oklch(none none none))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in oklch, oklch(none none none), oklch(50 60 70deg))' assert_true: 'color-mix(in oklch, oklch(none none none), oklch(50 60 70deg))' is a supported value for color. expected true got false
 FAIL Property color value 'color-mix(in oklch, oklch(10 20 30deg), oklch(none none none))' assert_true: 'color-mix(in oklch, oklch(10 20 30deg), oklch(none none none))' is a supported value for color. expected true got false
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 09831b34..4ee9d8d 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -5598,28 +5598,6 @@
   </summary>
 </histogram>
 
-<histogram
-    name="Media.WebmMuxer.DidAdjustTimestamp.{StreamTypesRecorded}.{Domain}"
-    enum="Boolean" expires_after="2023-06-26">
-  <owner>handellm@google.com</owner>
-  <owner>video-performance@google.com</owner>
-  <summary>
-    Boolean indicating if {Domain} stream timestamps had to be corrected during
-    a muxing session with {StreamTypesRecorded} present. Reported on muxer
-    destructor.
-  </summary>
-  <token key="StreamTypesRecorded">
-    <variant name="AudioOnly" summary=""/>
-    <variant name="AudioVideo" summary=""/>
-    <variant name="VideoOnly" summary=""/>
-  </token>
-  <token key="Domain">
-    <variant name="Audio" summary=""/>
-    <variant name="Muxer" summary=""/>
-    <variant name="Video" summary=""/>
-  </token>
-</histogram>
-
 <histogram name="Media.WebrtcVideoPerfHistory.GetPerfInfoCodecProfile"
     enum="VideoCodecProfile" expires_after="2023-06-04">
   <owner>kron@chromium.org</owner>
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 9147c5e..83a2dfd 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -1284,7 +1284,6 @@
     ":main",
     "//ui/file_manager:build_ts",
     "//ui/webui/resources:library",
-    "//ui/webui/resources:preprocess",
   ]
 }
 
@@ -1304,6 +1303,5 @@
   deps = [
     "metadata:metadata_dispatcher",
     "//ui/file_manager:build_ts",
-    "//ui/webui/resources:preprocess",
   ]
 }
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn
index 0a969cb..af907ca 100644
--- a/ui/file_manager/image_loader/BUILD.gn
+++ b/ui/file_manager/image_loader/BUILD.gn
@@ -211,6 +211,6 @@
     "//ui/file_manager:preprocess_generated",
     "//ui/file_manager:preprocess_static",
     "//ui/file_manager:preprocess_static_image_loader",
-    "//ui/webui/resources:preprocess",
+    "//ui/webui/resources:library",
   ]
 }
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index ec036c9..ed6eb96 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -7,7 +7,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/include_polymer.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("./cr_elements/cr_elements.gni")
 
 generate_grd("build_grd") {
   grd_prefix = "webui"
@@ -28,7 +27,7 @@
   }
 
   public_deps = [
-    ":build_ts_grdp",
+    "cr_elements:build_grdp",
     "css:build_grdp",
     "images:build_grdp",
     "js:build_grdp",
@@ -36,12 +35,12 @@
     "//third_party/jstemplate:build_grdp",
   ]
   grdp_files = [
+    "$root_gen_dir/third_party/jstemplate/resources.grdp",
+    "$target_gen_dir/cr_elements/resources.grdp",
     "$target_gen_dir/css/resources.grdp",
     "$target_gen_dir/images/resources.grdp",
     "$target_gen_dir/js/metrics_reporter/resources.grdp",
     "$target_gen_dir/js/resources.grdp",
-    "$target_gen_dir/resources_ts.grdp",
-    "$root_gen_dir/third_party/jstemplate/resources.grdp",
   ]
 
   if (include_polymer) {
@@ -135,40 +134,24 @@
   }
 }
 
-group("preprocess") {
-  public_deps = [ "cr_elements:preprocess" ]
-}
-
 # TypeScript targets
 
-preprocessed_folder = "$target_gen_dir/preprocessed"
-
+# TODO(crbug/1402829): This target has no input files and just exists to allow
+# incrementally rolling out the breaking up of this target to separate targets.
+# Remove when all references have been updated.
+ignored_folder = "$target_gen_dir/ignored"
 ts_library("library") {
-  root_dir = preprocessed_folder
-  out_dir = preprocessed_folder
+  root_dir = ignored_folder
+  out_dir = ignored_folder
   composite = true
   tsconfig_base = "tsconfig_base.json"
-  extra_deps = []
 
-  in_files = cr_elements_files
+  # Intentionally empty. Don't add any files here.
+  in_files = []
 
-  definitions = [
-    "//tools/typescript/definitions/pending.d.ts",
-    "//tools/typescript/definitions/settings_private.d.ts",
+  deps = [
+    "//ui/webui/resources/cr_elements:build_ts",
+    "//ui/webui/resources/js:build_ts",
+    "//ui/webui/resources/mojo:library",
   ]
-
-  deps = [ "//third_party/polymer/v3_0:library" ]
-  extra_deps += [
-    ":preprocess",
-    "js:build_ts",
-    "mojo:library",
-  ]
-}
-
-generate_grd("build_ts_grdp") {
-  grd_prefix = "webui"
-  out_grd = "$target_gen_dir/resources_ts.grdp"
-  public_deps = [ ":library" ]
-  manifest_files =
-      filter_include(get_target_outputs(":library"), [ "*.manifest" ])
 }
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index 9de29c78..48a5cc75 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -3,66 +3,117 @@
 # found in the LICENSE file.
 
 import("//build/config/chromeos/ui_mode.gni")
-import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/css_to_wrapper.gni")
-import("//tools/polymer/html_to_wrapper.gni")
 import("//ui/webui/resources/include_polymer.gni")
-import("//ui/webui/webui_features.gni")
-import("./cr_elements.gni")
 
-preprocess_folder = "$root_gen_dir/ui/webui/resources/preprocessed/cr_elements"
+import("../tools/build_cr_component.gni")
 
-group("preprocess") {
-  public_deps = [
-    ":html_wrapper_files_native",
-    ":preprocess_ts",
+build_cr_component("build") {
+  grd_prefix = "webui_cr_elements"
+
+  web_component_files = [
+    "cr_tab_box/cr_tab_box.ts",
+    "cr_tree/cr_tree.ts",
+    "cr_tree/cr_tree_item.ts",
+  ]
+
+  non_web_component_files = [
+    "cr_lazy_render/cr_lazy_render.ts",
+    "cr_splitter/cr_splitter.ts",
+    "cr_tree/cr_tree_base.ts",
   ]
 
   if (include_polymer) {
-    public_deps += [
-      ":css_wrapper_files",
-      ":html_wrapper_files",
+    web_component_files += [
+      "cr_a11y_announcer/cr_a11y_announcer.ts",
+      "cr_action_menu/cr_action_menu.ts",
+      "cr_button/cr_button.ts",
+      "cr_checkbox/cr_checkbox.ts",
+      "cr_dialog/cr_dialog.ts",
+      "cr_drawer/cr_drawer.ts",
+      "cr_expand_button/cr_expand_button.ts",
+      "cr_fingerprint/cr_fingerprint_progress_arc.ts",
+      "cr_grid/cr_grid.ts",
+      "cr_icon_button/cr_icon_button.ts",
+      "cr_input/cr_input.ts",
+      "cr_link_row/cr_link_row.ts",
+      "cr_lottie/cr_lottie.ts",
+      "cr_textarea/cr_textarea.ts",
+      "cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts",
+      "cr_profile_avatar_selector/cr_profile_avatar_selector.ts",
+      "cr_radio_button/cr_card_radio_button.ts",
+      "cr_radio_button/cr_radio_button.ts",
+      "cr_radio_group/cr_radio_group.ts",
+      "cr_search_field/cr_search_field.ts",
+      "cr_slider/cr_slider.ts",
+      "cr_tabs/cr_tabs.ts",
+      "cr_toast/cr_toast_manager.ts",
+      "cr_toast/cr_toast.ts",
+      "cr_toggle/cr_toggle.ts",
+      "cr_toolbar/cr_toolbar.ts",
+      "cr_toolbar/cr_toolbar_search_field.ts",
+      "cr_toolbar/cr_toolbar_selection_overlay.ts",
+      "cr_url_list_item/cr_url_list_item.ts",
+      "cr_view_manager/cr_view_manager.ts",
+      "policy/cr_policy_indicator.ts",
+      "policy/cr_policy_pref_indicator.ts",
+      "policy/cr_tooltip_icon.ts",
     ]
-  }
-}
 
-# TS files are passed to a separate target so that they are not listed in the
-# |out_manifest|.
-preprocess_if_expr("preprocess_ts") {
-  in_folder = "."
-  out_folder = preprocess_folder
-  in_files =
-      web_component_files_native + native_html_files + non_web_component_files
-  if (include_polymer) {
-    in_files += web_component_files_polymer + polymer_html_files +
-                icons_html_files + css_files
-  }
-}
+    if (is_chromeos) {
+      web_component_files +=
+          [ "cr_searchable_drop_down/cr_searchable_drop_down.ts" ]
+    }
 
-html_to_wrapper("html_wrapper_files_native") {
-  deps = [ ":preprocess_ts" ]
-  in_folder = preprocess_folder
-  out_folder = preprocess_folder
-  in_files = native_html_files
-  minify = optimize_webui
-  template = "native"
-}
+    icons_html_files = [
+      "cr_fingerprint/cr_fingerprint_icons.html",
+      "icons.html",
+      "mwb_shared_icons.html",
+    ]
 
-if (include_polymer) {
-  html_to_wrapper("html_wrapper_files") {
-    deps = [ ":preprocess_ts" ]
-    in_folder = preprocess_folder
-    out_folder = preprocess_folder
-    in_files = polymer_html_files + icons_html_files
-    scheme = "relative"
-    minify = optimize_webui
+    non_web_component_files += [
+      "cr_auto_img/cr_auto_img.ts",
+      "cr_container_shadow_mixin.ts",
+      "cr_menu_selector/cr_menu_selector.ts",
+      "cr_radio_button/cr_radio_button_mixin.ts",
+      "cr_scrollable_mixin.ts",
+      "cr_search_field/cr_search_field_mixin.ts",
+      "find_shortcut_mixin.ts",
+      "i18n_mixin.ts",
+      "list_property_update_mixin.ts",
+      "mouse_hoverable_mixin.ts",
+      "policy/cr_policy_indicator_mixin.ts",
+      "web_ui_listener_mixin.ts",
+    ]
+
+    css_files = [
+      "action_link.css",
+      "cr_actionable_row_style.css",
+      "cr_hidden_style.css",
+      "cr_icons.css",
+      "cr_nav_menu_item_style.css",
+      "cr_page_host_style.css",
+      "cr_radio_button/cr_radio_button_style.css",
+      "cr_shared_style.css",
+      "cr_shared_vars.css",
+      "md_select.css",
+      "mwb_element_shared_style.css",
+      "mwb_shared_style.css",
+      "mwb_shared_vars.css",
+      "search_highlight_style.css",
+      "cr_input/cr_input_style.css",
+    ]
+
+    if (is_chromeos_ash) {
+      css_files += [ "chromeos/cros_color_overrides.css" ]
+    }
   }
 
-  css_to_wrapper("css_wrapper_files") {
-    deps = [ ":preprocess_ts" ]
-    in_folder = preprocess_folder
-    out_folder = preprocess_folder
-    in_files = css_files
-    minify = optimize_webui
-  }
+  html_to_wrapper_template = "detect"
+
+  tsc_dir = "$root_gen_dir/ui/webui/resources/preprocessed/cr_elements"
+  ts_deps = [ "../js:build_ts" ]
+  ts_definitions = [
+    "//tools/typescript/definitions/pending.d.ts",
+    "//tools/typescript/definitions/settings_private.d.ts",
+  ]
 }
diff --git a/ui/webui/resources/cr_elements/cr_elements.gni b/ui/webui/resources/cr_elements/cr_elements.gni
deleted file mode 100644
index e06ea43..0000000
--- a/ui/webui/resources/cr_elements/cr_elements.gni
+++ /dev/null
@@ -1,160 +0,0 @@
-# Copyright 2022 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/chromeos/ui_mode.gni")
-import("//ui/webui/resources/include_polymer.gni")
-
-# TS files holding a non-Polymer element definition and have an equivalent .html
-# file.
-web_component_files_native = [
-  "cr_tab_box/cr_tab_box.ts",
-  "cr_tree/cr_tree.ts",
-  "cr_tree/cr_tree_item.ts",
-]
-
-# Files that are passed as input to html_to_wrapper().
-native_html_files = []
-foreach(f, web_component_files_native) {
-  native_html_files += [ string_replace(f, ".ts", ".html") ]
-}
-
-# Files that are generated by html_to_wrapper().
-native_html_wrapper_files = []
-foreach(f, native_html_files) {
-  native_html_wrapper_files += [ f + ".ts" ]
-}
-
-if (include_polymer) {
-  # TS files holding a Polymer element definition and have an equivalent .html
-  # file.
-  web_component_files_polymer = [
-    "cr_a11y_announcer/cr_a11y_announcer.ts",
-    "cr_action_menu/cr_action_menu.ts",
-    "cr_button/cr_button.ts",
-    "cr_checkbox/cr_checkbox.ts",
-    "cr_dialog/cr_dialog.ts",
-    "cr_drawer/cr_drawer.ts",
-    "cr_expand_button/cr_expand_button.ts",
-    "cr_fingerprint/cr_fingerprint_progress_arc.ts",
-    "cr_grid/cr_grid.ts",
-    "cr_icon_button/cr_icon_button.ts",
-    "cr_input/cr_input.ts",
-    "cr_link_row/cr_link_row.ts",
-    "cr_lottie/cr_lottie.ts",
-    "cr_textarea/cr_textarea.ts",
-    "cr_profile_avatar_selector/cr_profile_avatar_selector_grid.ts",
-    "cr_profile_avatar_selector/cr_profile_avatar_selector.ts",
-    "cr_radio_button/cr_card_radio_button.ts",
-    "cr_radio_button/cr_radio_button.ts",
-    "cr_radio_group/cr_radio_group.ts",
-    "cr_search_field/cr_search_field.ts",
-    "cr_slider/cr_slider.ts",
-    "cr_tabs/cr_tabs.ts",
-    "cr_toast/cr_toast_manager.ts",
-    "cr_toast/cr_toast.ts",
-    "cr_toggle/cr_toggle.ts",
-    "cr_toolbar/cr_toolbar.ts",
-    "cr_toolbar/cr_toolbar_search_field.ts",
-    "cr_toolbar/cr_toolbar_selection_overlay.ts",
-    "cr_url_list_item/cr_url_list_item.ts",
-    "cr_view_manager/cr_view_manager.ts",
-    "policy/cr_policy_indicator.ts",
-    "policy/cr_policy_pref_indicator.ts",
-    "policy/cr_tooltip_icon.ts",
-  ]
-
-  if (is_chromeos) {
-    web_component_files_polymer +=
-        [ "cr_searchable_drop_down/cr_searchable_drop_down.ts" ]
-  }
-
-  icons_html_files = [
-    "cr_fingerprint/cr_fingerprint_icons.html",
-    "icons.html",
-    "mwb_shared_icons.html",
-  ]
-
-  # Polymer HTML files that are passed as input to html_to_wrapper().
-  polymer_html_files = []
-  foreach(f, web_component_files_polymer) {
-    polymer_html_files += [ string_replace(f, ".ts", ".html") ]
-  }
-
-  # Files that are generated by html_to_wrapper().
-  polymer_html_wrapper_files = []
-  foreach(f, polymer_html_files + icons_html_files) {
-    polymer_html_wrapper_files += [ f + ".ts" ]
-  }
-}
-
-# Files that either dont hold a custom element definition or the custom element
-# does not have an equivalent .html file.
-non_web_component_files = [
-  "cr_lazy_render/cr_lazy_render.ts",
-  "cr_splitter/cr_splitter.ts",
-  "cr_tree/cr_tree_base.ts",
-]
-
-if (include_polymer) {
-  non_web_component_files += [
-    "cr_auto_img/cr_auto_img.ts",
-    "cr_container_shadow_mixin.ts",
-    "cr_menu_selector/cr_menu_selector.ts",
-    "cr_radio_button/cr_radio_button_mixin.ts",
-    "cr_scrollable_mixin.ts",
-    "cr_search_field/cr_search_field_mixin.ts",
-    "find_shortcut_mixin.ts",
-    "i18n_mixin.ts",
-    "list_property_update_mixin.ts",
-    "mouse_hoverable_mixin.ts",
-    "policy/cr_policy_indicator_mixin.ts",
-    "web_ui_listener_mixin.ts",
-  ]
-
-  # Files that are passed as input to css_to_wrapper().
-  css_files = [
-    "action_link.css",
-    "cr_actionable_row_style.css",
-    "cr_hidden_style.css",
-    "cr_icons.css",
-    "cr_nav_menu_item_style.css",
-    "cr_page_host_style.css",
-    "cr_radio_button/cr_radio_button_style.css",
-    "cr_shared_style.css",
-    "cr_shared_vars.css",
-    "md_select.css",
-    "mwb_element_shared_style.css",
-    "mwb_shared_style.css",
-    "mwb_shared_vars.css",
-    "search_highlight_style.css",
-    "cr_input/cr_input_style.css",
-  ]
-
-  if (is_chromeos_ash) {
-    css_files += [ "chromeos/cros_color_overrides.css" ]
-  }
-
-  # Files that are generated by css_to_wrapper().
-  css_wrapper_files = []
-  foreach(f, css_files) {
-    css_wrapper_files += [ f + ".ts" ]
-  }
-}
-
-# List of all files above with the "cr_elements/" prefix to be used in a parent
-# BUILD.gn file.
-cr_elements_files = []
-foreach(f,
-        web_component_files_native + native_html_wrapper_files +
-            non_web_component_files) {
-  cr_elements_files += [ "cr_elements/" + f ]
-}
-
-if (include_polymer) {
-  foreach(f,
-          web_component_files_polymer + polymer_html_wrapper_files +
-              css_wrapper_files) {
-    cr_elements_files += [ "cr_elements/" + f ]
-  }
-}
diff --git a/ui/webui/resources/cr_elements/cr_nav_menu_item_style.css b/ui/webui/resources/cr_elements/cr_nav_menu_item_style.css
index 037d755..0ada293d2 100644
--- a/ui/webui/resources/cr_elements/cr_nav_menu_item_style.css
+++ b/ui/webui/resources/cr_elements/cr_nav_menu_item_style.css
@@ -4,7 +4,7 @@
 
 /* #css_wrapper_metadata_start
  * #type=style
- * #import=chrome://resources/cr_elements/cr_shared_vars.css.js
+ * #import=./cr_shared_vars.css.js
  * #css_wrapper_metadata_end */
 
 .cr-nav-menu-item {
diff --git a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_mixin.ts b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_mixin.ts
index 915a00fb..f95d04e 100644
--- a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_mixin.ts
+++ b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_mixin.ts
@@ -6,10 +6,11 @@
  * Helper functions for implementing an incremental search field. See
  * <settings-subpage-search> for a simple implementation.
  */
-import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
 import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
 import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {CrInputElement} from '../cr_input/cr_input.js';
+
 
 type Constructor<T> = new (...args: any[]) => T;
 
diff --git a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts
index 083cd62..1f2785d 100644
--- a/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts
+++ b/ui/webui/resources/cr_elements/cr_url_list_item/cr_url_list_item.ts
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '//resources/cr_elements/cr_icons.css.js';
-import '//resources/cr_elements/cr_shared_vars.css.js';
+import '../cr_icons.css.js';
+import '../cr_shared_vars.css.js';
 
 import {getFaviconForPageURL} from '//resources/js/icon.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {MouseHoverableMixin} from 'chrome://resources/cr_elements/mouse_hoverable_mixin.js';
 import {assert} from 'chrome://resources/js/assert_ts.js';
 
+import {MouseHoverableMixin} from '../mouse_hoverable_mixin.js';
+
 import {getTemplate} from './cr_url_list_item.html.js';
 
 export enum CrUrlListItemSize {
diff --git a/ui/webui/resources/cr_elements/tsconfig_base.json b/ui/webui/resources/cr_elements/tsconfig_base.json
new file mode 100644
index 0000000..de14880
--- /dev/null
+++ b/ui/webui/resources/cr_elements/tsconfig_base.json
@@ -0,0 +1,7 @@
+{
+  "extends": "../../../../tools/typescript/tsconfig_base.json",
+  "compilerOptions": {
+    "noUnusedLocals": false,
+    "strictPropertyInitialization": false
+  }
+}
diff --git a/ui/webui/resources/tools/build_cr_component.gni b/ui/webui/resources/tools/build_cr_component.gni
index d2323b6a..0cfcc96a 100644
--- a/ui/webui/resources/tools/build_cr_component.gni
+++ b/ui/webui/resources/tools/build_cr_component.gni
@@ -146,6 +146,7 @@
       in_folder = preprocess_dir
       out_folder = preprocess_dir
       in_files = html_files
+      scheme = "relative"
       minify = optimize
 
       if (defined(invoker.html_to_wrapper_template)) {