diff --git a/DEPS b/DEPS
index 408c38f..2e29d86 100644
--- a/DEPS
+++ b/DEPS
@@ -276,11 +276,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '3ce4702c33df16bb3cc2619173d8f80639872707',
+  'src_internal_revision': '07d1b817873ca3c81870063eceec46298d475541',
   # 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': '3531a78f28898e41d4180d2094e3ecf2e55bea0e',
+  'skia_revision': '539c311a3a7fa76bf50a9c83822815abdb825a18',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -328,7 +328,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '1400b20ae8683315f53f00b6c3707fc64faeaa7b',
+  'freetype_revision': 'f219996754c4df75b758983e18cabb401e5b93a1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -352,7 +352,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': 'a3f542676a2b8ff19db3e41192e7c867f16ed8bb',
+  'chromium_variations_revision': '91db0dddd20500f927076d7309ab54d3b3909344',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -372,7 +372,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': 'e79621229ef59e11bc5859d82a765892b2a5979c',
+  'devtools_frontend_revision': '40f57f86c54cd8b5c06878c0a7301bce9d4b0dbf',
   # 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.
@@ -396,7 +396,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': '777987d6d109a1632a0a413eca952cf6902e09fb',
+  'dawn_revision': '46d1e23d9ee5fdf648359b7b3e3f9caa5eafac68',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -496,7 +496,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    'b9f74ba96d2f3a088e6a38fc1f3331e1aa62b637',
+  'llvm_libc_revision':    '597b2e8c42ef95d1996a3d3713cddac269c68b50',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
@@ -1110,7 +1110,7 @@
   },
 
   'src/chrome/release_scripts': {
-      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + '2d23cdc03824f73a4fce61d34cbbe9828e56b962',
+      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + 'b37cf13dae4ea8bdbff22cee2b4820c94c83bab8',
       'condition': 'checkout_chrome_release_scripts',
   },
 
@@ -1439,12 +1439,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'c6c9102b9d6c333bc6d52b2fd31c27d92f06b088',
+    '2a16411ff60d055cb1def36b935da824fd6ce71a',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'cfc3c3cbd1b88b84ebecbf11e57faf79c2530e7f',
+    'url': Var('chromium_git') + '/website.git' + '@' + 'fb143e8ce76fcf5f67792fbbd6c219c5d03ec2d9',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1669,7 +1669,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/error_prone',
-               'version': 'a-wq097LhH9krgIuF0T5waFnHU4KilRItqhJPGFZxtwC',
+               'version': '7c91BXn6VPvSmr-dFRYaNVkfHjRN1jdMIN4EcrPem9cC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1702,7 +1702,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'UGF3GC1qR9jeALurBm6PNVfQT1TNc-yqDjT4pEpuiYsC',
+               'version': 'osgd04hyZB3eu5L7oiL6irk9AqRBX9lOxNLsaCmUCowC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1934,7 +1934,7 @@
 
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6cbd7a824340c50ef1aa5cdddf94e14114ade41f',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a912cd245b093ea57a187ca66665ca98090a82fd',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1943,7 +1943,7 @@
     Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '24e0c2a125d2b37b35719124d1f758777c150ca8',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '7bb23b1e360e22a395eef75061565fc079ae6a85',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@@ -2176,7 +2176,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'uguVAY3NvbfV4KgHrjjwvtTioMwPwSijfAgBPpbaYk0C',
+              'version': 'rR6d6Pj-PTodfgswJ661KwgKAuHXYKAhifnuXpoo748C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2436,7 +2436,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e324242074e2e64a65e90a2933afd3ca4413554f',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c6ea87b5b19e6b2798f290b000bb3609c9018c81',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2573,7 +2573,7 @@
     Var('chromium_git') + '/external/github.com/protocolbuffers/protobuf-javascript' + '@' + 'e34549db516f8712f678fcd4bc411613b5cc5295',
 
   'src/third_party/pthreadpool/src':
-    Var('chromium_git') + '/external/github.com/Maratyszcza/pthreadpool.git' + '@' + '560c60d342a76076f0557a3946924c6478470044',
+    Var('chromium_git') + '/external/github.com/google/pthreadpool.git' + '@' + 'b4fb4eb1668c7d976cdaa941b135a02462adb460',
 
   # Dependency of skia.
   'src/third_party/pyelftools': {
@@ -2656,7 +2656,7 @@
   },
 
   'src/third_party/ruy/src':
-    Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '95484c3e02206f73309c08ee5ee23d2304ca092b',
+    Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '83fd40d730feb0804fafbc2d8814bcc19a17b2e5',
 
   'src/third_party/skia':
     Var('skia_git') + '/skia.git' + '@' +  Var('skia_revision'),
@@ -2739,7 +2739,7 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'b25df276c8e912c22f57263ffcae6ca8f4c64342',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'b7bed6cb1d5eeebd81324b60d8bd624b9124ef5b',
 
   'src/third_party/turbine/cipd': {
       'packages': [
@@ -2752,16 +2752,16 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@8540477b5d951bf001cb55fd57dae8dac8974000',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@8d2a13cc437488e3dafc128371e0fb78cd1a216b',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@e43514866f7e0f8265c677039d2fe773c892d44b',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@a380cd25433092dbce9a455a3feb1242138febee',
-  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@31c154a2a68a2efad82d372b957b42c6b51c1585',
+  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@9064fe8637daf9f694c8a2e035a34da94022f2be',
   'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@d4a196d8c84e032d27f999adcea3075517c1c97f',
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@369f59ad598b60d6ed9f553af651c5cccd20234c',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@315964ad5aabd5b148a484e5fbea8a365c8d1eb3',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@5a88b6042edb8f03eefc8de73bd73a899989373f',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@10f90cce65ba16710a0a2900749008aa0767749e',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@ea05bf71f2948d64f7d36651ffcad59216401095',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2800,13 +2800,13 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '450cceb587613ac1469c5a131fac15935c99e0e7',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3dd1feca3b4bf0c6223a6a732d5b7db79a6cf95b',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3d039b4adaba9163659becb0af593a9a9a6f8069',
 
   'src/third_party/webpagereplay':
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'f94bddf72cefe1abd30b54474d774ff08dfd181e',
+    Var('webrtc_git') + '/src.git' + '@' + 'd8135eb75b7ed9544c6b41732c8fd5640514d565',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -2837,7 +2837,7 @@
   },
 
   'src/third_party/xnnpack/src':
-    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '7440eee88f66c4b81d4e7d31f6ae07af66e059ea',
+    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '0824e2965f6edc2297e55c8dff5a8ac4cb12aaad',
 
   'src/third_party/libei/cipd': {
 
@@ -2932,7 +2932,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_app/app',
-        'version': 'eIsUtdJm7i6ojGWlaMeLBt_Rq5w3eFBpu3OdmRtr3mYC',
+        'version': 'waXRDqwwLQKvPqABrqULEhbPQOZVfphzzbClpeg5tU4C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2987,7 +2987,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'HX21RbdumtVXLiUyHl-18JqiOBAoNPZHBEqE5a7ziU4C',
+        'version': 'MSHT5g8mGz8hw9PuIVbZzV0bUFpNer8ByMgqWmkhIKkC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4545,7 +4545,7 @@
 
   'src/components/autofill/core/browser/form_parsing/internal_resources': {
       'url': Var('chrome_git') + '/chrome/components/autofill_regex_patterns.git' + '@' +
-        '6672b4874e193fd6790f6c9ce6c78a1c2195208b',
+        'd74d93ad9bc077c106419510e7aa08fa5d618cf1',
       'condition': 'checkout_src_internal',
   },
 
@@ -4634,7 +4634,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '7ef8f19635a1aab0f89f14854cc7732534811bc3',
+        '728f2050ecc1547009c1ec095855a100e6554117',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0d8f1e0f..e1246e38 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -421,6 +421,8 @@
     "calendar/calendar_controller.h",
     "cancel_mode.cc",
     "cancel_mode.h",
+    "capture_mode/action_button_container_view.cc",
+    "capture_mode/action_button_container_view.h",
     "capture_mode/action_button_view.cc",
     "capture_mode/action_button_view.h",
     "capture_mode/base_capture_mode_session.cc",
@@ -3815,6 +3817,7 @@
     "bubble//simple_grid_layout_unittest.cc",
     "bubble/bubble_event_filter_unittest.cc",
     "bubble/bubble_utils_unittest.cc",
+    "capture_mode/action_button_container_view_unittest.cc",
     "capture_mode/action_button_view_unittest.cc",
     "capture_mode/capture_audio_mixing_unittests.cc",
     "capture_mode/capture_mode_camera_unittests.cc",
diff --git a/ash/annotator/annotation_tray.cc b/ash/annotator/annotation_tray.cc
index eca23bd..a6a95630 100644
--- a/ash/annotator/annotation_tray.cc
+++ b/ash/annotator/annotation_tray.cc
@@ -263,8 +263,8 @@
       SkColorSetA(AshColorProvider::Get()->GetContentLayerColor(
                       AshColorProvider::ContentLayerType::kIconColorPrimary),
                   0x4D);
-  image_view_->SetImage(gfx::CreateVectorIcon(kPaletteTrayIconProjectorIcon,
-                                              disabled_icon_color));
+  image_view_->SetImage(ui::ImageModel::FromVectorIcon(
+      kPaletteTrayIconProjectorIcon, disabled_icon_color));
   image_view_->SetTooltipText(l10n_util::GetStringUTF16(
       IDS_ASH_STATUS_AREA_PROJECTOR_ANNOTATION_TRAY_UNAVAILABLE));
 }
diff --git a/ash/capture_mode/action_button_container_view.cc b/ash/capture_mode/action_button_container_view.cc
new file mode 100644
index 0000000..d7b0828
--- /dev/null
+++ b/ash/capture_mode/action_button_container_view.cc
@@ -0,0 +1,208 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/capture_mode/action_button_container_view.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "ash/capture_mode/action_button_view.h"
+#include "ash/capture_mode/capture_mode_types.h"
+#include "base/check.h"
+#include "base/functional/bind.h"
+#include "base/ranges/algorithm.h"
+#include "base/time/time.h"
+#include "ui/aura/window.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/views/animation/animation_builder.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view.h"
+#include "ui/views/view_utils.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+// The horizontal distance between action buttons in a row.
+constexpr int kActionButtonSpacing = 10;
+
+// The animation duration for fading out old action buttons after the smart
+// actions button is pressed.
+constexpr base::TimeDelta kSmartActionsButtonTransitionFadeOutDuration =
+    base::Milliseconds(100);
+
+// The animation duration for fading in new icon buttons after the smart actions
+// button is pressed.
+constexpr base::TimeDelta kSmartActionsButtonTransitionFadeInDuration =
+    base::Milliseconds(50);
+
+// The animation duration for sliding in new icon buttons after the smart
+// actions button is pressed.
+constexpr base::TimeDelta kSmartActionsButtonTransitionSlideInDuration =
+    base::Milliseconds(250);
+
+}  // namespace
+
+ActionButtonContainerView::ActionButtonContainerView() {
+  auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kHorizontal));
+  box_layout->set_between_child_spacing(kActionButtonSpacing);
+  box_layout->set_main_axis_alignment(
+      views::BoxLayout::MainAxisAlignment::kCenter);
+  box_layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kStretch);
+}
+
+ActionButtonContainerView::~ActionButtonContainerView() = default;
+
+ActionButtonView* ActionButtonContainerView::AddActionButton(
+    views::Button::PressedCallback callback,
+    std::u16string text,
+    const gfx::VectorIcon* icon,
+    ActionButtonRank rank,
+    ActionButtonViewID id) {
+  // Collect the existing buttons and newly requested button, and sort them by
+  // rank.
+  std::vector<std::unique_ptr<ActionButtonView>> action_buttons;
+
+  // Populate `action_buttons` with the existing action buttons, if any. We need
+  // to copy the vector of `children()` as we will be removing buttons from the
+  // original.
+  views::View::Views children_copy = children();
+  for (views::View* action_button : children_copy) {
+    CHECK(action_button);
+    action_buttons.push_back(
+        RemoveChildViewT(views::AsViewClass<ActionButtonView>(action_button)));
+  }
+
+  CHECK(children().empty());
+
+  // Add the new action button to the vector so it can also be sorted.
+  auto new_action_button =
+      std::make_unique<ActionButtonView>(std::move(callback), text, icon, rank);
+  new_action_button->SetID(id);
+  ActionButtonView* new_action_button_ptr = new_action_button.get();
+  action_buttons.push_back(std::move(new_action_button));
+
+  // Sort the buttons by rank.
+  auto rank_sort = [](const std::unique_ptr<ActionButtonView>& lhs,
+                      const std::unique_ptr<ActionButtonView>& rhs) {
+    return lhs->rank() < rhs->rank();
+  };
+  sort(action_buttons.begin(), action_buttons.end(), rank_sort);
+
+  // Re-insert the buttons into the container view in sorted order from highest
+  // to lowest. Higher ranked buttons should appear to the right of lower ranked
+  // buttons, so insert new buttons on the left.
+  for (std::unique_ptr<ActionButtonView>& action_button : action_buttons) {
+    AddChildView(std::move(action_button));
+  }
+
+  return new_action_button_ptr;
+}
+
+void ActionButtonContainerView::StartSmartActionsButtonTransition() {
+  views::Widget* widget = GetWidget();
+  if (!widget) {
+    return;
+  }
+
+  SetWidgetEventsEnabled(false);
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnEnded(base::BindOnce(
+          &ActionButtonContainerView::OnSmartActionsButtonFadedOut,
+          weak_ptr_factory_.GetWeakPtr()))
+      .Once()
+      .SetDuration(kSmartActionsButtonTransitionFadeOutDuration)
+      .SetOpacity(widget->GetLayer(), 0.0f, gfx::Tween::LINEAR);
+}
+
+void ActionButtonContainerView::OnSmartActionsButtonFadedOut() {
+  views::Widget* widget = GetWidget();
+  if (!widget) {
+    return;
+  }
+
+  // Remove Scanner action buttons and keep other buttons. We need to copy
+  // `children()` since we will be removing buttons from the original vector.
+  std::vector<std::unique_ptr<ActionButtonView>> action_buttons_to_keep;
+  views::View::Views children_copy = children();
+  for (views::View* child : children_copy) {
+    auto action_button =
+        RemoveChildViewT(views::AsViewClass<ActionButtonView>(child));
+    if (action_button->rank().type != ActionButtonType::kScanner) {
+      action_buttons_to_keep.push_back(std::move(action_button));
+    }
+  }
+  CHECK(children().empty());
+
+  // Add the buttons to keep back into the action button container and
+  // collapse them into icon buttons.
+  for (std::unique_ptr<ActionButtonView>& action_button :
+       action_buttons_to_keep) {
+    action_button->CollapseToIconButton();
+    AddChildView(std::move(action_button));
+  }
+
+  // Compute bounds required to slide in the new icon buttons from the left edge
+  // of the old action container bounds to the right edge.
+  const gfx::Rect old_action_container_bounds =
+      widget->GetWindowBoundsInScreen();
+  const gfx::Size new_preferred_size = GetPreferredSize();
+  const gfx::Vector2d slide_offset(
+      old_action_container_bounds.width() - new_preferred_size.width(), 0);
+
+  // Set the target bounds at the right edge.
+  widget->SetBounds(gfx::Rect(
+      old_action_container_bounds.origin() + slide_offset, new_preferred_size));
+
+  // Set an initial translation so that the new icon buttons start sliding from
+  // the left edge.
+  gfx::Transform initial_translation;
+  initial_translation.Translate(-slide_offset);
+  ui::Layer* layer = widget->GetLayer();
+  layer->SetTransform(initial_translation);
+
+  views::AnimationBuilder()
+      .SetPreemptionStrategy(
+          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
+      .OnEnded(
+          base::BindOnce(&ActionButtonContainerView::SetWidgetEventsEnabled,
+                         weak_ptr_factory_.GetWeakPtr(), true))
+      .Once()
+      .SetDuration(kSmartActionsButtonTransitionFadeInDuration)
+      .SetOpacity(layer, 1.0f, gfx::Tween::LINEAR)
+      .At(base::TimeDelta())
+      .SetDuration(kSmartActionsButtonTransitionSlideInDuration)
+      .SetTransform(layer, gfx::Transform(), gfx::Tween::ACCEL_LIN_DECEL_100);
+}
+
+void ActionButtonContainerView::SetWidgetEventsEnabled(bool enabled) {
+  views::Widget* widget = GetWidget();
+  if (!widget) {
+    return;
+  }
+  widget->GetContentsView()->SetCanProcessEventsWithinSubtree(enabled);
+  widget->GetNativeWindow()->SetEventTargetingPolicy(
+      enabled ? aura::EventTargetingPolicy::kTargetAndDescendants
+              : aura::EventTargetingPolicy::kNone);
+}
+
+BEGIN_METADATA(ActionButtonContainerView)
+END_METADATA
+
+}  // namespace ash
diff --git a/ash/capture_mode/action_button_container_view.h b/ash/capture_mode/action_button_container_view.h
new file mode 100644
index 0000000..41f2e29
--- /dev/null
+++ b/ash/capture_mode/action_button_container_view.h
@@ -0,0 +1,65 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_CAPTURE_MODE_ACTION_BUTTON_CONTAINER_VIEW_H_
+#define ASH_CAPTURE_MODE_ACTION_BUTTON_CONTAINER_VIEW_H_
+
+#include <string>
+
+#include "ash/ash_export.h"
+#include "ash/capture_mode/capture_mode_types.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace gfx {
+struct VectorIcon;
+}  // namespace gfx
+
+namespace ash {
+
+class ActionButtonView;
+
+// A view that displays a row of action buttons near the capture region.
+class ASH_EXPORT ActionButtonContainerView : public views::View {
+  METADATA_HEADER(ActionButtonContainerView, views::View)
+
+ public:
+  ActionButtonContainerView();
+  ActionButtonContainerView(const ActionButtonContainerView&) = delete;
+  ActionButtonContainerView& operator=(const ActionButtonContainerView&) =
+      delete;
+  ~ActionButtonContainerView() override;
+
+  // Adds an action button to the container. Returns a pointer to the added
+  // button.
+  // TODO(crbug.com/372740410): Determine behavior when we add a button with the
+  // exact same rank (type and priority) as an existing valid button.
+  ActionButtonView* AddActionButton(views::Button::PressedCallback callback,
+                                    std::u16string text,
+                                    const gfx::VectorIcon* icon,
+                                    ActionButtonRank rank,
+                                    ActionButtonViewID id);
+
+  // Starts performing the button transition triggered after pressing the smart
+  // actions button. This will fade out existing action buttons, remove the
+  // smart actions button, then animate in new icon buttons to replace the old
+  // copy text and search buttons.
+  void StartSmartActionsButtonTransition();
+
+ private:
+  // Called when the smart actions button has faded out, to start the transition
+  // to new buttons. See `StartSmartActionsButtonTransition()`.
+  void OnSmartActionsButtonFadedOut();
+
+  // Enables or disables events on the action button container widget.
+  void SetWidgetEventsEnabled(bool enabled);
+
+  base::WeakPtrFactory<ActionButtonContainerView> weak_ptr_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_CAPTURE_MODE_ACTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/capture_mode/action_button_container_view_unittest.cc b/ash/capture_mode/action_button_container_view_unittest.cc
new file mode 100644
index 0000000..3961313
--- /dev/null
+++ b/ash/capture_mode/action_button_container_view_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/capture_mode/action_button_container_view.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/capture_mode/action_button_view.h"
+#include "ash/capture_mode/capture_mode_types.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/test/view_drawn_waiter.h"
+#include "base/test/test_future.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
+
+namespace ash {
+namespace {
+
+using ::testing::ElementsAre;
+
+// Returns true if `action_button` is collapsed (i.e. label hidden, only icon
+// visible).
+bool IsActionButtonCollapsed(const ActionButtonView* action_button) {
+  return !action_button->label_for_testing()->GetVisible();
+}
+
+using ActionButtonContainerViewTest = views::ViewsTestBase;
+
+TEST_F(ActionButtonContainerViewTest, AddsActionButton) {
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
+  widget->SetBounds(gfx::Rect(50, 50, 300, 200));
+  widget->Show();
+  auto* action_button_container =
+      widget->SetContentsView(std::make_unique<ActionButtonContainerView>());
+  base::test::TestFuture<void> action_future;
+
+  ActionButtonView* action_button = action_button_container->AddActionButton(
+      action_future.GetCallback(), u"Button Text", &kCaptureModeImageIcon,
+      ActionButtonRank(ActionButtonType::kScanner, 0),
+      ActionButtonViewID::kScannerButton);
+
+  // Check that the action button has been successfully created.
+  ASSERT_TRUE(action_button);
+  EXPECT_THAT(action_button_container->children(), ElementsAre(action_button));
+  EXPECT_EQ(action_button->label_for_testing()->GetText(), u"Button Text");
+
+  // Check that clicking the action button runs the action callback.
+  ViewDrawnWaiter().Wait(action_button);
+  ui::test::EventGenerator event_generator(GetRootWindow(widget.get()));
+  event_generator.MoveMouseTo(action_button->GetBoundsInScreen().CenterPoint());
+  event_generator.ClickLeftButton();
+
+  EXPECT_TRUE(action_future.Wait());
+}
+
+TEST_F(ActionButtonContainerViewTest, ActionButtonsOrderedByRank) {
+  ActionButtonContainerView action_button_container;
+
+  ActionButtonView* copy_text_button = action_button_container.AddActionButton(
+      views::Button::PressedCallback(), u"Copy Text", &kCaptureModeImageIcon,
+      ActionButtonRank(ActionButtonType::kCopyText, 0),
+      ActionButtonViewID::kCopyTextButton);
+  ActionButtonView* search_button = action_button_container.AddActionButton(
+      views::Button::PressedCallback(), u"Search Button",
+      &kCaptureModeImageIcon, ActionButtonRank(ActionButtonType::kSunfish, 0),
+      ActionButtonViewID::kSearchButton);
+  ActionButtonView* scanner_button = action_button_container.AddActionButton(
+      views::Button::PressedCallback(), u"Scanner Button",
+      &kCaptureModeImageIcon, ActionButtonRank(ActionButtonType::kScanner, 0),
+      ActionButtonViewID::kScannerButton);
+
+  EXPECT_THAT(action_button_container.children(),
+              ElementsAre(scanner_button, copy_text_button, search_button));
+}
+
+TEST_F(ActionButtonContainerViewTest, SmartActionsButtonTransition) {
+  ui::ScopedAnimationDurationScaleMode animation_scale(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
+  widget->SetBounds(gfx::Rect(50, 50, 300, 200));
+  widget->Show();
+  auto* action_button_container =
+      widget->SetContentsView(std::make_unique<ActionButtonContainerView>());
+  // Set up action buttons.
+  ActionButtonView* copy_text_button = action_button_container->AddActionButton(
+      views::Button::PressedCallback(), u"Copy Text", &kCaptureModeImageIcon,
+      ActionButtonRank(ActionButtonType::kCopyText, 0),
+      ActionButtonViewID::kCopyTextButton);
+  ActionButtonView* search_button = action_button_container->AddActionButton(
+      views::Button::PressedCallback(), u"Search", &kCaptureModeImageIcon,
+      ActionButtonRank(ActionButtonType::kSunfish, 0),
+      ActionButtonViewID::kSearchButton);
+  ActionButtonView* smart_actions_button =
+      action_button_container->AddActionButton(
+          views::Button::PressedCallback(), u"Smart Actions",
+          &kCaptureModeImageIcon,
+          ActionButtonRank(ActionButtonType::kScanner, 0),
+          ActionButtonViewID::kSmartActionsButton);
+  EXPECT_THAT(
+      action_button_container->children(),
+      ElementsAre(smart_actions_button, copy_text_button, search_button));
+
+  action_button_container->StartSmartActionsButtonTransition();
+
+  // The smart actions button should be removed and other buttons should be
+  // collapsed.
+  EXPECT_THAT(action_button_container->children(),
+              ElementsAre(copy_text_button, search_button));
+  EXPECT_TRUE(IsActionButtonCollapsed(copy_text_button));
+  EXPECT_TRUE(IsActionButtonCollapsed(search_button));
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index 7a64dd1f..6feafee9 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -11,6 +11,7 @@
 
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/accessibility/magnifier/magnifier_glass.h"
+#include "ash/capture_mode/action_button_container_view.h"
 #include "ash/capture_mode/action_button_view.h"
 #include "ash/capture_mode/capture_label_view.h"
 #include "ash/capture_mode/capture_mode_behavior.h"
@@ -96,7 +97,6 @@
 #include "ui/views/animation/animation_builder.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout_view.h"
 #include "ui/views/view_utils.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
@@ -203,27 +203,9 @@
 // value times the root window's width and height.
 constexpr float kRegionDefaultRatio = 0.24f;
 
-// The horizontal distance between action buttons in a row.
-constexpr int kActionButtonSpacing = 10;
-
 // The spacing between the feedback button and the work area.
 constexpr int kFeedbackButtonSpacing = 10;
 
-// The animation duration for fading out old action buttons after the smart
-// actions button is pressed.
-constexpr base::TimeDelta kSmartActionsButtonTransitionFadeOutDuration =
-    base::Milliseconds(100);
-
-// The animation duration for fading in new icon buttons after the smart actions
-// button is pressed.
-constexpr base::TimeDelta kSmartActionsButtonTransitionFadeInDuration =
-    base::Milliseconds(50);
-
-// The animation duration for sliding in new icon buttons after the smart
-// actions button is pressed.
-constexpr base::TimeDelta kSmartActionsButtonTransitionSlideInDuration =
-    base::Milliseconds(250);
-
 // The animation duration for fading in Scanner action buttons.
 constexpr base::TimeDelta kScannerActionButtonFadeInDuration =
     base::Milliseconds(100);
@@ -1387,8 +1369,6 @@
   return is_shutting_down_ ? nullptr : weak_token_factory_.GetWeakPtr();
 }
 
-// TODO(crbug.com/372740410): Determine behavior when we add a button with the
-// exact same rank (type and priority) as an existing valid button.
 ActionButtonView* CaptureModeSession::AddActionButton(
     views::Button::PressedCallback callback,
     std::u16string text,
@@ -1406,55 +1386,20 @@
     return nullptr;
   }
 
-  CHECK(action_container_view_);
-
   // If the user is shown an action button, they have successfully selected a
   // region and invoked a backend response, so there is no need to show the
   // nudge anymore.
   MaybeDismissSunfishRegionNudgeForever();
 
-  // Collect the existing buttons and newly requested button, and sort them by
-  // rank.
-  std::vector<std::unique_ptr<ActionButtonView>> action_buttons;
-
-  // Populate `action_buttons` with the existing action buttons, if any. We need
-  // to copy the vector of `children()` as we will be removing buttons from the
-  // original.
-  auto children = action_container_view_->children();
-  for (views::View* action_button : children) {
-    CHECK(action_button);
-    action_buttons.push_back(action_container_view_->RemoveChildViewT(
-        AsViewClass<ActionButtonView>(action_button)));
-  }
-
-  CHECK(action_container_view_->children().empty());
-
-  // Add the new action button to the vector so it can also be sorted.
-  auto new_action_button =
-      std::make_unique<ActionButtonView>(std::move(callback), text, icon, rank);
-  new_action_button->SetID(id);
-  CaptureModeSessionFocusCycler::HighlightHelper::Install(
-      new_action_button.get());
-  ActionButtonView* new_action_button_ptr = new_action_button.get();
-  action_buttons.push_back(std::move(new_action_button));
-
-  // Sort the buttons by rank.
-  auto rank_sort = [](const std::unique_ptr<ActionButtonView>& lhs,
-                      const std::unique_ptr<ActionButtonView>& rhs) {
-    return lhs->rank() < rhs->rank();
-  };
-  sort(action_buttons.begin(), action_buttons.end(), rank_sort);
-
-  // Re-insert the buttons into the container view in sorted order from highest
-  // to lowest. Higher ranked buttons should appear to the right of lower ranked
-  // buttons, so insert new buttons on the left.
-  for (std::unique_ptr<ActionButtonView>& action_button : action_buttons) {
-    action_container_view_->AddChildView(std::move(action_button));
-  }
+  CHECK(action_container_view_);
+  ActionButtonView* action_button = action_container_view_->AddActionButton(
+      std::move(callback), text, icon, rank, id);
+  CHECK(action_button);
+  CaptureModeSessionFocusCycler::HighlightHelper::Install(action_button);
 
   UpdateActionContainerWidget();
 
-  return new_action_button_ptr;
+  return action_button;
 }
 
 void CaptureModeSession::AddSmartActionsButton() {
@@ -1547,7 +1492,8 @@
 }
 
 void CaptureModeSession::OnSmartActionsButtonDisclaimerCheckSuccess() {
-  StartSmartActionsButtonTransition();
+  CHECK(action_container_view_);
+  action_container_view_->StartSmartActionsButtonTransition();
 
   // Fetch Scanner actions.
   auto* scanner_controller = Shell::Get()->scanner_controller();
@@ -3281,15 +3227,8 @@
     action_container_widget_->Init(
         CreateWidgetParams(parent, gfx::Rect(), "ActionButtonsContainer"));
 
-    action_container_widget_->SetContentsView(
-        views::Builder<views::BoxLayoutView>()
-            .CopyAddressTo(&action_container_view_)
-            .SetOrientation(views::BoxLayout::Orientation::kHorizontal)
-            .SetBetweenChildSpacing(kActionButtonSpacing)
-            .SetMainAxisAlignment(views::BoxLayout::MainAxisAlignment::kCenter)
-            .SetCrossAxisAlignment(
-                views::BoxLayout::CrossAxisAlignment::kStretch)
-            .Build());
+    action_container_view_ = action_container_widget_->SetContentsView(
+        std::make_unique<ActionButtonContainerView>());
   }
 
   action_container_widget_->Show();
@@ -3474,86 +3413,6 @@
   layer()->SchedulePaint(glow_bounds);
 }
 
-void CaptureModeSession::StartSmartActionsButtonTransition() {
-  SetActionContainerEventsEnabled(false);
-  views::AnimationBuilder()
-      .SetPreemptionStrategy(
-          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
-      .OnEnded(base::BindOnce(&CaptureModeSession::OnSmartActionsButtonFadedOut,
-                              weak_ptr_factory_.GetWeakPtr()))
-      .Once()
-      .SetDuration(kSmartActionsButtonTransitionFadeOutDuration)
-      .SetOpacity(action_container_widget_->GetLayer(), 0.0f,
-                  gfx::Tween::LINEAR);
-}
-
-void CaptureModeSession::OnSmartActionsButtonFadedOut() {
-  // Remove Scanner action buttons and keep other buttons. We need to copy
-  // `children()` since we will be removing buttons from the original vector.
-  std::vector<std::unique_ptr<ActionButtonView>> action_buttons_to_keep;
-  views::View::Views children = action_container_view_->children();
-  for (views::View* child : children) {
-    auto action_button = action_container_view_->RemoveChildViewT(
-        AsViewClass<ActionButtonView>(child));
-    if (action_button->rank().type != ActionButtonType::kScanner) {
-      action_buttons_to_keep.push_back(std::move(action_button));
-    }
-  }
-  CHECK(action_container_view_->children().empty());
-
-  // Add the buttons to keep back into the action button container and
-  // collapse them into icon buttons.
-  for (std::unique_ptr<ActionButtonView>& action_button :
-       action_buttons_to_keep) {
-    action_button->CollapseToIconButton();
-    action_container_view_->AddChildView(std::move(action_button));
-  }
-
-  // Compute bounds required to slide in the new icon buttons from the left edge
-  // of the old action container bounds to the right edge.
-  const gfx::Rect old_action_container_bounds =
-      action_container_widget_->GetWindowBoundsInScreen();
-  const gfx::Size new_preferred_size =
-      action_container_view_->GetPreferredSize();
-  const gfx::Vector2d slide_offset(
-      old_action_container_bounds.width() - new_preferred_size.width(), 0);
-
-  // Set the target bounds at the right edge.
-  action_container_widget_->SetBounds(gfx::Rect(
-      old_action_container_bounds.origin() + slide_offset, new_preferred_size));
-
-  // Set an initial translation so that the new icon buttons start sliding from
-  // the left edge.
-  gfx::Transform initial_translation;
-  initial_translation.Translate(-slide_offset);
-  ui::Layer* layer = action_container_widget_->GetLayer();
-  layer->SetTransform(initial_translation);
-
-  views::AnimationBuilder()
-      .SetPreemptionStrategy(
-          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
-      .OnEnded(
-          base::BindOnce(&CaptureModeSession::SetActionContainerEventsEnabled,
-                         weak_ptr_factory_.GetWeakPtr(), true))
-      .Once()
-      .SetDuration(kSmartActionsButtonTransitionFadeInDuration)
-      .SetOpacity(layer, 1.0f, gfx::Tween::LINEAR)
-      .At(base::TimeDelta())
-      .SetDuration(kSmartActionsButtonTransitionSlideInDuration)
-      .SetTransform(layer, gfx::Transform(), gfx::Tween::ACCEL_LIN_DECEL_100);
-}
-
-void CaptureModeSession::SetActionContainerEventsEnabled(bool enabled) {
-  if (!action_container_widget_) {
-    return;
-  }
-  action_container_widget_->GetContentsView()->SetCanProcessEventsWithinSubtree(
-      enabled);
-  action_container_widget_->GetNativeWindow()->SetEventTargetingPolicy(
-      enabled ? aura::EventTargetingPolicy::kTargetAndDescendants
-              : aura::EventTargetingPolicy::kNone);
-}
-
 void CaptureModeSession::InvalidateImageSearch() {
   weak_token_factory_.InvalidateWeakPtrs();
   MaybeRemoveGlowAnimation();
diff --git a/ash/capture_mode/capture_mode_session.h b/ash/capture_mode/capture_mode_session.h
index 07bfd50..99562d3 100644
--- a/ash/capture_mode/capture_mode_session.h
+++ b/ash/capture_mode/capture_mode_session.h
@@ -39,12 +39,9 @@
 class Canvas;
 }  // namespace gfx
 
-namespace views {
-class BoxLayoutView;
-}  // namespace views
-
 namespace ash {
 
+class ActionButtonContainerView;
 class ActionButtonView;
 class CaptureModeBarView;
 class CaptureModeController;
@@ -489,19 +486,6 @@
   // Schedules a repaint of the glow area surrounding the capture region.
   void RefreshGlowRegion();
 
-  // Starts performing the button transition triggered after pressing the smart
-  // actions button. This will fade out existing action buttons, remove the
-  // smart actions button, then animate in new icon buttons to replace the old
-  // copy text and search buttons.
-  void StartSmartActionsButtonTransition();
-
-  // Called when the smart actions button has faded out, to start the transition
-  // to new buttons. See `StartSmartActionsButtonTransition()`.
-  void OnSmartActionsButtonFadedOut();
-
-  // Enables or disables events on the action container widget.
-  void SetActionContainerEventsEnabled(bool enabled);
-
   // Invalidates the current image search, so that results from any ongoing
   // search will be discarded. This will invalidate all pointers previously
   // returned from `GetImageSearchToken()` and remove related loading
@@ -541,7 +525,7 @@
 
   // TODO(hewer): Check if we can migrate these widgets to `SunfishBehavior`.
   views::UniqueWidgetPtr action_container_widget_;
-  raw_ptr<views::BoxLayoutView> action_container_view_ = nullptr;
+  raw_ptr<ActionButtonContainerView> action_container_view_ = nullptr;
 
   // Widget that hosts the recording type menu, from which the user can pick the
   // desired recording format type.
diff --git a/ash/capture_mode/capture_mode_session_focus_cycler.cc b/ash/capture_mode/capture_mode_session_focus_cycler.cc
index 8f96d84..0cd96e3 100644
--- a/ash/capture_mode/capture_mode_session_focus_cycler.cc
+++ b/ash/capture_mode/capture_mode_session_focus_cycler.cc
@@ -8,6 +8,7 @@
 
 #include "ash/accessibility/magnifier/magnifier_utils.h"
 #include "ash/accessibility/scoped_a11y_override_window_setter.h"
+#include "ash/capture_mode/action_button_container_view.h"
 #include "ash/capture_mode/capture_button_view.h"
 #include "ash/capture_mode/capture_label_view.h"
 #include "ash/capture_mode/capture_mode_bar_view.h"
@@ -35,7 +36,6 @@
 #include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/controls/focus_ring.h"
 #include "ui/views/controls/highlight_path_generator.h"
-#include "ui/views/layout/box_layout_view.h"
 #include "ui/views/view.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
diff --git a/ash/capture_mode/capture_mode_session_test_api.cc b/ash/capture_mode/capture_mode_session_test_api.cc
index 66426c0..ef45476 100644
--- a/ash/capture_mode/capture_mode_session_test_api.cc
+++ b/ash/capture_mode/capture_mode_session_test_api.cc
@@ -4,6 +4,7 @@
 
 #include "ash/capture_mode/capture_mode_session_test_api.h"
 
+#include "ash/capture_mode/action_button_container_view.h"
 #include "ash/capture_mode/action_button_view.h"
 #include "ash/capture_mode/capture_mode_controller.h"
 #include "ash/capture_mode/capture_mode_session.h"
@@ -154,7 +155,8 @@
 
 ActionButtonView* CaptureModeSessionTestApi::GetButtonWithViewID(
     ActionButtonViewID id) const {
-  raw_ptr<views::BoxLayoutView> container = session_->action_container_view_;
+  raw_ptr<ActionButtonContainerView> container =
+      session_->action_container_view_;
   return container
              ? views::AsViewClass<ActionButtonView>(container->GetViewByID(id))
              : nullptr;
diff --git a/ash/constants/ash_paths.cc b/ash/constants/ash_paths.cc
index 42ace4f..b7e42ef 100644
--- a/ash/constants/ash_paths.cc
+++ b/ash/constants/ash_paths.cc
@@ -63,6 +63,9 @@
 const base::FilePath::CharType kDevicePolicyScreensaverDataDir[] =
     FILE_PATH_LITERAL("/var/cache/managed_screensaver");
 
+const base::FilePath::CharType kDeviceLocalAccountIwaCacheDir[] =
+    FILE_PATH_LITERAL("/var/cache/device_local_account_iwa");
+
 bool PathProvider(int key, base::FilePath* result) {
   switch (key) {
     case FILE_DEFAULT_APP_ORDER:
@@ -110,6 +113,9 @@
     case DIR_DEVICE_POLICY_SCREENSAVER_DATA:
       *result = base::FilePath(kDevicePolicyScreensaverDataDir);
       break;
+    case DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE:
+      *result = base::FilePath(kDeviceLocalAccountIwaCacheDir);
+      break;
 
     default:
       return false;
diff --git a/ash/constants/ash_paths.h b/ash/constants/ash_paths.h
index 178a4b6..a9d0ddf 100644
--- a/ash/constants/ash_paths.h
+++ b/ash/constants/ash_paths.h
@@ -59,6 +59,9 @@
                                        // data resources are cached.
   DIR_DEVICE_POLICY_SCREENSAVER_DATA,  // Directory where the device policy
                                        // managed screensaver images are cached.
+  DIR_DEVICE_LOCAL_ACCOUNT_IWA_CACHE,  // Directory under which a cache of
+                                       // force-installed IWAs is maintained for
+                                       // kiosk and MGS.
   PATH_END
 };
 
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index 4110185..21a7f36 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -317,7 +317,7 @@
 
   DragImageView* drag_image =
       static_cast<DragImageView*>(drag_image_widget_->GetContentsView());
-  drag_image->SetImage(image);
+  drag_image->SetImage(ui::ImageModel::FromImageSkia(image));
   drag_image_offset_ = image_offset;
   gfx::Rect drag_image_bounds(current_location_,
                               drag_image->GetPreferredSize());
diff --git a/ash/quick_insert/views/quick_insert_emoji_bar_view_unittest.cc b/ash/quick_insert/views/quick_insert_emoji_bar_view_unittest.cc
index 60b1f3f..14c73c7 100644
--- a/ash/quick_insert/views/quick_insert_emoji_bar_view_unittest.cc
+++ b/ash/quick_insert/views/quick_insert_emoji_bar_view_unittest.cc
@@ -249,6 +249,8 @@
 
 TEST_F(QuickInsertEmojiBarViewTest,
        ClickingGifsButtonDoesNotToggleCheckedState) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kPickerGifs);
   MockEmojiBarViewDelegate mock_delegate;
   std::unique_ptr<views::Widget> widget =
       CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
diff --git a/ash/quick_insert/views/quick_insert_view_unittest.cc b/ash/quick_insert/views/quick_insert_view_unittest.cc
index 4cad33f6..a7c1b2db 100644
--- a/ash/quick_insert/views/quick_insert_view_unittest.cc
+++ b/ash/quick_insert/views/quick_insert_view_unittest.cc
@@ -2824,6 +2824,8 @@
 }
 
 TEST_F(QuickInsertViewTest, ClickingGifsButtonOpensGifPickerWithQuerySearch) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(features::kPickerGifs);
   FakeQuickInsertViewDelegate delegate(
       {.available_categories = {QuickInsertCategory::kEmojisGifs}});
   auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
diff --git a/ash/webui/media_app_ui/BUILD.gn b/ash/webui/media_app_ui/BUILD.gn
index 8e6c0cc..03354df 100644
--- a/ash/webui/media_app_ui/BUILD.gn
+++ b/ash/webui/media_app_ui/BUILD.gn
@@ -40,6 +40,7 @@
     "//ash/webui/system_apps/public:system_web_app_type",
     "//ash/webui/web_applications",
     "//chromeos/ash/components/mantis/media_app",
+    "//chromeos/ash/components/specialized_features",
     "//chromeos/constants",
     "//chromeos/strings",
     "//components/prefs",
diff --git a/ash/webui/media_app_ui/DEPS b/ash/webui/media_app_ui/DEPS
index 11bcc03..2dfbb55 100644
--- a/ash/webui/media_app_ui/DEPS
+++ b/ash/webui/media_app_ui/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   # Do not add chrome here (use a delegate instead).
   "+chromeos/ash/components/mantis/media_app",
+  "+chromeos/ash/components/specialized_features",
   "+chromeos/grit/chromeos_media_app_bundle_resources.h",
   "+chromeos/grit/chromeos_media_app_bundle_resources_map.h",
   "+components/content_settings/core/common",
diff --git a/ash/webui/media_app_ui/media_app_guest_ui.cc b/ash/webui/media_app_ui/media_app_guest_ui.cc
index 315e105..6fd22e6 100644
--- a/ash/webui/media_app_ui/media_app_guest_ui.cc
+++ b/ash/webui/media_app_ui/media_app_guest_ui.cc
@@ -25,6 +25,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/task/thread_pool.h"
 #include "chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "chromeos/grit/chromeos_media_app_bundle_resources.h"
 #include "chromeos/grit/chromeos_media_app_bundle_resources_map.h"
 #include "content/public/browser/navigation_handle.h"
@@ -310,8 +311,12 @@
   // Mantis does not live in //chrome, no need to use delegate.
   if (mantis_untrusted_service_manager_ == nullptr) {
     mantis_untrusted_service_manager_ =
-        std::make_unique<MantisUntrustedServiceManager>();
+        std::make_unique<MantisUntrustedServiceManager>(
+            delegate_->GetFeatureAccessChecker(
+                MantisUntrustedServiceManager::GetFeatureAccessConfig(),
+                web_ui()));
   }
+
   mantis_untrusted_service_manager_->IsAvailable(
       delegate_->GetPrefService(web_ui()),
       base::BindOnce(&MediaAppGuestUI::OnMantisAvailableDone,
diff --git a/ash/webui/media_app_ui/media_app_guest_ui.h b/ash/webui/media_app_ui/media_app_guest_ui.h
index bdc7061..00437c9 100644
--- a/ash/webui/media_app_ui/media_app_guest_ui.h
+++ b/ash/webui/media_app_ui/media_app_guest_ui.h
@@ -5,6 +5,7 @@
 #ifndef ASH_WEBUI_MEDIA_APP_UI_MEDIA_APP_GUEST_UI_H_
 #define ASH_WEBUI_MEDIA_APP_UI_MEDIA_APP_GUEST_UI_H_
 
+#include <memory>
 #include <optional>
 #include <string>
 
@@ -12,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/task/sequenced_task_runner.h"
 #include "chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -34,6 +36,9 @@
   // Takes a WebUI and WebUIDataSource, and populates its load-time data.
   virtual void PopulateLoadTimeData(content::WebUI* web_ui,
                                     content::WebUIDataSource* source) = 0;
+  virtual std::unique_ptr<specialized_features::FeatureAccessChecker>
+  GetFeatureAccessChecker(specialized_features::FeatureAccessConfig config,
+                          content::WebUI* web_ui) const = 0;
   virtual PrefService* GetPrefService(content::WebUI* web_ui) = 0;
   virtual void CreateAndBindOcrUntrustedService(
       content::BrowserContext& context,
diff --git a/ash/wm/desks/desk_button/desk_button.cc b/ash/wm/desks/desk_button/desk_button.cc
index 5397086..e276aab 100644
--- a/ash/wm/desks/desk_button/desk_button.cc
+++ b/ash/wm/desks/desk_button/desk_button.cc
@@ -285,7 +285,8 @@
             summary->icon, skia::ImageOperations::RESIZE_BEST,
             kDeskButtonAvatarSize);
 
-        desk_avatar_view_->SetImage(desk_avatar_image_);
+        desk_avatar_view_->SetImage(
+            ui::ImageModel::FromImageSkia(desk_avatar_image_));
         desk_avatar_view_->SetImageSize(kDeskButtonAvatarSize);
         desk_avatar_view_->SetVisible(true);
         return;
diff --git a/base/tracing/stdlib/chrome/chrome_scrolls.sql b/base/tracing/stdlib/chrome/chrome_scrolls.sql
index 97d64fa..58f1b11 100644
--- a/base/tracing/stdlib/chrome/chrome_scrolls.sql
+++ b/base/tracing/stdlib/chrome/chrome_scrolls.sql
@@ -10,7 +10,7 @@
 -- Ties together input (`LatencyInfo.Flow`) and frame (`Graphics.Pipeline`)
 -- trace events. Only covers input events of the `GESTURE_SCROLL_UPDATE_EVENT`
 -- type.
-CREATE PERFETTO TABLE _chrome_scroll_update_refs(
+CREATE PERFETTO TABLE chrome_scroll_update_refs(
   -- Id of the Chrome input pipeline (`LatencyInfo.Flow`).
   scroll_update_latency_id LONG,
   -- Id of the touch move input corresponding to this scroll update.
@@ -92,7 +92,7 @@
   compositor_coalesced_input_handled_step.ts
     + compositor_coalesced_input_handled_step.dur
     AS compositor_coalesced_input_handled_end_ts
-FROM _chrome_scroll_update_refs refs
+FROM chrome_scroll_update_refs refs
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 LEFT JOIN chrome_event_latencies chrome_event_latency
   ON chrome_event_latency.scroll_update_id = refs.scroll_update_latency_id
@@ -362,7 +362,7 @@
   chrome_event_latency.buffer_ready_timestamp,
   chrome_event_latency.latch_timestamp,
   chrome_event_latency.presentation_timestamp
-FROM _chrome_scroll_update_refs refs
+FROM chrome_scroll_update_refs refs
 LEFT JOIN chrome_event_latencies chrome_event_latency
   ON chrome_event_latency.scroll_update_id = refs.presentation_latency_id
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
diff --git a/base/tracing/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py b/base/tracing/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
index 2411809..f3eec93 100755
--- a/base/tracing/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
+++ b/base/tracing/test/trace_processor/diff_tests/chrome/tests_scroll_jank.py
@@ -556,6 +556,47 @@
         8456911910253096993,8456911910253096992
         """))
 
+  def test_chrome_scroll_update_refs(self):
+        return DiffTestBlueprint(
+        trace=DataPath('scroll_m131.pftrace'),
+        query="""
+        INCLUDE PERFETTO MODULE chrome.chrome_scrolls;
+
+        SELECT
+          scroll_update_latency_id,
+          touch_move_latency_id,
+          presentation_latency_id,
+          surface_frame_id,
+          display_trace_id
+        FROM chrome_scroll_update_refs
+        ORDER BY scroll_update_latency_id
+        LIMIT 21
+        """,
+        out=Csv("""
+        "scroll_update_latency_id","touch_move_latency_id","presentation_latency_id","surface_frame_id","display_trace_id"
+        -2143831735395280256,"[NULL]",-2143831735395280256,1407387768455513,65727
+        -2143831735395280254,"[NULL]",-2143831735395280254,1407387768455514,65728
+        -2143831735395280250,"[NULL]",-2143831735395280250,1407387768455512,65726
+        -2143831735395280248,"[NULL]",-2143831735395280248,1407387768455517,65731
+        -2143831735395280246,"[NULL]",-2143831735395280246,1407387768455518,65732
+        -2143831735395280244,"[NULL]",-2143831735395280244,1407387768455515,65729
+        -2143831735395280242,"[NULL]",-2143831735395280242,1407387768455516,65730
+        -2143831735395280239,-2143831735395280236,-2143831735395280239,1407387768455508,65722
+        -2143831735395280229,"[NULL]",-2143831735395280229,1407387768455511,65725
+        -2143831735395280227,"[NULL]",-2143831735395280227,1407387768455509,65723
+        -2143831735395280226,"[NULL]",-2143831735395280226,1407387768455510,65724
+        -2143831735395280208,"[NULL]",-2143831735395280208,1407387768455521,65735
+        -2143831735395280206,"[NULL]",-2143831735395280206,1407387768455522,65736
+        -2143831735395280204,"[NULL]",-2143831735395280204,1407387768455519,65733
+        -2143831735395280202,"[NULL]",-2143831735395280202,1407387768455520,65734
+        -2143831735395280200,"[NULL]",-2143831735395280200,"[NULL]","[NULL]"
+        -2143831735395280196,"[NULL]",-2143831735395280196,1407387768455523,65737
+        -2143831735395280194,"[NULL]",-2143831735395280194,"[NULL]","[NULL]"
+        -2143831735395280183,-2143831735395280177,-2143831735395280179,"[NULL]","[NULL]"
+        -2143831735395280179,-2143831735395280189,-2143831735395280179,1407387768455503,65717
+        -2143831735395280166,-2143831735395280163,-2143831735395280166,1407387768455501,"[NULL]"
+  """))
+
   def test_chrome_scroll_update_input_info(self):
         return DiffTestBlueprint(
         trace=DataPath('scroll_m131.pftrace'),
diff --git a/chrome/VERSION b/chrome/VERSION
index 0e602df..9d30fcb9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=134
 MINOR=0
-BUILD=6954
+BUILD=6955
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
index 80a39d3..c38da80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivity.java
@@ -104,8 +104,10 @@
         super.triggerLayoutInflation();
 
         Intent intent = getIntent();
-        int signinAccessPoint = intent.getIntExtra(ARGUMENT_ACCESS_POINT, SigninAccessPoint.MAX);
-        assert signinAccessPoint != SigninAccessPoint.MAX : "Cannot find SigninAccessPoint!";
+        int signinAccessPoint = intent.getIntExtra(ARGUMENT_ACCESS_POINT,
+                                                   SigninAccessPoint.MAX_VALUE);
+        assert signinAccessPoint <= SigninAccessPoint.MAX_VALUE :
+          "Cannot find SigninAccessPoint!";
 
         if (intent.getBooleanExtra(ARGUMENT_IS_FULLSCREEN_SIGNIN, false)) {
             updateSystemUiForFullscreenSignin();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivityLauncherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivityLauncherImpl.java
index 59b20aa1..1f7239e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivityLauncherImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndHistorySyncActivityLauncherImpl.java
@@ -81,7 +81,8 @@
         SigninManager signinManager = IdentityServicesProvider.get().getSigninManager(profile);
         if (signinManager.isSigninDisabledByPolicy()) {
             RecordHistogram.recordEnumeratedHistogram(
-                    "Signin.SigninDisabledNotificationShown", accessPoint, SigninAccessPoint.MAX);
+                    "Signin.SigninDisabledNotificationShown", accessPoint,
+                    SigninAccessPoint.MAX_VALUE);
             ManagedPreferencesUtils.showManagedByAdministratorToast(context);
         }
         // TODO(crbug.com/376251506): Add generic error UI.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
index a13921be..6e48860 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
@@ -453,7 +453,7 @@
             RecordHistogram.recordEnumeratedHistogram(
                     "Signin.SigninCompletedAccessPoint",
                     mSignInState.getAccessPoint(),
-                    SigninAccessPoint.MAX);
+                    SigninAccessPoint.MAX_VALUE );
         }
 
         if (mSignInState.mCallback != null) {
@@ -602,7 +602,7 @@
         RecordHistogram.recordEnumeratedHistogram(
                 "Signin.SigninAbortedAccessPoint",
                 signInState.getAccessPoint(),
-                SigninAccessPoint.MAX);
+                SigninAccessPoint.MAX_VALUE);
 
         if (signInState.mCallback != null) {
             signInState.mCallback.onSignInAborted();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java
index bb36f83..4a1676d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivityLauncherImpl.java
@@ -104,7 +104,8 @@
         }
         if (signinManager.isSigninDisabledByPolicy()) {
             RecordHistogram.recordEnumeratedHistogram(
-                    "Signin.SyncDisabledNotificationShown", accessPoint, SigninAccessPoint.MAX);
+                    "Signin.SyncDisabledNotificationShown", accessPoint,
+                     SigninAccessPoint.MAX_VALUE);
             ManagedPreferencesUtils.showManagedByAdministratorToast(context);
         }
         return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
index 38dc7ca..64f3c8e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
@@ -141,7 +141,7 @@
         }
 
         RecordHistogram.recordEnumeratedHistogram(
-                histogram, mSigninAccessPoint, SigninAccessPoint.MAX);
+                histogram, mSigninAccessPoint, SigninAccessPoint.MAX_VALUE);
     }
 
     private void recordSigninStartedHistogramAccountInfo() {
@@ -167,7 +167,7 @@
         }
 
         RecordHistogram.recordEnumeratedHistogram(
-                histogram, mSigninAccessPoint, SigninAccessPoint.MAX);
+                histogram, mSigninAccessPoint, SigninAccessPoint.MAX_VALUE);
     }
 
     @Override
diff --git a/chrome/browser/ash/accessibility/accessibility_test_utils.cc b/chrome/browser/ash/accessibility/accessibility_test_utils.cc
index c9a1c588..67b9b45 100644
--- a/chrome/browser/ash/accessibility/accessibility_test_utils.cc
+++ b/chrome/browser/ash/accessibility/accessibility_test_utils.cc
@@ -95,7 +95,7 @@
 
 void HistogramWaiter::OnHistogramCallback(const char* metric_name,
                                           uint64_t name_hash,
-                                          base::HistogramBase::Sample sample) {
+                                          base::HistogramBase::Sample32 sample) {
   run_loop_.Quit();
   histogram_observer_.reset();
 }
diff --git a/chrome/browser/ash/accessibility/accessibility_test_utils.h b/chrome/browser/ash/accessibility/accessibility_test_utils.h
index db9dda0..88ba43ae 100644
--- a/chrome/browser/ash/accessibility/accessibility_test_utils.h
+++ b/chrome/browser/ash/accessibility/accessibility_test_utils.h
@@ -112,7 +112,7 @@
   void Wait();
   void OnHistogramCallback(const char* metric_name,
                            uint64_t name_hash,
-                           base::HistogramBase::Sample sample);
+                           base::HistogramBase::Sample32 sample);
 
  private:
   std::unique_ptr<base::StatisticsRecorder::ScopedHistogramSampleObserver>
diff --git a/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc b/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc
index 45e56368..9c9466af 100644
--- a/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc
+++ b/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc
@@ -135,7 +135,7 @@
 
   int last_retry_bucket_count = histogram_tester.GetBucketCount(
       "AndroidSms.FcmMessageDispatchRetry",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           FcmConnectionEstablisher::MessageType::kStart));
 
   int retry_count = 0;
diff --git a/chrome/browser/ash/app_mode/kiosk_guest_view_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_guest_view_browsertest.cc
index 8524013..e38b9638 100644
--- a/chrome/browser/ash/app_mode/kiosk_guest_view_browsertest.cc
+++ b/chrome/browser/ash/app_mode/kiosk_guest_view_browsertest.cc
@@ -7,12 +7,14 @@
 #include "base/check_deref.h"
 #include "chrome/browser/ash/app_mode/kiosk_controller.h"
 #include "chrome/browser/ash/app_mode/test/kiosk_mixin.h"
+#include "chrome/browser/ash/app_mode/test/kiosk_test_utils.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/guest_view/browser/guest_view.h"
 #include "components/guest_view/browser/guest_view_base.h"
 #include "components/guest_view/browser/guest_view_manager_delegate.h"
 #include "components/guest_view/browser/test_guest_view_manager.h"
@@ -22,6 +24,8 @@
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
 
@@ -29,40 +33,54 @@
 
 namespace {
 
+// This web page opens a PDF file once `link1` is clicked.
+// That triggers a mime handler guest view creation.
+constexpr std::string_view kPdfOpenerUrl = "/pdf/test-iframe-pdf.html";
+
 void NotifyKioskGuestAdded(content::WebContents* guest_web_contents) {
   KioskController::Get().OnGuestAdded(guest_web_contents);
 }
 
-Profile& GetProfile() {
-  return CHECK_DEREF(ProfileManager::GetPrimaryUserProfile());
-}
+// Creates a new browser with enabled kiosk troubleshooting tools policy,
+// navigates to the given `page_url` and returns it's active `WebContents`.
+content::WebContents* OpenUrlInBrowser(GURL page_url) {
+  // Enable troubleshooting tools to be able to open a browser in kiosk mode.
+  ash::kiosk::test::CurrentProfile().GetPrefs()->SetBoolean(
+      prefs::kKioskTroubleshootingToolsEnabled, true);
 
-void OpenWebUiWithGuestView() {
-  // Enable troubleshooting tools to access a Web Ui page with `<webview>` tag.
-  // Note: `<webview>` is a restricted tag and triggers guest view creation only
-  // for Chrome apps and allowlisted WebUi pages.
-  GetProfile().GetPrefs()->SetBoolean(prefs::kKioskTroubleshootingToolsEnabled,
-                                      true);
-
-  // Navigate to the WebUi page allowlisted here
-  // extensions/common/api/_api_features.json.
-  GURL signin_url{"chrome://chrome-signin/?reason=5"};
   Browser::CreateParams params =
       Browser::CreateParams(Browser::Type::TYPE_NORMAL,
-                            /*profile=*/&GetProfile(),
+                            /*profile=*/&ash::kiosk::test::CurrentProfile(),
                             /*user_gesture=*/true);
   auto& new_browser = CHECK_DEREF(Browser::Create(params));
   new_browser.window()->Show();
   ui_test_utils::NavigateToURLWithDisposition(
-      &new_browser, signin_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      &new_browser, page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+  return new_browser.tab_strip_model()->GetActiveWebContents();
+}
+
+// Open a PDF file in iframe of test-iframe-pdf.html web page.
+// `web_contents` is active browser web contents of test-iframe-pdf.html.
+bool OpenPdfInWebContents(content::WebContents* web_contents) {
+  return content::ExecJs(
+      web_contents,
+      "var button_to_open_pdf = document.getElementById('link1');"
+      "button_to_open_pdf.click();");
 }
 
 guest_view::TestGuestViewManager& GetGuestViewManager(
     guest_view::TestGuestViewManagerFactory& factory) {
   return CHECK_DEREF(factory.GetOrCreateTestGuestViewManager(
-      &GetProfile(), extensions::ExtensionsAPIClient::Get()
-                         ->CreateGuestViewManagerDelegate()));
+      &ash::kiosk::test::CurrentProfile(),
+      extensions::ExtensionsAPIClient::Get()
+          ->CreateGuestViewManagerDelegate()));
+}
+
+KioskMixin::DefaultServerWebAppOption PdfWebApp() {
+  return KioskMixin::DefaultServerWebAppOption{
+      /*account_id=*/"pdf-web-app@localhost",
+      /*url_path=*/kPdfOpenerUrl};
 }
 
 }  // namespace
@@ -87,21 +105,45 @@
 
   guest_view::TestGuestViewManagerFactory& factory() { return factory_; }
 
- private:
   ash::KioskMixin kiosk_{&mixin_host_,
                          /*cached_configuration=*/kiosk_mixin_config()};
 
+ private:
   guest_view::TestGuestViewManagerFactory factory_;
 };
 
-IN_PROC_BROWSER_TEST_P(KioskGuestViewTest, AddingGuestViewDoesNotCrash) {
+IN_PROC_BROWSER_TEST_P(KioskGuestViewTest, AddingWebViewGuestViewDoesNotCrash) {
   EXPECT_EQ(0ULL, GetGuestViewManager(factory()).GetCurrentGuestCount());
-  OpenWebUiWithGuestView();
+
+  // Open Web UI with a `<webview>` tag.
+  // Note: `<webview>` is a restricted tag and triggers guest view creation only
+  // for Chrome apps and WebUi pages, which are allowlisted here:
+  // extensions/common/api/_api_features.json
+  ASSERT_NE(nullptr,
+            OpenUrlInBrowser(GURL("chrome://chrome-signin/?reason=5")));
 
   auto* guest_view =
       GetGuestViewManager(factory()).WaitForSingleGuestViewCreated();
   ASSERT_NE(guest_view, nullptr);
   ASSERT_NE(guest_view->web_contents(), nullptr);
+  EXPECT_NE(nullptr, extensions::WebViewGuest::FromWebContents(
+                         guest_view->web_contents()));
+  EXPECT_NO_FATAL_FAILURE(NotifyKioskGuestAdded(guest_view->web_contents()));
+}
+
+IN_PROC_BROWSER_TEST_P(KioskGuestViewTest,
+                       AddingMimeHandlerGuestViewDoesNotCrash) {
+  // Open a new browser with locally served test-iframe-pdf.html web page.
+  GURL url = kiosk_.GetDefaultServerUrl(kPdfOpenerUrl);
+  content::WebContents* web_contents = OpenUrlInBrowser(url);
+  ASSERT_TRUE(OpenPdfInWebContents(web_contents));
+
+  auto* guest_view =
+      GetGuestViewManager(factory()).WaitForSingleGuestViewCreated();
+  ASSERT_NE(guest_view, nullptr);
+  ASSERT_NE(guest_view->web_contents(), nullptr);
+  EXPECT_EQ(nullptr, extensions::WebViewGuest::FromWebContents(
+                         guest_view->web_contents()));
   EXPECT_NO_FATAL_FAILURE(NotifyKioskGuestAdded(guest_view->web_contents()));
 }
 
@@ -111,4 +153,52 @@
     testing::ValuesIn(KioskMixin::ConfigsToAutoLaunchEachAppType()),
     KioskMixin::ConfigName);
 
+class WebKioskGuestViewTest : public MixinBasedInProcessBrowserTest {
+ public:
+  WebKioskGuestViewTest() = default;
+  WebKioskGuestViewTest(const WebKioskGuestViewTest&) = delete;
+  WebKioskGuestViewTest& operator=(const WebKioskGuestViewTest&) = delete;
+
+  ~WebKioskGuestViewTest() override = default;
+
+ protected:
+  void SetUpOnMainThread() override {
+    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(kiosk_.WaitSessionLaunched());
+  }
+
+  guest_view::TestGuestViewManagerFactory& factory() { return factory_; }
+
+ private:
+  ash::KioskMixin kiosk_{
+      &mixin_host_,
+      KioskMixin::Config(/*name=*/{},
+                         KioskMixin::AutoLaunchAccount(PdfWebApp().account_id),
+                         {PdfWebApp()})};
+
+  guest_view::TestGuestViewManagerFactory factory_;
+};
+
+IN_PROC_BROWSER_TEST_F(WebKioskGuestViewTest,
+                       AddingMimeHandlerGuestViewDoesNotCrash) {
+  auto* web_contents = BrowserList::GetInstance()
+                           ->get(0)
+                           ->tab_strip_model()
+                           ->GetActiveWebContents();
+  ASSERT_TRUE(web_contents);
+  if (web_contents->IsLoading()) {
+    content::WaitForLoadStop(web_contents);
+  }
+  ASSERT_TRUE(OpenPdfInWebContents(web_contents));
+
+  auto* guest_view =
+      GetGuestViewManager(factory()).WaitForSingleGuestViewCreated();
+
+  ASSERT_NE(guest_view, nullptr);
+  ASSERT_NE(guest_view->web_contents(), nullptr);
+  EXPECT_EQ(nullptr, extensions::WebViewGuest::FromWebContents(
+                         guest_view->web_contents()));
+  EXPECT_NO_FATAL_FAILURE(NotifyKioskGuestAdded(guest_view->web_contents()));
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/crostini/crostini_installer_unittest.cc b/chrome/browser/ash/crostini/crostini_installer_unittest.cc
index 63e96fd..0f627ee 100644
--- a/chrome/browser/ash/crostini/crostini_installer_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_installer_unittest.cc
@@ -225,7 +225,7 @@
   task_environment_.RunUntilIdle();
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kSuccess),
       1);
   histogram_tester_.ExpectTotalCount("Crostini.Setup.Started", 1);
@@ -268,7 +268,7 @@
   task_environment_.RunUntilIdle();
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kSuccess),
       1);
 
@@ -281,7 +281,7 @@
 
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kNotStarted),
       1);
 }
@@ -314,7 +314,7 @@
 
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kUserCancelledStartTerminaVm),
       1);
   EXPECT_TRUE(crostini_installer_->CanInstall())
@@ -334,7 +334,7 @@
 
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kNotStarted),
       1);
   EXPECT_TRUE(crostini_installer_->CanInstall())
@@ -359,7 +359,7 @@
 
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kErrorStartingTermina),
       1);
   histogram_tester_.ExpectTotalCount("Crostini.Setup.Started", 1);
@@ -395,7 +395,7 @@
   task_environment_.RunUntilIdle();
   histogram_tester_.ExpectUniqueSample(
       "Crostini.SetupResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniInstaller::SetupResult::kErrorConfiguringContainer),
       1);
 
diff --git a/chrome/browser/ash/crostini/crostini_upgrade_available_notification_unittest.cc b/chrome/browser/ash/crostini/crostini_upgrade_available_notification_unittest.cc
index f128fdc..6268612 100644
--- a/chrome/browser/ash/crostini/crostini_upgrade_available_notification_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_upgrade_available_notification_unittest.cc
@@ -151,13 +151,13 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UpgradeDialogEvent",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           crostini::UpgradeDialogEvent::kDialogShown),
       1);
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UpgradeAvailable",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           crostini::CrostiniUpgradeAvailableNotificationClosed::kUpgradeButton),
       1);
 }
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
index 633288d..c3761b4 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -1455,7 +1455,7 @@
 void NativeInputMethodEngineObserver::ReportHistogramSample(
     base::Histogram* histogram,
     uint16_t value) {
-  histogram->Add(base::strict_cast<base::Histogram::Sample>(value));
+  histogram->Add(base::strict_cast<base::Histogram::Sample32>(value));
 }
 
 void NativeInputMethodEngineObserver::UpdateQuickSettings(
diff --git a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
index 0baf738c..9362714 100644
--- a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
+++ b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
@@ -51,10 +51,10 @@
 
   EXPECT_THAT(histogram_tester.GetAllSamples("Fingerprint.Auth.ScanResult"),
               ::testing::ElementsAre(
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    device::mojom::ScanResult::SUCCESS),
                                1),
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    device::mojom::ScanResult::TOO_FAST),
                                1)));
 }
@@ -418,10 +418,10 @@
   AuthenticateAndCheckThroughHistogram(histogram_tester, biod);
   EXPECT_THAT(histogram_tester.GetAllSamples("Fingerprint.Enroll.ScanResult"),
               ::testing::ElementsAre(
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    device::mojom::ScanResult::SUCCESS),
                                1),
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    device::mojom::ScanResult::TOO_SLOW),
                                1)));
 }
diff --git a/chrome/browser/ash/system_web_apps/apps/media_app/BUILD.gn b/chrome/browser/ash/system_web_apps/apps/media_app/BUILD.gn
index 2989a1f..726a30d 100644
--- a/chrome/browser/ash/system_web_apps/apps/media_app/BUILD.gn
+++ b/chrome/browser/ash/system_web_apps/apps/media_app/BUILD.gn
@@ -20,6 +20,7 @@
     "//base",
     "//chrome/browser:browser_public_dependencies",
     "//chrome/browser/ash/system_web_apps/types",
+    "//chromeos/ash/components/specialized_features",
     "//content/public/browser",
     "//mojo/public/cpp/bindings",
     "//storage/browser",
diff --git a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc
index f434e33..261d0c07 100644
--- a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc
+++ b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.cc
@@ -17,9 +17,11 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "chromeos/components/mahi/public/cpp/mahi_manager.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -121,6 +123,16 @@
   source->AddBoolean("isDevChannel", channel == version_info::Channel::DEV);
 }
 
+std::unique_ptr<specialized_features::FeatureAccessChecker>
+ChromeMediaAppGuestUIDelegate::GetFeatureAccessChecker(
+    specialized_features::FeatureAccessConfig config,
+    content::WebUI* web_ui) const {
+  return std::make_unique<specialized_features::FeatureAccessChecker>(
+      std::move(config), Profile::FromWebUI(web_ui)->GetPrefs(),
+      IdentityManagerFactory::GetForProfile(Profile::FromWebUI(web_ui)),
+      g_browser_process->variations_service());
+}
+
 PrefService* ChromeMediaAppGuestUIDelegate::GetPrefService(
     content::WebUI* web_ui) {
   return Profile::FromWebUI(web_ui)->GetPrefs();
diff --git a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h
index 4047066f..d0465dd1 100644
--- a/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h
+++ b/chrome/browser/ash/system_web_apps/apps/media_app/media_app_guest_ui_config.h
@@ -5,9 +5,12 @@
 #ifndef CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_MEDIA_APP_MEDIA_APP_GUEST_UI_CONFIG_H_
 #define CHROME_BROWSER_ASH_SYSTEM_WEB_APPS_APPS_MEDIA_APP_MEDIA_APP_GUEST_UI_CONFIG_H_
 
+#include <memory>
+
 #include "ash/webui/media_app_ui/media_app_guest_ui.h"
 #include "ash/webui/media_app_ui/media_app_ui_untrusted.mojom.h"
 #include "chrome/browser/accessibility/media_app/ax_media_app_untrusted_service.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/webui_config.h"
 
@@ -30,6 +33,9 @@
 
   void PopulateLoadTimeData(content::WebUI* web_ui,
                             content::WebUIDataSource* source) override;
+  std::unique_ptr<specialized_features::FeatureAccessChecker>
+  GetFeatureAccessChecker(specialized_features::FeatureAccessConfig config,
+                          content::WebUI* web_ui) const override;
   PrefService* GetPrefService(content::WebUI* web_ui) override;
   void CreateAndBindOcrUntrustedService(
       content::BrowserContext& context,
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 9d0b802..fe1a58ca 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -3113,7 +3113,7 @@
 
   // Short hand for ExpectBucketCount:
   auto expect_count = [&](std::string_view name,
-                          base::HistogramBase::Sample sample,
+                          base::HistogramBase::Sample32 sample,
                           base::HistogramBase::Count expected_count) {
     histogram_tester().ExpectBucketCount(name, sample, expected_count);
   };
diff --git a/chrome/browser/battery/battery_metrics_browsertest.cc b/chrome/browser/battery/battery_metrics_browsertest.cc
index 4fc4078..ca63cc526 100644
--- a/chrome/browser/battery/battery_metrics_browsertest.cc
+++ b/chrome/browser/battery/battery_metrics_browsertest.cc
@@ -26,7 +26,7 @@
 void RetryForHistogramBucketUntilCountReached(
     base::HistogramTester* histogram_tester,
     const std::string& histogram_name,
-    base::HistogramBase::Sample target_bucket,
+    base::HistogramBase::Sample32 target_bucket,
     size_t count) {
   base::RunLoop().RunUntilIdle();
   for (size_t attempt = 0; attempt < 50; ++attempt) {
diff --git a/chrome/browser/chrome_back_forward_cache_browsertest.cc b/chrome/browser/chrome_back_forward_cache_browsertest.cc
index 30eae748e..597abba8 100644
--- a/chrome/browser/chrome_back_forward_cache_browsertest.cc
+++ b/chrome/browser/chrome_back_forward_cache_browsertest.cc
@@ -682,7 +682,7 @@
       blink::scheduler::WebSchedulerTrackedFeature feature,
       base::Location location) {
     content::FetchHistogramsFromChildProcesses();
-    base::HistogramBase::Sample sample = base::HistogramBase::Sample(feature);
+    base::HistogramBase::Sample32 sample = base::HistogramBase::Sample(feature);
     base::Bucket expected_blocklisted(sample, 1);
 
     EXPECT_THAT(histogram_tester_->GetAllSamples(
@@ -763,7 +763,7 @@
     static constexpr uint8_t kReasonHaveInnerContents = 32;
 
     content::FetchHistogramsFromChildProcesses();
-    base::HistogramBase::Sample sample = base::HistogramBase::Sample(
+    base::HistogramBase::Sample32 sample = base::HistogramBase::Sample(
         UseOopif() ? kReasonBlocklistedFeatures : kReasonHaveInnerContents);
     base::Bucket expected_not_restored(sample, 1);
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4214d595..bd990578 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1771,7 +1771,7 @@
     add_profiles_extra_parts = false;
 #endif
   if (add_profiles_extra_parts)
-    chrome::AddProfilesExtraParts(main_parts.get());
+    AddProfilesExtraParts(main_parts.get());
 
     // Construct additional browser parts. Stages are called in the order in
     // which they are added.
diff --git a/chrome/browser/chromeos/gemini_app/gemini_app_tab_helper_unittest.cc b/chrome/browser/chromeos/gemini_app/gemini_app_tab_helper_unittest.cc
index e68fdca..c9af526 100644
--- a/chrome/browser/chromeos/gemini_app/gemini_app_tab_helper_unittest.cc
+++ b/chrome/browser/chromeos/gemini_app/gemini_app_tab_helper_unittest.cc
@@ -142,7 +142,7 @@
   bool record = IsGeminiAppPreinstallEnabled() && !IsProfileOffTheRecord();
   for (const auto& [url, page] : page_urls) {
     auto histogram_buckets_it = base::ranges::find(
-        histogram_buckets, static_cast<base::HistogramBase::Sample>(page),
+        histogram_buckets, static_cast<base::HistogramBase::Sample32>(page),
         &Bucket::min);
     {
       // Check exact page match.
diff --git a/chrome/browser/chromeos/policy/dlp/clipboard_bubble.cc b/chrome/browser/chromeos/policy/dlp/clipboard_bubble.cc
index a18b578..a630f5cd 100644
--- a/chrome/browser/chromeos/policy/dlp/clipboard_bubble.cc
+++ b/chrome/browser/chromeos/policy/dlp/clipboard_bubble.cc
@@ -131,8 +131,8 @@
   managed_icon_->layer()->SetFillsBoundsOpaquely(false);
   managed_icon_->SetBounds(kBubblePadding, kBubblePadding, kManagedIconSize,
                            kManagedIconSize);
-  managed_icon_->SetImage(gfx::CreateVectorIcon(vector_icons::kBusinessIcon,
-                                                kManagedIconSize, icon_color));
+  managed_icon_->SetImage(ui::ImageModel::FromVectorIcon(
+      vector_icons::kBusinessIcon, icon_color, kManagedIconSize));
 
   // Add the bubble text.
   label_ = AddChildView(std::make_unique<views::StyledLabel>());
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.cc b/chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.cc
index 0bece009..b265c9f 100644
--- a/chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.cc
+++ b/chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.cc
@@ -87,8 +87,8 @@
   // TODO(crbug.com/40202228) Enable dynamic UI color & theme in lacros
   auto color = SK_ColorGRAY;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-  managed_icon->SetImage(gfx::CreateVectorIcon(vector_icons::kBusinessIcon,
-                                               kManagedIconSize, color));
+  managed_icon->SetImage(ui::ImageModel::FromVectorIcon(
+      vector_icons::kBusinessIcon, color, kManagedIconSize));
 }
 
 views::Label* PolicyDialogBase::AddTitle(const std::u16string& title) {
diff --git a/chrome/browser/compose/chrome_compose_client_unittest.cc b/chrome/browser/compose/chrome_compose_client_unittest.cc
index a973af7..fbebea1b 100644
--- a/chrome/browser/compose/chrome_compose_client_unittest.cc
+++ b/chrome/browser/compose/chrome_compose_client_unittest.cc
@@ -920,7 +920,7 @@
   NavigateAndCommitActiveTab(GURL("about:blank"));
   EXPECT_EQ(training_labels.Get().output_metric,
             std::make_pair("Compose.ProactiveNudge.DerivedEngagement",
-                           static_cast<base::HistogramBase::Sample>(
+                           static_cast<base::HistogramBase::Sample32>(
                                compose::ProactiveNudgeDerivedEngagement::
                                    kAcceptedComposeSuggestion)));
 }
diff --git a/chrome/browser/compose/proactive_nudge_tracker.cc b/chrome/browser/compose/proactive_nudge_tracker.cc
index 4bfa665b..aa8ef651 100644
--- a/chrome/browser/compose/proactive_nudge_tracker.cc
+++ b/chrome/browser/compose/proactive_nudge_tracker.cc
@@ -592,7 +592,7 @@
                                 engagement);
   training_labels.output_metric =
       std::make_pair("Compose.ProactiveNudge.DerivedEngagement",
-                     static_cast<base::HistogramBase::Sample>(engagement));
+                     static_cast<base::HistogramBase::Sample32>(engagement));
   ukm::SourceId source =
       state_ ? state_->signals.ukm_source_id : ukm::kInvalidSourceId;
   segmentation_service_->CollectTrainingData(
diff --git a/chrome/browser/compose/proactive_nudge_tracker_unittest.cc b/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
index 23bbbf6..bd2f273 100644
--- a/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
+++ b/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
@@ -131,9 +131,7 @@
     }
   }
 
-  void TearDown() override {
-    compose::ResetConfigForTesting();
-  }
+  void TearDown() override { compose::ResetConfigForTesting(); }
 
   segmentation_platform::MockSegmentationPlatformService&
   segmentation_service() {
@@ -789,7 +787,7 @@
 
   EXPECT_EQ(training_labels.Get().output_metric,
             std::make_pair("Compose.ProactiveNudge.DerivedEngagement",
-                           static_cast<base::HistogramBase::Sample>(
+                           static_cast<base::HistogramBase::Sample32>(
                                ProactiveNudgeDerivedEngagement::kIgnored)));
 }
 
@@ -807,7 +805,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kOpenedComposeMinimalUse)));
 }
 
@@ -828,7 +826,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kGeneratedComposeSuggestion)));
   histograms.ExpectUniqueSample(
       "Compose.ProactiveNudge.DerivedEngagement",
@@ -850,7 +848,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kAcceptedComposeSuggestion)));
 }
 
@@ -877,7 +875,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kAcceptedComposeSuggestion)));
 }
 
@@ -899,11 +897,11 @@
       training_labels1.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kAcceptedComposeSuggestion)));
   EXPECT_EQ(training_labels2.Get().output_metric,
             std::make_pair("Compose.ProactiveNudge.DerivedEngagement",
-                           static_cast<base::HistogramBase::Sample>(
+                           static_cast<base::HistogramBase::Sample32>(
                                ProactiveNudgeDerivedEngagement::kIgnored)));
 }
 
@@ -917,7 +915,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kNudgeDisabledOnSingleSite)));
 }
 
@@ -931,7 +929,7 @@
       training_labels.Get().output_metric,
       std::make_pair(
           "Compose.ProactiveNudge.DerivedEngagement",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               ProactiveNudgeDerivedEngagement::kNudgeDisabledOnAllSites)));
 }
 
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index f73f955..74591fc 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -128,8 +128,8 @@
 
 ChromeDevToolsSession::~ChromeDevToolsSession() = default;
 
-base::HistogramBase::Sample GetCommandUmaId(std::string_view command_name) {
-  return static_cast<base::HistogramBase::Sample>(
+base::HistogramBase::Sample32 GetCommandUmaId(std::string_view command_name) {
+  return static_cast<base::HistogramBase::Sample32>(
       base::HashMetricName(command_name));
 }
 
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc
index 956a8a7f..ff9d9a0 100644
--- a/chrome/browser/download/download_target_determiner_unittest.cc
+++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -112,8 +112,8 @@
     "Download.PathValidationResult.Transient";
 
 template <typename T>
-base::HistogramBase::Sample ToHistogramSample(T t) {
-  return static_cast<base::HistogramBase::Sample>(t);
+base::HistogramBase::Sample32 ToHistogramSample(T t) {
+  return static_cast<base::HistogramBase::Sample32>(t);
 }
 
 // No-op delegate.
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index d604bb0..de845766 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -3640,20 +3640,20 @@
   EXPECT_THAT(
       tester.GetAllSamples("Extensions.WebRequest.ResponseHeaderChanged"),
       ::testing::UnorderedElementsAre(
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ResponseHeaderType::kSetCookie),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ResponseHeaderType::kContentLength),
                        1)));
 
   // Added request header histogram should record kOther and kDNT.
   EXPECT_THAT(tester.GetAllSamples("Extensions.WebRequest.RequestHeaderAdded"),
               ::testing::UnorderedElementsAre(
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    RequestHeaderType::kDnt),
                                1),
-                  base::Bucket(static_cast<base::HistogramBase::Sample>(
+                  base::Bucket(static_cast<base::HistogramBase::Sample32>(
                                    RequestHeaderType::kOther),
                                2)));
 
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
index 5e2dffd8b..6bc450e3 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/signinbottomsheet/SigninBottomSheetCoordinator.java
@@ -146,7 +146,7 @@
         RecordHistogram.recordEnumeratedHistogram(
                 "Signin.SigninDisabledNotificationShown",
                 mSigninAccessPoint,
-                SigninAccessPoint.MAX);
+                SigninAccessPoint.MAX_VALUE);
         if (mSetTestToast) return;
         Toast.makeText(
                         mWindowAndroid.getActivity().get(),
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
index 5b0db34..b3815a5 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
@@ -407,7 +407,7 @@
     histograms.ExpectBucketCount(
         permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
             ContentSettingsType::FILE_SYSTEM_WRITE_GUARD),
-        static_cast<base::HistogramBase::Sample>(
+        static_cast<base::HistogramBase::Sample32>(
             permissions::OneTimePermissionEvent::EXPIRED_IN_BACKGROUND),
         1);
     EXPECT_EQ(grant1->GetStatus(), PermissionStatus::ASK);
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
index ace94fb..5a452bd 100644
--- a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
@@ -51,7 +51,7 @@
 
 struct HistogramSampleExpectation {
   std::string histogram_name_prefix;
-  base::Histogram::Sample sample;
+  base::Histogram::Sample32 sample;
 };
 
 // For each histogram named after the combination of prefixes from
diff --git a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
index 735f4ec..f0aac435 100644
--- a/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_reporter_unittest.cc
@@ -46,7 +46,7 @@
 
 struct HistogramSampleExpectation {
   std::string histogram_name_prefix;
-  std::optional<base::Histogram::Sample> sample;
+  std::optional<base::Histogram::Sample32> sample;
 };
 
 // For each histogram named after the combination of prefixes from
diff --git a/chrome/browser/metrics/power/power_metrics_unittest.cc b/chrome/browser/metrics/power/power_metrics_unittest.cc
index 0835489d5..5236cf7d 100644
--- a/chrome/browser/metrics/power/power_metrics_unittest.cc
+++ b/chrome/browser/metrics/power/power_metrics_unittest.cc
@@ -13,7 +13,7 @@
 
 struct HistogramSampleExpectation {
   std::string histogram_name_prefix;
-  base::Histogram::Sample sample;
+  base::Histogram::Sample32 sample;
 };
 
 // For each histogram named after the combination of prefixes from
diff --git a/chrome/browser/metrics/startup_metrics_browsertest.cc b/chrome/browser/metrics/startup_metrics_browsertest.cc
index 0ca9e54..19e757e 100644
--- a/chrome/browser/metrics/startup_metrics_browsertest.cc
+++ b/chrome/browser/metrics/startup_metrics_browsertest.cc
@@ -90,7 +90,7 @@
         histogram,
         base::BindLambdaForTesting(
             [&](const char* histogram_name, uint64_t name_hash,
-                base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+                base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
     run_loop.Run();
   }
 }
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc b/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
index 57976d7e..73e78ff7 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
@@ -169,7 +169,7 @@
   void OnHistogramRecorded(const base::RepeatingClosure& quit_closure,
                            const char* histogram_name,
                            uint64_t name_hash,
-                           base::HistogramBase::Sample sample) {
+                           base::HistogramBase::Sample32 sample) {
     quit_closure.Run();
   }
 
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
index dc255862..94e63761 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_browsertest.cc
@@ -224,12 +224,15 @@
       const net::test_server::HttpRequest& request) {
     // Returning nullptr will cause the test server to fallback to serving the
     // file from the test data directory.
-    if (request.GetURL() == model_file_url_)
+    if (request.GetURL() == model_file_url_) {
       return nullptr;
-    if (request.GetURL() == model_file_with_good_additional_file_url_)
+    }
+    if (request.GetURL() == model_file_with_good_additional_file_url_) {
       return nullptr;
-    if (request.GetURL() == model_file_with_nonexistent_additional_file_url_)
+    }
+    if (request.GetURL() == model_file_with_nonexistent_additional_file_url_) {
       return nullptr;
+    }
 
     std::unique_ptr<net::test_server::BasicHttpResponse> response;
 
@@ -614,19 +617,19 @@
       histogram_tester.GetAllSamples("OptimizationGuide.PredictionManager."
                                      "ModelDeliveryEvents.PainfulPageLoad"),
       testing::UnorderedElementsAre(
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kGetModelsRequest),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kDownloadServiceRequest),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDownloadStarted),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDownloaded),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDelivered),
                        1)));
 }
@@ -671,19 +674,19 @@
       histogram_tester.GetAllSamples("OptimizationGuide.PredictionManager."
                                      "ModelDeliveryEvents.PainfulPageLoad"),
       testing::UnorderedElementsAre(
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kGetModelsRequest),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kDownloadServiceRequest),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDownloadStarted),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDownloaded),
                        1),
-          base::Bucket(static_cast<base::HistogramBase::Sample>(
+          base::Bucket(static_cast<base::HistogramBase::Sample32>(
                            ModelDeliveryEvent::kModelDelivered),
                        1)));
 }
diff --git a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
index 96b5ee7..fb763a3 100644
--- a/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
+++ b/chrome/browser/os_crypt/app_bound_encryption_win_browsertest.cc
@@ -66,7 +66,7 @@
           histogram_name,
           base::BindLambdaForTesting(
               [&](const char* histogram_name, uint64_t name_hash,
-                  base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+                  base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
   run_loop.Run();
 }
 
diff --git a/chrome/browser/page_load_metrics/integration_tests/cross_document_resource_reuse_test.cc b/chrome/browser/page_load_metrics/integration_tests/cross_document_resource_reuse_test.cc
index 09cb8cb4..bcbb8f76 100644
--- a/chrome/browser/page_load_metrics/integration_tests/cross_document_resource_reuse_test.cc
+++ b/chrome/browser/page_load_metrics/integration_tests/cross_document_resource_reuse_test.cc
@@ -13,7 +13,7 @@
 using CrossDocumentResourceReuseTest = MetricIntegrationTest;
 
 // Enumeration value hard coded in histograms.xml
-constexpr base::Histogram::Sample kImage = 1;
+constexpr base::Histogram::Sample32 kImage = 1;
 
 // The test verifies the metrics for reusing resources among different
 // documents. The first and the second page share an image in common. We
diff --git a/chrome/browser/page_load_metrics/integration_tests/metric_integration_test.cc b/chrome/browser/page_load_metrics/integration_tests/metric_integration_test.cc
index 46344060..e4f20b7 100644
--- a/chrome/browser/page_load_metrics/integration_tests/metric_integration_test.cc
+++ b/chrome/browser/page_load_metrics/integration_tests/metric_integration_test.cc
@@ -292,7 +292,7 @@
 
 void MetricIntegrationTest::ExpectUniqueUMABucketCount(
     std::string_view metric_name,
-    base::HistogramBase::Sample sample,
+    base::HistogramBase::Sample32 sample,
     base::HistogramBase::Count count) {
   histogram_tester_->ExpectBucketCount(metric_name, sample, count);
 }
diff --git a/chrome/browser/page_load_metrics/observers/core/amp_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core/amp_page_load_metrics_observer_unittest.cc
index 0f90578..8aff5038 100644
--- a/chrome/browser/page_load_metrics/observers/core/amp_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core/amp_page_load_metrics_observer_unittest.cc
@@ -79,12 +79,12 @@
       return;
     tester()->histogram_tester().ExpectUniqueSample(
         histogram,
-        static_cast<base::HistogramBase::Sample>(
+        static_cast<base::HistogramBase::Sample32>(
             event.value().InMilliseconds()),
         1);
     tester()->histogram_tester().ExpectUniqueSample(
         view_type_histogram,
-        static_cast<base::HistogramBase::Sample>(
+        static_cast<base::HistogramBase::Sample32>(
             event.value().InMilliseconds()),
         1);
   }
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
index 3064f04..9bd9e1e 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer_unittest.cc
@@ -1988,7 +1988,7 @@
   // The layout shift score was originally 1, after multiplying 10000, it
   // should fit into the bucket of value 9130, with a histogram of maximum
   // value of 24000.
-  const base::HistogramBase::Sample max_cls = 9130;
+  const base::HistogramBase::Sample32 max_cls = 9130;
   EXPECT_THAT(tester()->histogram_tester().GetAllSamples(
                   "PageLoad.LayoutInstability."
                   "MaxCumulativeShiftScoreAtFirstOnHidden.SessionWindow."
@@ -2044,7 +2044,7 @@
   // The layout shift score was originally 1, after multiplying 10000, it
   // should fit into the bucket of value 9130, with a histogram of maximum
   // value of 24000.
-  const base::HistogramBase::Sample max_cls = 9130;
+  const base::HistogramBase::Sample32 max_cls = 9130;
   EXPECT_THAT(tester()->histogram_tester().GetAllSamples(
                   "PageLoad.LayoutInstability."
                   "MaxCumulativeShiftScoreAtFirstOnHidden.SessionWindow."
diff --git a/chrome/browser/page_load_metrics/observers/scheme_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/scheme_page_load_metrics_observer_unittest.cc
index d8fb774..01b041d 100644
--- a/chrome/browser/page_load_metrics/observers/scheme_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/scheme_page_load_metrics_observer_unittest.cc
@@ -106,7 +106,7 @@
         prefix + ".PaintTiming.ParseStartToFirstContentfulPaint", 1);
     tester()->histogram_tester().ExpectUniqueSample(
         prefix + ".PaintTiming.ParseStartToFirstContentfulPaint",
-        static_cast<base::HistogramBase::Sample>(200), 1);
+        static_cast<base::HistogramBase::Sample32>(200), 1);
     tester()->histogram_tester().ExpectTotalCount(
         prefix + ".Experimental.PaintTiming.NavigationToFirstMeaningfulPaint",
         1);
diff --git a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_browsertest.cc
index f6c2bf7..1a73067 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_browsertest.cc
@@ -97,17 +97,17 @@
   for (auto feature : features_0) {
     histogram_tester().ExpectBucketCount(
         "Blink.UseCounter.Features",
-        static_cast<base::Histogram::Sample>(feature), 1);
+        static_cast<base::Histogram::Sample32>(feature), 1);
     histogram_tester().ExpectBucketCount(
         "Blink.UseCounter.MainFrame.Features",
-        static_cast<base::Histogram::Sample>(feature), 1);
+        static_cast<base::Histogram::Sample32>(feature), 1);
   }
   for (auto feature : features_1) {
     histogram_tester().ExpectBucketCount(
         "Blink.UseCounter.Features",
-        static_cast<base::Histogram::Sample>(feature), 1);
+        static_cast<base::Histogram::Sample32>(feature), 1);
     histogram_tester().ExpectBucketCount(
         "Blink.UseCounter.MainFrame.Features",
-        static_cast<base::Histogram::Sample>(feature), 1);
+        static_cast<base::Histogram::Sample32>(feature), 1);
   }
 }
diff --git a/chrome/browser/password_manager/android/password_manager_android_browsertest.cc b/chrome/browser/password_manager/android/password_manager_android_browsertest.cc
index 13c740b..e71cd9a 100644
--- a/chrome/browser/password_manager/android/password_manager_android_browsertest.cc
+++ b/chrome/browser/password_manager/android/password_manager_android_browsertest.cc
@@ -83,7 +83,7 @@
         histogram_name,
         base::BindLambdaForTesting(
             [&](const char* histogram_name, uint64_t name_hash,
-                base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+                base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
     run_loop.Run();
   }
 
diff --git a/chrome/browser/password_manager/password_change_browsertest.cc b/chrome/browser/password_manager/password_change_browsertest.cc
index a7dae02..82516ca 100644
--- a/chrome/browser/password_manager/password_change_browsertest.cc
+++ b/chrome/browser/password_manager/password_change_browsertest.cc
@@ -427,3 +427,28 @@
       PasswordBubbleViewBase::manage_password_bubble();
   ASSERT_FALSE(bubble);
 }
+
+#if !BUILDFLAG(IS_ANDROID)
+IN_PROC_BROWSER_TEST_F(PasswordChangeBrowserTest, OpenTabWithPasswordChange) {
+  SetPrivacyNoticeAcceptedPref();
+
+  GURL main_url("https://example.com/");
+  GURL change_password_url =
+      embedded_test_server()->GetURL("/password/update_form_empty_fields.html");
+
+  EXPECT_CALL(*affiliation_service(), GetChangePasswordURL(main_url))
+      .WillOnce(testing::Return(change_password_url));
+  password_change_service()->StartPasswordChange(main_url, u"test", u"password",
+                                                 WebContents());
+
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+  ASSERT_EQ(2, tab_strip->count());
+
+  EXPECT_EQ(0, tab_strip->active_index());
+  password_change_service()
+      ->GetPasswordChangeDelegate(WebContents())
+      ->OpenPasswordChangeTab();
+
+  EXPECT_EQ(1, tab_strip->active_index());
+}
+#endif
diff --git a/chrome/browser/password_manager/password_change_delegate.h b/chrome/browser/password_manager/password_change_delegate.h
index 94ddf1b..a0361c9 100644
--- a/chrome/browser/password_manager/password_change_delegate.h
+++ b/chrome/browser/password_manager/password_change_delegate.h
@@ -61,6 +61,12 @@
   // invoked after this function is called as the object will soon be destroyed.
   virtual void Stop() = 0;
 
+#if !BUILDFLAG(IS_ANDROID)
+  // Brings a tab where password change is ongoing. Does nothing if the tab
+  // doesn't exist anymore.
+  virtual void OpenPasswordChangeTab() = 0;
+#endif
+
   // Informs delegate about successful form submission.
   virtual void SuccessfulSubmissionDetected(
       content::WebContents* web_contents) = 0;
diff --git a/chrome/browser/password_manager/password_change_delegate_impl.cc b/chrome/browser/password_manager/password_change_delegate_impl.cc
index ced6713..6d64c72 100644
--- a/chrome/browser/password_manager/password_change_delegate_impl.cc
+++ b/chrome/browser/password_manager/password_change_delegate_impl.cc
@@ -19,6 +19,12 @@
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
+#include "chrome/browser/ui/tabs/public/tab_interface.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#endif
+
 namespace {
 
 using password_manager::PasswordForm;
@@ -83,13 +89,13 @@
                   : PasswordChangeDelegate::State::kWaitingForAgreement);
   if (GetCurrentState() ==
       PasswordChangeDelegate::State::kWaitingForChangePasswordForm) {
-    OpenPasswordChangeTab();
+    StartPasswordChange();
   }
 }
 
 PasswordChangeDelegateImpl::~PasswordChangeDelegateImpl() = default;
 
-void PasswordChangeDelegateImpl::OpenPasswordChangeTab() {
+void PasswordChangeDelegateImpl::StartPasswordChange() {
   CHECK(originator_);
   content::WebContents* new_tab =
       std::move(open_password_change_tab_callback_)
@@ -146,6 +152,20 @@
                     this);
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+void PasswordChangeDelegateImpl::OpenPasswordChangeTab() {
+  if (executor_) {
+    auto* tab_interface = tabs::TabInterface::GetFromContents(executor_.get());
+    CHECK(tab_interface);
+
+    auto* tabs_strip =
+        tab_interface->GetBrowserWindowInterface()->GetTabStripModel();
+    tabs_strip->ActivateTabAt(
+        tabs_strip->GetIndexOfWebContents(executor_.get()));
+  }
+}
+#endif
+
 void PasswordChangeDelegateImpl::SuccessfulSubmissionDetected(
     content::WebContents* web_contents) {
   if (executor_ && executor_.get() == web_contents && form_manager_) {
@@ -185,7 +205,7 @@
   profile->GetPrefs()->SetBoolean(
       password_manager::prefs::kPasswordChangeFlowNoticeAgreement, true);
   UpdateState(PasswordChangeDelegate::State::kWaitingForChangePasswordForm);
-  OpenPasswordChangeTab();
+  StartPasswordChange();
 }
 
 void PasswordChangeDelegateImpl::UpdateState(
diff --git a/chrome/browser/password_manager/password_change_delegate_impl.h b/chrome/browser/password_manager/password_change_delegate_impl.h
index 00d60ad0..5de40702 100644
--- a/chrome/browser/password_manager/password_change_delegate_impl.h
+++ b/chrome/browser/password_manager/password_change_delegate_impl.h
@@ -53,6 +53,9 @@
   bool IsPasswordChangeOngoing(content::WebContents* web_contents) override;
   State GetCurrentState() const override;
   void Stop() override;
+#if !BUILDFLAG(IS_ANDROID)
+  void OpenPasswordChangeTab() override;
+#endif
   void SuccessfulSubmissionDetected(
       content::WebContents* web_contents) override;
   void OnPrivacyNoticeAccepted() override;
@@ -65,8 +68,9 @@
   // content::WebContentsObserver Impl
   void WebContentsDestroyed() override;
 
-  // Opens the tab for password change and observes it.
-  void OpenPasswordChangeTab();
+  // Opens the tab for password change and start looking for change password
+  // form.
+  void StartPasswordChange();
 
   // Updates `current_state_` and notifies `observers_`.
   void UpdateState(State new_state);
diff --git a/chrome/browser/password_manager/password_change_delegate_mock.h b/chrome/browser/password_manager/password_change_delegate_mock.h
index 75a83f7..b342c4a 100644
--- a/chrome/browser/password_manager/password_change_delegate_mock.h
+++ b/chrome/browser/password_manager/password_change_delegate_mock.h
@@ -29,6 +29,7 @@
               (),
               (const override));
   MOCK_METHOD(void, Stop, (), (override));
+  MOCK_METHOD(void, OpenPasswordChangeTab, (), (override));
   MOCK_METHOD(void,
               SuccessfulSubmissionDetected,
               (content::WebContents*),
diff --git a/chrome/browser/permissions/chrome_permission_request_manager_unittest.cc b/chrome/browser/permissions/chrome_permission_request_manager_unittest.cc
index 5ef9e9a..02045d61 100644
--- a/chrome/browser/permissions/chrome_permission_request_manager_unittest.cc
+++ b/chrome/browser/permissions/chrome_permission_request_manager_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #include <stddef.h>
 
 #include <optional>
@@ -174,12 +173,12 @@
   WaitForBubbleToBeShown();
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptShown,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::PERMISSION_GEOLOCATION),
       1);
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptShownGesture,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::PERMISSION_GEOLOCATION),
       1);
   histograms.ExpectTotalCount(
@@ -189,7 +188,7 @@
   Accept();
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptAccepted,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::PERMISSION_GEOLOCATION),
       1);
   histograms.ExpectTotalCount(
@@ -197,7 +196,7 @@
 
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptAcceptedGesture,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::PERMISSION_GEOLOCATION),
       1);
   histograms.ExpectTotalCount(
@@ -216,7 +215,7 @@
       permissions::PermissionUmaUtil::kPermissionsPromptShownGesture, 0);
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptShownNoGesture,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::DOWNLOAD),
       1);
   histograms.ExpectTotalCount("Permissions.Engagement.Denied.MultipleDownload",
@@ -229,13 +228,13 @@
       permissions::PermissionUmaUtil::kPermissionsPromptAccepted, 0);
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptDenied,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::DOWNLOAD),
       1);
 
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptDeniedNoGesture,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::DOWNLOAD),
       1);
   histograms.ExpectTotalCount(
@@ -254,7 +253,7 @@
 
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptShown,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::MULTIPLE_AUDIO_AND_VIDEO_CAPTURE),
       1);
   histograms.ExpectTotalCount(
@@ -268,7 +267,7 @@
 
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptAccepted,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::MULTIPLE_AUDIO_AND_VIDEO_CAPTURE),
       1);
   histograms.ExpectUniqueSample(
@@ -291,7 +290,7 @@
 
   histograms.ExpectUniqueSample(
       permissions::PermissionUmaUtil::kPermissionsPromptDenied,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::RequestTypeForUma::MULTIPLE_AUDIO_AND_VIDEO_CAPTURE),
       1);
   histograms.ExpectUniqueSample(
diff --git a/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc b/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc
index a24e840..f1ab4d00 100644
--- a/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc
+++ b/chrome/browser/permissions/contextual_notification_permission_ui_selector_unittest.cc
@@ -666,7 +666,7 @@
                                  Decision::UseNormalUi(),
                                  WarningReason::kAbusiveContent);
 
-    auto expected_bucket = static_cast<base::HistogramBase::Sample>(
+    auto expected_bucket = static_cast<base::HistogramBase::Sample32>(
         test.expected_histogram_bucket);
     histograms.ExpectBucketCount("Permissions.CrowdDeny.DidHoldbackQuietUi",
                                  expected_bucket, 1);
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index e802e4c..a9162e99 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -782,7 +782,7 @@
   void ExpectBlocklistedFeature(
       blink::scheduler::WebSchedulerTrackedFeature feature,
       base::Location location) {
-    base::HistogramBase::Sample sample = base::HistogramBase::Sample(feature);
+    base::HistogramBase::Sample32 sample = base::HistogramBase::Sample(feature);
     AddSampleToBuckets(&expected_blocklisted_features_, sample);
 
     EXPECT_THAT(
@@ -802,7 +802,7 @@
 
  private:
   void AddSampleToBuckets(std::vector<base::Bucket>* buckets,
-                          base::HistogramBase::Sample sample) {
+                          base::HistogramBase::Sample32 sample) {
     auto it = base::ranges::find(*buckets, sample, &base::Bucket::min);
     if (it == buckets->end()) {
       buckets->push_back(base::Bucket(sample, 1));
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc
index d1e6cd5..c13d7328 100644
--- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc
+++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_browsertest.cc
@@ -951,7 +951,7 @@
         histogram_name,
         base::BindLambdaForTesting([&](const char* histogram_name,
                                        uint64_t name_hash,
-                                       base::HistogramBase::Sample sample) {
+                                       base::HistogramBase::Sample32 sample) {
           if (GetTotalSampleCount(histogram_name) >= expected_sample_count) {
             run_loop.Quit();
           }
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index b0528b0b..f99e157 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -565,14 +565,10 @@
 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
         // BUILDFLAG(IS_WIN)
 
-namespace chrome {
-
 void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsProfiles>());
 }
 
-}  // namespace chrome
-
 ChromeBrowserMainExtraPartsProfiles::ChromeBrowserMainExtraPartsProfiles() =
     default;
 
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h
index a25f907a..e55a5225 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h
@@ -9,9 +9,7 @@
 
 class ChromeBrowserMainParts;
 
-namespace chrome {
 void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts);
-}
 
 class ChromeBrowserMainExtraPartsProfiles : public ChromeBrowserMainExtraParts {
  public:
diff --git a/chrome/browser/resources/settings/ai_page/history_search_page.html b/chrome/browser/resources/settings/ai_page/history_search_page.html
index 893f251..52a2c85 100644
--- a/chrome/browser/resources/settings/ai_page/history_search_page.html
+++ b/chrome/browser/resources/settings/ai_page/history_search_page.html
@@ -14,6 +14,10 @@
   cr-icon {
     flex-shrink: 0;
   }
+
+  cr-policy-pref-indicator {
+    margin-inline-end: 4px;
+  }
 </style>
 
 <template is="dom-if" if="[[!enableAiSettingsPageRefresh_]]" restamp>
@@ -67,31 +71,47 @@
 
 <template is="dom-if" if="[[enableAiSettingsPageRefresh_]]" restamp>
   <div class="settings-row first">
-    <cr-link-row label="$i18n{historySearchSettingLabel}"
-        on-click="onHistorySearchLinkoutClick_" external>
-      <div slot="sub-label">
-        <span id="linkoutText" hidden="[[isAnswersFeatureEnabled_]]">
-          $i18n{historySearchSettingSublabelV2}$i18n{sentenceEnd}
-        </span>
-        <span id="linkoutTextWithAnswers"
-            hidden="[[!isAnswersFeatureEnabled_]]">
-          $i18n{historySearchWithAnswersSettingSublabelV2}$i18n{sentenceEnd}
-        </span>
-        <a href="[[getLearnMoreUrl_(enterprisePref_)]]"
-            aria-label="$i18n{historySearchLearnMoreA11yLabel}"
-            on-click="onLearnMoreClick_" target="_blank">
-          $i18n{learnMore}
-        </a>
+    <template is="dom-if" if="[[!isDisabledByPolicy_(enterprisePref_)]]"
+        restamp>
+      <cr-link-row label="$i18n{historySearchSettingLabel}"
+          on-click="onHistorySearchLinkoutClick_" external>
+        <div slot="sub-label">
+          <span id="linkoutText">[[toggleSubLabelV2_]]</span>
+          <a href="[[getLearnMoreUrl_(enterprisePref_)]]"
+              aria-label="$i18n{historySearchLearnMoreA11yLabel}"
+              on-click="onLearnMoreClick_" target="_blank">
+            $i18n{learnMore}
+          </a>
+        </div>
+      </cr-link-row>
+      <div class="separator"></div>
+    </template>
+    <template is="dom-if" if="[[isDisabledByPolicy_(enterprisePref_)]]" restamp>
+      <div class="cr-row first">
+        <div class="flex cr-padded-text">
+          <div id="historySearchLabel">$i18n{historySearchSettingLabel}</div>
+          <div class="secondary">
+            [[toggleSubLabelV2_]]
+            <a href="[[getLearnMoreUrl_(enterprisePref_)]]"
+                aria-label="$i18n{historySearchLearnMoreA11yLabel}"
+                on-click="onLearnMoreClick_" target="_blank">
+              $i18n{learnMore}
+            </a>
+          </div>
+        </div>
       </div>
-    </cr-link-row>
-    <div class="separator"></div>
+      <cr-policy-pref-indicator id="policyIndicator"
+            pref="[[enterprisePref_]]">
+      </cr-policy-pref-indicator>
+    </template>
     <settings-toggle-button aria-label="$i18n{historySearchSettingLabel}"
         learn-more-url="[[getLearnMoreUrl_(enterprisePref_)]]"
         learn-more-aria-label="$i18n{historySearchLearnMoreA11yLabel}"
         pref="{{prefs.optimization_guide.history_search_setting_state}}"
         numeric-unchecked-values="[[numericUncheckedValues_]]"
         numeric-checked-value="[[featureOptInStateEnum_.ENABLED]]"
-        on-settings-boolean-control-change="onHistorySearchToggleChange_">
+        on-settings-boolean-control-change="onHistorySearchToggleChange_"
+        disabled="[[isDisabledByPolicy_(enterprisePref_)]]">
     </settings-toggle-button>
   </div>
   <div class="settings-columned-section">
diff --git a/chrome/browser/resources/settings/ai_page/history_search_page.ts b/chrome/browser/resources/settings/ai_page/history_search_page.ts
index 64461c3..6d06ec4b 100644
--- a/chrome/browser/resources/settings/ai_page/history_search_page.ts
+++ b/chrome/browser/resources/settings/ai_page/history_search_page.ts
@@ -17,6 +17,7 @@
 import {AiPageHistorySearchInteractions, MetricsBrowserProxyImpl} from '../metrics_browser_proxy.js';
 
 import {getAiLearnMoreUrl} from './ai_learn_more_url_util.js';
+import {isFeatureDisabledByPolicy} from './ai_policy_indicator.js';
 import {AiEnterpriseFeaturePrefName, AiPageActions, FeatureOptInState} from './constants.js';
 import {getTemplate} from './history_search_page.html.js';
 
@@ -65,6 +66,19 @@
         },
       },
 
+      toggleSubLabelV2_: {
+        type: String,
+        value: () => {
+          return (loadTimeData.getBoolean(
+                      'historyEmbeddingsAnswersFeatureEnabled') ?
+                      loadTimeData.getString(
+                          'historySearchWithAnswersSettingSublabelV2') :
+                      loadTimeData.getString(
+                          'historySearchSettingSublabelV2')) +
+              loadTimeData.getString('sentenceEnd');
+        },
+      },
+
       enterprisePref_: {
         type: Object,
         computed:
@@ -124,6 +138,10 @@
         loadTimeData.getString('historySearchLearnMoreUrl'),
         loadTimeData.getString('historySearchLearnMoreManagedUrl'));
   }
+
+  private isDisabledByPolicy_(): boolean {
+    return isFeatureDisabledByPolicy(this.enterprisePref_);
+  }
 }
 
 declare global {
diff --git a/chrome/browser/segmentation_platform/service_browsertest.cc b/chrome/browser/segmentation_platform/service_browsertest.cc
index 244488f..13a0617 100644
--- a/chrome/browser/segmentation_platform/service_browsertest.cc
+++ b/chrome/browser/segmentation_platform/service_browsertest.cc
@@ -289,7 +289,7 @@
         histogram_name,
         base::BindLambdaForTesting(
             [&](const char* histogram_name, uint64_t name_hash,
-                base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+                base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
     run_loop.Run();
   }
 
diff --git a/chrome/browser/signin/android/signin_metrics_utils.cc b/chrome/browser/signin/android/signin_metrics_utils.cc
index 30ab1b9..a33fbd6 100644
--- a/chrome/browser/signin/android/signin_metrics_utils.cc
+++ b/chrome/browser/signin/android/signin_metrics_utils.cc
@@ -26,7 +26,7 @@
                signin_metrics::AccountConsistencyPromoAction::kMaxValue));
   CHECK_GE(access_point, 0);
   CHECK_LE(access_point,
-           static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX));
+           static_cast<int>(signin_metrics::AccessPoint::kMaxValue));
   signin_metrics::RecordConsistencyPromoUserAction(
       static_cast<signin_metrics::AccountConsistencyPromoAction>(promo_action),
       static_cast<signin_metrics::AccessPoint>(access_point));
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index ad04c92..b8a5170 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -383,16 +383,13 @@
     }
   }
 
-  if (base::FeatureList::IsEnabled(
-          ::switches::kPreconnectAccountCapabilitiesPostSignin)) {
-    // The user is signing in, which means that account fetching will shortly be
-    // triggered.
-    //
-    // Notify identity manager. This will trigger pre-connecting the network
-    // socket to the AccountCapabilities endpoint, in parallel with the LST and
-    // access token requests (instead of waiting for these to complete).
-    identity_manager_->PrepareForAddingNewAccount();
-  }
+  // The user is signing in, which means that account fetching will shortly be
+  // triggered.
+  //
+  // Notify identity manager. This will trigger pre-connecting the network
+  // socket to the AccountCapabilities endpoint, in parallel with the LST and
+  // access token requests (instead of waiting for these to complete).
+  identity_manager_->PrepareForAddingNewAccount();
 
 #if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
   base::expected<raw_ref<RegistrationTokenHelper>, TokenBindingOutcome>
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 4770e6f..e1bd6db 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -411,24 +411,7 @@
   }
 }
 
-class SigninDiceResponseHandlerTestPreconnect
-    : public DiceResponseHandlerTest,
-      public ::testing::WithParamInterface<bool> {
- public:
-  SigninDiceResponseHandlerTestPreconnect() {
-    feature_list_.InitWithFeatureState(
-        switches::kPreconnectAccountCapabilitiesPostSignin,
-        PreconnectEnabled());
-  }
-
-  bool PreconnectEnabled() { return GetParam(); }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-// Checks that a SIGNIN action triggers a token exchange request.
-TEST_P(SigninDiceResponseHandlerTestPreconnect, Signin) {
+TEST_F(DiceResponseHandlerTest, Signin) {
   DiceResponseParams dice_params = MakeDiceParams(DiceAction::SIGNIN);
   const auto& account_info = dice_params.signin_info->account_info;
   CoreAccountId account_id = identity_manager()->PickAccountIdForAccount(
@@ -464,7 +447,7 @@
             signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS);
   EXPECT_EQ(
       identity_test_env_.GetNumCallsToPrepareForFetchingAccountCapabilities(),
-      PreconnectEnabled() ? 1 : 0);
+      1);
 #if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
   histogram_tester_.ExpectUniqueSample(
       kTokenBindingOutcomeHistogram,
@@ -473,10 +456,6 @@
 #endif  // BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
 }
 
-INSTANTIATE_TEST_SUITE_P(PreconnectEnabled,
-                         SigninDiceResponseHandlerTestPreconnect,
-                         ::testing::Bool());
-
 #if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
 // Checks that a SIGNIN action triggers a token exchange request.
 TEST_F(DiceResponseHandlerTest, SigninWithBoundToken) {
diff --git a/chrome/browser/signin/dice_tab_helper.cc b/chrome/browser/signin/dice_tab_helper.cc
index 7c1b58f..3ccc944 100644
--- a/chrome/browser/signin/dice_tab_helper.cc
+++ b/chrome/browser/signin/dice_tab_helper.cc
@@ -142,8 +142,7 @@
 
   if (signin_util::IsSigninPending(identity_manager)) {
     base::UmaHistogramEnumeration(
-        "Signin.SigninPending.ResolutionSourceStarted", access_point,
-        signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+        "Signin.SigninPending.ResolutionSourceStarted", access_point);
   }
 }
 
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl.cc b/chrome/browser/signin/process_dice_header_delegate_impl.cc
index f485eeff..5e3eb997 100644
--- a/chrome/browser/signin/process_dice_header_delegate_impl.cc
+++ b/chrome/browser/signin/process_dice_header_delegate_impl.cc
@@ -81,9 +81,8 @@
            access_point);
 
   if (!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
-    base::UmaHistogramEnumeration(
-        "Signin.SigninManager.SigninAccessPoint", access_point,
-        signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+    base::UmaHistogramEnumeration("Signin.SigninManager.SigninAccessPoint",
+                                  access_point);
     identity_manager->GetPrimaryAccountMutator()->SetPrimaryAccount(
         account_id, signin::ConsentLevel::kSignin, access_point);
   }
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java
index 9dbbe34..0cb20f92 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninMetricsUtils.java
@@ -65,7 +65,7 @@
      */
     public static void logSyncConsentStarted(@SigninAccessPoint int accessPoint) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.SigninStartedAccessPoint", accessPoint, SigninAccessPoint.MAX);
+                "Signin.SigninStartedAccessPoint", accessPoint, SigninAccessPoint.MAX_VALUE);
     }
 
     /**
@@ -76,7 +76,7 @@
      */
     public static void logSigninStarted(@SigninAccessPoint int accessPoint) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.SignIn.Started", accessPoint, SigninAccessPoint.MAX);
+                "Signin.SignIn.Started", accessPoint, SigninAccessPoint.MAX_VALUE);
     }
 
     /** Logs signin user action for a given {@link SigninAccessPoint}. */
@@ -97,14 +97,14 @@
     public static void logHistorySyncAcceptButtonClicked(
             @SigninAccessPoint int accessPoint, @SyncButtonClicked int syncButtonType) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.Completed", accessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.Completed", accessPoint, SigninAccessPoint.MAX_VALUE);
         recordButtonTypeClicked(syncButtonType);
     }
 
     public static void logHistorySyncDeclineButtonClicked(
             @SigninAccessPoint int accessPoint, @SyncButtonClicked int syncButtonType) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.Declined", accessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.Declined", accessPoint, SigninAccessPoint.MAX_VALUE);
         recordButtonTypeClicked(syncButtonType);
     }
 
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index 32055a9e..fcdcc8bc 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -142,9 +142,8 @@
         access_point =
             signin_metrics::AccessPoint::ACCESS_POINT_DESKTOP_SIGNIN_MANAGER;
       }
-      base::UmaHistogramEnumeration(
-          "Signin.SigninManager.SigninAccessPoint", access_point,
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+      base::UmaHistogramEnumeration("Signin.SigninManager.SigninAccessPoint",
+                                    access_point);
       identity_manager_->GetPrimaryAccountMutator()->SetPrimaryAccount(
           account.account_id, signin::ConsentLevel::kSignin, access_point);
     }
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc
index 6506d585..21c269b3 100644
--- a/chrome/browser/signin/signin_promo.cc
+++ b/chrome/browser/signin/signin_promo.cc
@@ -40,8 +40,8 @@
 GURL GetEmbeddedPromoURL(signin_metrics::AccessPoint access_point,
                          signin_metrics::Reason reason,
                          bool auto_close) {
-  CHECK_LT(static_cast<int>(access_point),
-           static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX));
+  CHECK_LE(static_cast<int>(access_point),
+           static_cast<int>(signin_metrics::AccessPoint::kMaxValue));
   CHECK_NE(static_cast<int>(access_point),
            static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN));
   CHECK_LE(static_cast<int>(reason),
@@ -140,8 +140,7 @@
   if (access_point <
           static_cast<int>(
               signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE) ||
-      access_point >=
-          static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX)) {
+      access_point > static_cast<int>(signin_metrics::AccessPoint::kMaxValue)) {
     return signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN;
   }
 
diff --git a/chrome/browser/site_protection/site_protection_metrics_observer_unittest.cc b/chrome/browser/site_protection/site_protection_metrics_observer_unittest.cc
index 209400e..38e5e0d1 100644
--- a/chrome/browser/site_protection/site_protection_metrics_observer_unittest.cc
+++ b/chrome/browser/site_protection/site_protection_metrics_observer_unittest.cc
@@ -154,7 +154,7 @@
         histogram_name,
         base::BindLambdaForTesting(
             [&](const char* histogram_name, uint64_t name_hash,
-                base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+                base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
     NavigateAndCommit(url);
     run_loop.Run();
   }
@@ -337,7 +337,7 @@
       "SafeBrowsing.SiteProtection.FamiliarityHeuristic",
       base::BindLambdaForTesting(
           [&](const char* histogram_name, uint64_t name_hash,
-              base::HistogramBase::Sample sample) { run_loop.Quit(); }));
+              base::HistogramBase::Sample32 sample) { run_loop.Quit(); }));
 
   NavigateAndCommit(kUrl, ui::PAGE_TRANSITION_TYPED);
   run_loop.Run();
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncConsentFragmentBase.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncConsentFragmentBase.java
index d15b4ceb..c602769a 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncConsentFragmentBase.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncConsentFragmentBase.java
@@ -283,8 +283,10 @@
         super.onCreate(savedInstanceState);
 
         Bundle arguments = getArguments();
-        mSigninAccessPoint = arguments.getInt(ARGUMENT_ACCESS_POINT, SigninAccessPoint.MAX);
-        assert mSigninAccessPoint != SigninAccessPoint.MAX : "Cannot find SigninAccessPoint!";
+        mSigninAccessPoint = arguments.getInt(ARGUMENT_ACCESS_POINT,
+                                              SigninAccessPoint.MAX_VALUE);
+        assert mSigninAccessPoint <=
+            SigninAccessPoint.MAX_VALUE : "Cannot find SigninAccessPoint!";
 
         // TODO(crbug.com/40828116): remove usage of Profile.isChild() and the need for a bundle
         // argument in the FRE, but moving to a new API for determining device supervision status.
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncCoordinator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncCoordinator.java
index c1ed6a2..9d1f6b460 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncCoordinator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncCoordinator.java
@@ -80,7 +80,7 @@
 
         setView(view, mUseLandscapeLayout);
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.Started", accessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.Started", accessPoint, SigninAccessPoint.MAX_VALUE);
         MinorModeHelper.resolveMinorMode(
                 IdentityServicesProvider.get().getSigninManager(mProfile).getIdentityManager(),
                 IdentityServicesProvider.get()
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncHelper.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncHelper.java
index 2033d209c..da3c614 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncHelper.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncHelper.java
@@ -115,11 +115,13 @@
 
     private void recordUserAlreadyOptedIn(@SigninAccessPoint int accessPoint) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.AlreadyOptedIn", accessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.AlreadyOptedIn", accessPoint,
+                SigninAccessPoint.MAX_VALUE);
     }
 
     private void recordHistorySyncSkipped(@SigninAccessPoint int accessPoint) {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.Skipped", accessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.Skipped", accessPoint,
+                SigninAccessPoint.MAX_VALUE);
     }
 }
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncMediator.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncMediator.java
index 00ab393..50c211d 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncMediator.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/history_sync/HistorySyncMediator.java
@@ -98,7 +98,7 @@
     @Override
     public void onSignedOut() {
         RecordHistogram.recordEnumeratedHistogram(
-                "Signin.HistorySyncOptIn.Aborted", mAccessPoint, SigninAccessPoint.MAX);
+                "Signin.HistorySyncOptIn.Aborted", mAccessPoint, SigninAccessPoint.MAX_VALUE);
         mDelegate.dismissHistorySync(/* isHistorySyncAccepted= */ false);
     }
 
diff --git a/chrome/browser/ui/ash/quick_insert/quick_insert_accessibility_browsertest.cc b/chrome/browser/ui/ash/quick_insert/quick_insert_accessibility_browsertest.cc
index 7f36cf9..71222e1 100644
--- a/chrome/browser/ui/ash/quick_insert/quick_insert_accessibility_browsertest.cc
+++ b/chrome/browser/ui/ash/quick_insert/quick_insert_accessibility_browsertest.cc
@@ -389,7 +389,18 @@
   sm_.Replay();
 }
 
-IN_PROC_BROWSER_TEST_F(QuickInsertAccessibilityBrowserTest,
+class QuickInsertAccessibilityWithGifsFlagDisabledBrowserTest
+    : public QuickInsertAccessibilityBrowserTest {
+ public:
+  QuickInsertAccessibilityWithGifsFlagDisabledBrowserTest() {
+    scoped_feature_list_.InitAndDisableFeature(ash::features::kPickerGifs);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(QuickInsertAccessibilityWithGifsFlagDisabledBrowserTest,
                        FocusingGifsButtonAnnouncesLabel) {
   std::unique_ptr<views::Widget> widget =
       ash::TestWidgetBuilder()
diff --git a/chrome/browser/ui/ash/quick_insert/quick_insert_interactive_uitest.cc b/chrome/browser/ui/ash/quick_insert/quick_insert_interactive_uitest.cc
index 56d059f..8a40209 100644
--- a/chrome/browser/ui/ash/quick_insert/quick_insert_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/quick_insert/quick_insert_interactive_uitest.cc
@@ -300,7 +300,19 @@
       WaitForShow(ash::kEmojiPickerElementId));
 }
 
-IN_PROC_BROWSER_TEST_F(QuickInsertInteractiveUiTest, SearchGifs) {
+class QuickInsertWithGifsDisabledInteractiveUiTest
+    : public QuickInsertInteractiveUiTest {
+ public:
+  QuickInsertWithGifsDisabledInteractiveUiTest() {
+    feature_list_.InitAndDisableFeature(ash::features::kPickerGifs);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsDisabledInteractiveUiTest,
+                       SearchGifs) {
   ASSERT_TRUE(CreateBrowserWindow(
       GURL("data:text/html,<input type=\"text\" autofocus/>")));
   const ui::ElementContext browser_context =
@@ -395,17 +407,18 @@
   std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
 };
 
-class QuickInsertWithGifsInteractiveUiTest
+class QuickInsertWithGifsEnabledInteractiveUiTest
     : public QuickInsertInteractiveUiTest {
  public:
-  QuickInsertWithGifsInteractiveUiTest()
+  QuickInsertWithGifsEnabledInteractiveUiTest()
       : feature_list_(ash::features::kPickerGifs) {}
 
  private:
   base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsInteractiveUiTest, SearchGifs) {
+IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsEnabledInteractiveUiTest,
+                       SearchGifs) {
   FakeTenorServer fake_tenor_server;
   // TODO: b/360229206 - Use a contenteditable input field so the file can be
   // inserted.
@@ -442,7 +455,8 @@
       WaitForHide(ash::kQuickInsertElementId));
 }
 
-IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsInteractiveUiTest, FeatureGifs) {
+IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsEnabledInteractiveUiTest,
+                       FeatureGifs) {
   FakeTenorServer fake_tenor_server;
   // TODO: b/360229206 - Use a contenteditable input field so the file can be
   // inserted.
@@ -475,7 +489,8 @@
       WaitForHide(ash::kQuickInsertElementId));
 }
 
-IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsInteractiveUiTest, ToggleGifs) {
+IN_PROC_BROWSER_TEST_F(QuickInsertWithGifsEnabledInteractiveUiTest,
+                       ToggleGifs) {
   AddUrlToHistory(GetActiveUserProfile(), GURL("https://foo.com/history"));
   FakeTenorServer fake_tenor_server;
   // TODO: b/360229206 - Use a contenteditable input field so the file can be
diff --git a/chrome/browser/ui/autofill/autofill_bubble_signin_promo_controller.cc b/chrome/browser/ui/autofill/autofill_bubble_signin_promo_controller.cc
index 922037fb..d452b507 100644
--- a/chrome/browser/ui/autofill/autofill_bubble_signin_promo_controller.cc
+++ b/chrome/browser/ui/autofill/autofill_bubble_signin_promo_controller.cc
@@ -52,8 +52,7 @@
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   CHECK(switches::IsExplicitBrowserSigninUIOnDesktopEnabled());
 
-  base::UmaHistogramEnumeration("Signin.SignInPromo.Accepted", access_point_,
-                                signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration("Signin.SignInPromo.Accepted", access_point_);
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index c04d1f7c..8789e5f 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1233,7 +1233,7 @@
 #if BUILDFLAG(IS_WIN)
   {  // From launch_mode_recorder.cc:
     constexpr char kLaunchModesHistogram[] = "Launch.Mode2";
-    const base::HistogramBase::Sample kWebAppOther = 22;
+    const base::HistogramBase::Sample32 kWebAppOther = 22;
 
     tester.ExpectUniqueSample(kLaunchModesHistogram, kWebAppOther, 1);
   }
diff --git a/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.cc
index 834d73428b..51754c5 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.cc
@@ -41,3 +41,12 @@
 void FailedPasswordChangeBubbleController::ReportInteractions() {
   // TODO(crbug.com/381053884): Report metrics.
 }
+
+void FailedPasswordChangeBubbleController::FixManually() {
+  password_change_delegate_->OpenPasswordChangeTab();
+  FinishPasswordChange();
+}
+
+void FailedPasswordChangeBubbleController::FinishPasswordChange() {
+  password_change_delegate_->Stop();
+}
diff --git a/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.h b/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.h
index 5a03fe3..001878c 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.h
+++ b/chrome/browser/ui/passwords/bubble_controllers/password_change/failed_password_change_bubble_controller.h
@@ -26,6 +26,12 @@
   std::u16string GetBody() const;
   std::u16string GetAcceptButton() const;
 
+  // Opens a tab where password change is ongoing.
+  void FixManually();
+
+  // Marks password change flow as completed.
+  void FinishPasswordChange();
+
  private:
   base::WeakPtr<PasswordChangeDelegate> password_change_delegate_;
 };
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index f69f34e7..52ed4ad6 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -609,7 +609,7 @@
     bool edit_username;
     bool change_password;
     // The UMA sample expected for PasswordManager.EditsInSaveBubble.
-    base::HistogramBase::Sample expected_uma_sample;
+    base::HistogramBase::Sample32 expected_uma_sample;
   } kTests[] = {
       {false, false, 0}, {true, false, 1}, {false, true, 2}, {true, true, 3}};
 
diff --git a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper.cc b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper.cc
index 8f8cd24..f51372f1 100644
--- a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper.cc
+++ b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper.cc
@@ -250,8 +250,9 @@
   uint32_t host_hash = base::Hash(navigation_handle->GetURL().IsAboutBlank()
                                       ? "about:blank"
                                       : navigation_handle->GetURL().host());
-  base::UmaHistogramSparse("Settings.PrivacySandbox.DialogDisplayHost",
-                           static_cast<base::HistogramBase::Sample>(host_hash));
+  base::UmaHistogramSparse(
+      "Settings.PrivacySandbox.DialogDisplayHost",
+      static_cast<base::HistogramBase::Sample32>(host_hash));
 
   browser->tab_strip_model()->ActivateTabAt(
       browser->tab_strip_model()->GetIndexOfWebContents(
diff --git a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
index 8d363ba..3cfae609 100644
--- a/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
+++ b/chrome/browser/ui/privacy_sandbox/privacy_sandbox_prompt_helper_browsertest.cc
@@ -176,7 +176,7 @@
   base::RunLoop().RunUntilIdle();
   histogram_tester.ExpectUniqueSample(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("new-tab-page")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("new-tab-page")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
@@ -207,7 +207,7 @@
   base::RunLoop().RunUntilIdle();
   histogram_tester.ExpectUniqueSample(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("about:blank")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("about:blank")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
@@ -233,7 +233,7 @@
   base::RunLoop().RunUntilIdle();
   histogram_tester.ExpectUniqueSample(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("settings")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("settings")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
@@ -265,7 +265,7 @@
   base::RunLoop().RunUntilIdle();
   histogram_tester.ExpectUniqueSample(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("history")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("history")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
@@ -427,7 +427,7 @@
   base::RunLoop().RunUntilIdle();
   histogram_tester.ExpectUniqueSample(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("new-tab-page")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("new-tab-page")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
@@ -458,10 +458,10 @@
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
   histogram_tester.ExpectBucketCount(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("new-tab-page")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("new-tab-page")), 1);
   histogram_tester.ExpectBucketCount(
       kPrivacySandboxDialogDisplayHostHistogram,
-      static_cast<base::HistogramBase::Sample>(base::Hash("about:blank")), 1);
+      static_cast<base::HistogramBase::Sample32>(base::Hash("about:blank")), 1);
   ValidatePromptEventEntries(
       &histogram_tester,
       {{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
diff --git a/chrome/browser/ui/views/crostini/crostini_recovery_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_recovery_view_browsertest.cc
index 4ff9c65..3cf9265 100644
--- a/chrome/browser/ui/views/crostini/crostini_recovery_view_browsertest.cc
+++ b/chrome/browser/ui/views/crostini/crostini_recovery_view_browsertest.cc
@@ -135,7 +135,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.RecoverySource",
-      static_cast<base::HistogramBase::Sample>(kUiSurface), 0);
+      static_cast<base::HistogramBase::Sample32>(kUiSurface), 0);
 }
 
 IN_PROC_BROWSER_TEST_F(CrostiniRecoveryViewBrowserTest, Cancel) {
@@ -181,7 +181,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.RecoverySource",
-      static_cast<base::HistogramBase::Sample>(kUiSurface), 3);
+      static_cast<base::HistogramBase::Sample32>(kUiSurface), 3);
 }
 
 IN_PROC_BROWSER_TEST_F(CrostiniRecoveryViewBrowserTest, Accept) {
@@ -218,5 +218,5 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.RecoverySource",
-      static_cast<base::HistogramBase::Sample>(kUiSurface), 2);
+      static_cast<base::HistogramBase::Sample32>(kUiSurface), 2);
 }
diff --git a/chrome/browser/ui/views/crostini/crostini_uninstaller_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_uninstaller_view_browsertest.cc
index 13309f0f..e8a30ac4 100644
--- a/chrome/browser/ui/views/crostini/crostini_uninstaller_view_browsertest.cc
+++ b/chrome/browser/ui/views/crostini/crostini_uninstaller_view_browsertest.cc
@@ -135,7 +135,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UninstallResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniUninstallerView::UninstallResult::kSuccess),
       1);
 }
@@ -162,7 +162,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UninstallResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniUninstallerView::UninstallResult::kSuccess),
       1);
 }
@@ -178,7 +178,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UninstallResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniUninstallerView::UninstallResult::kCancelled),
       1);
 }
@@ -200,7 +200,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UninstallResult",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           CrostiniUninstallerView::UninstallResult::kError),
       1);
 }
diff --git a/chrome/browser/ui/views/crostini/crostini_update_filesystem_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_update_filesystem_view_browsertest.cc
index ec4bebd..905c3c93 100644
--- a/chrome/browser/ui/views/crostini/crostini_update_filesystem_view_browsertest.cc
+++ b/chrome/browser/ui/views/crostini/crostini_update_filesystem_view_browsertest.cc
@@ -99,7 +99,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UpgradeContainerSource",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           crostini::CrostiniUISurface::kAppList),
       1);
 }
@@ -137,7 +137,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UpgradeContainerSource",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           crostini::CrostiniUISurface::kAppList),
       1);
 }
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
index 129d67fc..1d13459 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
@@ -113,10 +113,10 @@
   EXPECT_TRUE(tab_2->HasFocus());
 
   move_forward_over_tab(tab_2);
-  EXPECT_TRUE(tab_search_button()->HasFocus());
+  EXPECT_TRUE(new_tab_button()->HasFocus());
 
   press_right();
-  EXPECT_TRUE(new_tab_button()->HasFocus());
+  EXPECT_TRUE(tab_search_button()->HasFocus());
 
   // Focus should cycle back around to tab_0.
   press_right();
@@ -153,10 +153,10 @@
 
   // Pressing left should immediately cycle back around to the last button.
   press_left();
-  EXPECT_TRUE(new_tab_button()->HasFocus());
+  EXPECT_TRUE(tab_search_button()->HasFocus());
 
   press_left();
-  EXPECT_TRUE(tab_search_button()->HasFocus());
+  EXPECT_TRUE(new_tab_button()->HasFocus());
 
   move_back_to_tab(tab_2);
   EXPECT_TRUE(tab_2->HasFocus());
@@ -186,12 +186,12 @@
 #if !BUILDFLAG(IS_WIN)
     EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed(
         tab_strip_region_view()->end_key()));
-    EXPECT_TRUE(tab_search_button()->HasFocus());
+    EXPECT_TRUE(new_tab_button()->HasFocus());
 #endif  // !BUILDFLAG(IS_WIN)
 
     EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed(
         tab_strip_region_view()->home_key()));
-    EXPECT_TRUE(new_tab_button()->HasFocus());
+    EXPECT_TRUE(tab_search_button()->HasFocus());
 
   } else {
     // The first tab should be active.
@@ -200,7 +200,7 @@
 #if !BUILDFLAG(IS_WIN)
     EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed(
         tab_strip_region_view()->end_key()));
-    EXPECT_TRUE(new_tab_button()->HasFocus());
+    EXPECT_TRUE(tab_search_button()->HasFocus());
 #endif  // !BUILDFLAG(IS_WIN)
 
     EXPECT_TRUE(tab_strip_region_view()->AcceleratorPressed(
diff --git a/chrome/browser/ui/views/passwords/password_change/failed_password_change_view.cc b/chrome/browser/ui/views/passwords/password_change/failed_password_change_view.cc
index 8ffe795..009f730 100644
--- a/chrome/browser/ui/views/passwords/password_change/failed_password_change_view.cc
+++ b/chrome/browser/ui/views/passwords/password_change/failed_password_change_view.cc
@@ -58,9 +58,22 @@
 
   SetButtons(static_cast<int>(ui::mojom::DialogButton::kOk));
   SetButtonLabel(ui::mojom::DialogButton::kOk, controller_->GetAcceptButton());
-  // TODO(crbug.com/381054978): Handle button click.
+  SetAcceptCallback(
+      base::BindOnce(&FailedPasswordChangeBubbleController::FixManually,
+                     base::Unretained(controller_.get())));
 
   SetFootnoteView(CreateFooterView());
+
+  SetCloseCallback(base::BindRepeating(
+      [](FailedPasswordChangeView* view) {
+        // When dialog is closed explicitly finish password change flow to
+        // transition into a default password manager state.
+        if (view->GetWidget()->closed_reason() ==
+            views::Widget::ClosedReason::kCloseButtonClicked) {
+          view->controller_->FinishPasswordChange();
+        }
+      },
+      this));
 }
 
 FailedPasswordChangeView::~FailedPasswordChangeView() = default;
diff --git a/chrome/browser/ui/views/passwords/password_change/failed_password_change_view_unittest.cc b/chrome/browser/ui/views/passwords/password_change/failed_password_change_view_unittest.cc
index d35918f5..6af1c28 100644
--- a/chrome/browser/ui/views/passwords/password_change/failed_password_change_view_unittest.cc
+++ b/chrome/browser/ui/views/passwords/password_change/failed_password_change_view_unittest.cc
@@ -37,12 +37,18 @@
   }
 
   void TearDown() override {
-    view_->GetWidget()->CloseWithReason(
-        views::Widget::ClosedReason::kUnspecified);
-    view_ = nullptr;
+    if (view_) {
+      CloseBubble();
+    }
     PasswordBubbleViewTestBase::TearDown();
   }
 
+  void CloseBubble(views::Widget::ClosedReason reason =
+                       views::Widget::ClosedReason::kUnspecified) {
+    view_->GetWidget()->CloseWithReason(reason);
+    view_ = nullptr;
+  }
+
   void CreateAndShowView() {
     CreateAnchorViewAndShow();
 
@@ -72,3 +78,32 @@
             l10n_util::GetStringUTF16(
                 IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_FAILED_ACTION));
 }
+
+TEST_F(FailedPasswordChangeViewTest, FixNowClick) {
+  CreateAndShowView();
+
+  EXPECT_CALL(*password_change_delegate(), OpenPasswordChangeTab);
+  EXPECT_CALL(*password_change_delegate(), Stop);
+  EXPECT_CALL(*model_delegate_mock(), OnBubbleHidden);
+
+  views::test::ButtonTestApi(view()->GetOkButton())
+      .NotifyClick(ui::test::TestEvent());
+}
+
+TEST_F(FailedPasswordChangeViewTest, SuppressingBubbleDoesNotStopTheFlow) {
+  CreateAndShowView();
+
+  EXPECT_CALL(*password_change_delegate(), Stop).Times(0);
+  EXPECT_CALL(*model_delegate_mock(), OnBubbleHidden);
+
+  CloseBubble();
+}
+
+TEST_F(FailedPasswordChangeViewTest, ClosingBubbleStopsTheFlow) {
+  CreateAndShowView();
+
+  EXPECT_CALL(*password_change_delegate(), Stop);
+  EXPECT_CALL(*model_delegate_mock(), OnBubbleHidden);
+
+  CloseBubble(views::Widget::ClosedReason::kCloseButtonClicked);
+}
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
index 8a6f881..e561d0d 100644
--- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -220,8 +220,8 @@
   std::vector<base::Bucket> buckets =
       histogram_tester.GetAllSamples("PaymentRequest.Events2");
   ASSERT_EQ(2U, buckets.size());
-  base::HistogramBase::Sample shown;
-  base::HistogramBase::Sample could_not_show;
+  base::HistogramBase::Sample32 shown;
+  base::HistogramBase::Sample32 could_not_show;
   // Order of histogram recording is non-deterministic. So use EVENT_SHOWN bit
   // to differentiate between the two histograms.
   if (buckets[0].min & toInt(Event2::kShown)) {
diff --git a/chrome/browser/ui/views/permissions/embedded_permission_prompt_interactive_uitest.cc b/chrome/browser/ui/views/permissions/embedded_permission_prompt_interactive_uitest.cc
index 95b1ae79..7e9af0a 100644
--- a/chrome/browser/ui/views/permissions/embedded_permission_prompt_interactive_uitest.cc
+++ b/chrome/browser/ui/views/permissions/embedded_permission_prompt_interactive_uitest.cc
@@ -158,7 +158,7 @@
                       int count) {
     return Steps(Do([=, &tester]() {
       tester.ExpectBucketCount(
-          view_name, static_cast<base::HistogramBase::Sample>(request_type),
+          view_name, static_cast<base::HistogramBase::Sample32>(request_type),
           count);
     }));
   }
diff --git a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
index 11e3bf0..82f93d01 100644
--- a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
@@ -243,7 +243,7 @@
     histograms_.ExpectUniqueSample(
         permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
             content_setting_type),
-        static_cast<base::HistogramBase::Sample>(event), occ);
+        static_cast<base::HistogramBase::Sample32>(event), occ);
   }
 
   void OtpEventExpectBucketCount(ContentSettingsType content_setting_type,
@@ -252,7 +252,7 @@
     histograms_.ExpectBucketCount(
         permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
             content_setting_type),
-        static_cast<base::HistogramBase::Sample>(event), occ);
+        static_cast<base::HistogramBase::Sample32>(event), occ);
   }
 
   std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_;
@@ -703,13 +703,13 @@
                               active_expiry_is_active ? 2 : 0);
   histograms.ExpectBucketCount(
       kActiveExpiryHistogram,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           content_settings_uma_util::ContentSettingTypeToHistogramValue(
               ContentSettingsType::MEDIASTREAM_MIC)),
       active_expiry_is_active ? 1 : 0);
   histograms.ExpectBucketCount(
       kActiveExpiryHistogram,
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           content_settings_uma_util::ContentSettingTypeToHistogramValue(
               ContentSettingsType::MEDIASTREAM_CAMERA)),
       active_expiry_is_active ? 1 : 0);
@@ -723,13 +723,13 @@
   histograms.ExpectBucketCount(
       permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
           ContentSettingsType::MEDIASTREAM_CAMERA),
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::OneTimePermissionEvent::GRANTED_ONE_TIME),
       active_expiry_is_active ? 2 : 1);
   histograms.ExpectBucketCount(
       permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
           ContentSettingsType::MEDIASTREAM_CAMERA),
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::OneTimePermissionEvent::EXPIRED_AFTER_MAXIMUM_LIFETIME),
       active_expiry_is_active ? 1 : 0);
 
@@ -740,13 +740,13 @@
   histograms.ExpectBucketCount(
       permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
           ContentSettingsType::MEDIASTREAM_MIC),
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::OneTimePermissionEvent::GRANTED_ONE_TIME),
       active_expiry_is_active ? 2 : 1);
   histograms.ExpectBucketCount(
       permissions::PermissionUmaUtil::GetOneTimePermissionEventHistogram(
           ContentSettingsType::MEDIASTREAM_MIC),
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::OneTimePermissionEvent::EXPIRED_AFTER_MAXIMUM_LIFETIME),
       active_expiry_is_active ? 1 : 0);
 
diff --git a/chrome/browser/ui/views/permissions/permission_metrics_ui_test.cc b/chrome/browser/ui/views/permissions/permission_metrics_ui_test.cc
index 38f30a5..0f622874 100644
--- a/chrome/browser/ui/views/permissions/permission_metrics_ui_test.cc
+++ b/chrome/browser/ui/views/permissions/permission_metrics_ui_test.cc
@@ -81,7 +81,7 @@
   histograms.ExpectUniqueSample(
       "Permissions.Prompt.Notifications.LocationBarLeftChipAutoBubble."
       "IgnoredReason",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::PermissionIgnoredReason::TAB_CLOSED),
       1);
 }
@@ -122,7 +122,7 @@
   histograms.ExpectUniqueSample(
       "Permissions.Prompt.Notifications.LocationBarLeftChipAutoBubble."
       "IgnoredReason",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::PermissionIgnoredReason::TAB_CLOSED),
       1);
 }
@@ -155,7 +155,7 @@
   histograms.ExpectUniqueSample(
       "Permissions.Prompt.Notifications.LocationBarLeftChipAutoBubble."
       "IgnoredReason",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::PermissionIgnoredReason::WINDOW_CLOSED),
       1);
 }
@@ -187,7 +187,7 @@
   histograms.ExpectUniqueSample(
       "Permissions.Prompt.Notifications.LocationBarLeftChipAutoBubble."
       "IgnoredReason",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           permissions::PermissionIgnoredReason::NAVIGATION),
       1);
 }
diff --git a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
index 59985bb..4fcf56f 100644
--- a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
+++ b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
@@ -123,7 +123,7 @@
 
   base::UmaHistogramEnumeration(
       base::StrCat({"Signin.SignInPromo.Dismissed", dismiss_action}),
-      access_point_, signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+      access_point_);
 }
 
 AutofillBubbleSignInPromoView::~AutofillBubbleSignInPromoView() = default;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
index 1cade64..7414003 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
@@ -49,7 +49,7 @@
                                          TabStrip* tab_strip) {
   Edge new_tab_button_flat_edge = Edge::kNone;
   if (features::HasTabstripComboButtonWithBackground()) {
-    new_tab_button_flat_edge = base::i18n::IsRTL() ? Edge::kRight : Edge::kLeft;
+    new_tab_button_flat_edge = base::i18n::IsRTL() ? Edge::kLeft : Edge::kRight;
   }
   std::unique_ptr<TabStripControlButton> new_tab_button =
       std::make_unique<TabStripControlButton>(
@@ -70,9 +70,9 @@
     new_tab_button->SetBackgroundFrameInactiveColorId(
         kColorNewTabButtonCRBackgroundFrameInactive);
   } else {
-    // Add a gap between the new tab button and tab search button.
+    // Add a gap between the new tab button and tab search container.
     new_tab_button->SetProperty(
-        views::kMarginsKey, gfx::Insets::TLBR(0, kButtonGapNoBackground, 0, 0));
+        views::kMarginsKey, gfx::Insets::TLBR(0, 0, 0, kButtonGapNoBackground));
   }
 
   new_tab_button->SetTooltipText(
@@ -106,7 +106,7 @@
   Edge tab_search_button_flat_edge = Edge::kNone;
   if (features::HasTabstripComboButtonWithBackground()) {
     tab_search_button_flat_edge =
-        base::i18n::IsRTL() ? Edge::kLeft : Edge::kRight;
+        base::i18n::IsRTL() ? Edge::kRight : Edge::kLeft;
   }
   std::unique_ptr<TabSearchButton> tab_search_button =
       std::make_unique<TabSearchButton>(tab_strip->controller(), browser,
@@ -128,9 +128,9 @@
       .SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
   separator_container->SetCanProcessEventsWithinSubtree(false);
 
+  new_tab_button_ = button_container->AddChildView(std::move(new_tab_button));
   tab_search_button_ =
       button_container->AddChildView(std::move(tab_search_button));
-  new_tab_button_ = button_container->AddChildView(std::move(new_tab_button));
   separator_ = separator_container->AddChildView(std::move(separator));
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_interactive_uitest.cc
index 4aaf411..eaa3072 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view_interactive_uitest.cc
@@ -151,7 +151,7 @@
 
   InteractiveTestApi::MultiStep WaitForBucket(
       const std::string& histogram_name,
-      base::HistogramBase::Sample sample) {
+      base::HistogramBase::Sample32 sample) {
     return InteractiveTestApi::Steps(InteractiveTestApi::Do(
         base::BindOnce(&TranslateBubbleViewUITest::WaitForBucketImpl,
                        base::Unretained(this), histogram_name, sample)));
@@ -220,7 +220,7 @@
   }
 
   void WaitForBucketImpl(const std::string& histogram_name,
-                         base::HistogramBase::Sample sample) {
+                         base::HistogramBase::Sample32 sample) {
     // Wait until the bucket is recorded.
     base::RunLoop run_loop;
     while (run_loop.running()) {
@@ -335,7 +335,7 @@
         WaitForLanguageSettingInNewTab(kTranslateSettingsElementId),
         // V2. Verify the histogram is recorded correctly.
         WaitForBucket(translate::kTranslateUiInteractionEvent,
-                      static_cast<base::HistogramBase::Sample>(
+                      static_cast<base::HistogramBase::Sample32>(
                           translate::UIInteraction::kOpenLanguageSettings)));
   }
 }
diff --git a/chrome/browser/ui/web_applications/web_app_engagement_browsertest.cc b/chrome/browser/ui/web_applications/web_app_engagement_browsertest.cc
index c9db52a..702ecc00 100644
--- a/chrome/browser/ui/web_applications/web_app_engagement_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_engagement_browsertest.cc
@@ -616,7 +616,7 @@
   {
     // From c/b/ui/startup/launch_mode_recorder.h:
     constexpr char kLaunchModesHistogram[] = "Launch.Mode2";
-    const base::HistogramBase::Sample kWebAppOther = 22;
+    const base::HistogramBase::Sample32 kWebAppOther = 22;
 
     tester.ExpectUniqueSample(kLaunchModesHistogram, kWebAppOther, 1);
   }
@@ -675,7 +675,7 @@
   {
     // From c/b/ui/startup/launch_mode_recorder.h:
     constexpr char kLaunchModesHistogram[] = "Launch.Mode2";
-    const base::HistogramBase::Sample kWebAppOther = 22;
+    const base::HistogramBase::Sample32 kWebAppOther = 22;
 
     tester.ExpectUniqueSample(kLaunchModesHistogram, kWebAppOther, 1);
   }
@@ -724,7 +724,7 @@
   {
     // From startup_browser_creator_impl.cc:
     constexpr char kLaunchModesHistogram[] = "Launch.Mode2";
-    const base::HistogramBase::Sample kWebAppOther = 22;
+    const base::HistogramBase::Sample32 kWebAppOther = 22;
 
     tester.ExpectUniqueSample(kLaunchModesHistogram, kWebAppOther, 1);
   }
diff --git a/chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog_browsertest.cc
index 47a34d3..f005169 100644
--- a/chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog_browsertest.cc
@@ -159,7 +159,7 @@
 
   histogram_tester.ExpectUniqueSample(
       "Crostini.UpgradeDialogEvent",
-      static_cast<base::HistogramBase::Sample>(
+      static_cast<base::HistogramBase::Sample32>(
           crostini::UpgradeDialogEvent::kDialogShown),
       1);
 }
diff --git a/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_lock_screen_authentication_browsertest.cc b/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_lock_screen_authentication_browsertest.cc
index 011c024..c52f7ac 100644
--- a/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_lock_screen_authentication_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_lock_screen_authentication_browsertest.cc
@@ -19,7 +19,7 @@
 // Name and value of the metric that records authentication on the lock screen
 // page.
 const char kPinUnlockUmaHistogramName[] = "Settings.PinUnlockSetup";
-const base::HistogramBase::Sample kEnterPasswordCorrectly = 1;
+const base::HistogramBase::Sample32 kEnterPasswordCorrectly = 1;
 
 }  // namespace
 
diff --git a/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_pin_setup_browsertest.cc b/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_pin_setup_browsertest.cc
index 438000e..430751e 100644
--- a/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_pin_setup_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/settings/integration_tests/os_settings_pin_setup_browsertest.cc
@@ -56,9 +56,9 @@
 // Name and value of the metric that records authentication on the lock screen
 // page.
 const char kPinUnlockUmaHistogramName[] = "Settings.PinUnlockSetup";
-const base::HistogramBase::Sample kChoosePinOrPassword = 2;
-const base::HistogramBase::Sample kEnterPin = 3;
-const base::HistogramBase::Sample kConfirmPin = 4;
+const base::HistogramBase::Sample32 kChoosePinOrPassword = 2;
+const base::HistogramBase::Sample32 kEnterPin = 3;
+const base::HistogramBase::Sample32 kConfirmPin = 4;
 
 }  // namespace
 
diff --git a/chrome/browser/ui/webui/log_web_ui_url.cc b/chrome/browser/ui/webui/log_web_ui_url.cc
index b42cad2..8e38aa8 100644
--- a/chrome/browser/ui/webui/log_web_ui_url.cc
+++ b/chrome/browser/ui/webui/log_web_ui_url.cc
@@ -50,7 +50,7 @@
 
   uint32_t hash = base::Hash(web_ui_url.DeprecatedGetOriginAsURL().spec());
   base::UmaHistogramSparse(kWebUICreatedForUrl,
-                           static_cast<base::HistogramBase::Sample>(hash));
+                           static_cast<base::HistogramBase::Sample32>(hash));
   return true;
 }
 
@@ -61,7 +61,7 @@
 
   uint32_t hash = base::Hash(web_ui_url.DeprecatedGetOriginAsURL().spec());
   base::UmaHistogramSparse(kWebUIShownUrl,
-                           static_cast<base::HistogramBase::Sample>(hash));
+                           static_cast<base::HistogramBase::Sample32>(hash));
   return true;
 }
 
diff --git a/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc b/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc
index 4fe1bb17..962ebc2b 100644
--- a/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc
+++ b/chrome/browser/ui/webui/webui_url_hashes_browsertest.cc
@@ -27,7 +27,7 @@
     std::string url = config_info.origin.Serialize() + "/";
     uint32_t hash = base::Hash(url);
     std::string hash_string =
-        base::NumberToString(static_cast<base::HistogramBase::Sample>(hash));
+        base::NumberToString(static_cast<base::HistogramBase::Sample32>(hash));
     if (!webui_metrics::IsValidWebUIUrlHashes(hash_string)) {
       missing_entries.push_back(base::StrCat(
           {"  <int value=\"", hash_string, "\" label=\"", url, "\"/>"}));
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
index 9c09df0..ff8abe8 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager_unittest.cc
@@ -777,8 +777,8 @@
   AssertAppInstalledAtVersion(GetIwa2WebBundleId(), base::Version("2.2.0"));
 }
 
-// TODO(crbug.com/389137516): Flaky on ChromeOS MSAN.
-#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
+// TODO(crbug.com/389137516): Flaky on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS)
 #define MAYBE_StopsNonStartedUpdateDiscoveryTasksIfIwaIsUninstalled \
   DISABLED_StopsNonStartedUpdateDiscoveryTasksIfIwaIsUninstalled
 #else
diff --git a/chrome/browser/webapps/installable/ml_promotion_browsertest.cc b/chrome/browser/webapps/installable/ml_promotion_browsertest.cc
index 1aee3ec..2f569b8 100644
--- a/chrome/browser/webapps/installable/ml_promotion_browsertest.cc
+++ b/chrome/browser/webapps/installable/ml_promotion_browsertest.cc
@@ -343,7 +343,7 @@
                     request,
                     HasTrainingLabel(
                         "WebApps.MlInstall.DialogResponse",
-                        static_cast<base::HistogramBase::Sample>(response)),
+                        static_cast<base::HistogramBase::Sample32>(response)),
                     _));
   }
 
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 5f4e7a78..bb7ddf9 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1736702273-0e5a2aca5d988173e4eb6a3248acba876e985a10-7d31c8bad7d5747f47e42012459477f505ca0f4d.profdata
+chrome-android32-main-1736746872-e514ef74f980c47ceafd86e04b79d504b072e86c-77a482e6d2f3b2d4f7dd93761999631398997b02.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 15aec07..92c6614 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1736705989-d6395bea2f1aa9b29311fe6eb035eebf66014be2-18258c1269dc14f2c83466911873abf8ced6cb51.profdata
+chrome-android64-main-1736760647-8c11d10505f11791ca11ed781955da7894fde6e5-9ec21920c1b4f409b3294ccc49ba9a22d0fbeebf.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 95d18dd..9ce2bd7 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1736702273-5eecf700a6bcd37c901c0396f8070592e46e57d4-7d31c8bad7d5747f47e42012459477f505ca0f4d.profdata
+chrome-linux-main-1736746872-6b2c5881f6a443ca6db3e5a04cc460d4deaa6b7f-77a482e6d2f3b2d4f7dd93761999631398997b02.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index aee80379..f8152eb4 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1736711783-ff2d936086386bc175ca60139172d6f436ee25a4-4cab454645be913ab8445295afea7dead4844c58.profdata
+chrome-mac-arm-main-1736762265-539d8d96c43d951aeccc4943701185de8303dc02-75e11df2e4f721a7c3bb369f938397df72c74a58.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index cb4fbae..2acec16 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1736702273-5e0faca16865f04b174965fd901a1f360a371b96-7d31c8bad7d5747f47e42012459477f505ca0f4d.profdata
+chrome-mac-main-1736746872-7795a7842de50f7cf78dfa930de27c5d37bb3c57-77a482e6d2f3b2d4f7dd93761999631398997b02.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 3a9e483..5a788dda 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1736702273-42e5f8e7c3b870dab62139f525bf2aa9f932c1be-7d31c8bad7d5747f47e42012459477f505ca0f4d.profdata
+chrome-win-arm64-main-1736746872-2a4b0a9334b30696377fe0a1e485f9aeacbd3c8e-77a482e6d2f3b2d4f7dd93761999631398997b02.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index ccdc8c3..a285d541 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1736693294-851ba4e2b7fd3aa00a84864cc906ee46a9e3a266-329ac413dbce89a9be8006c0af7eb42d0f4d832f.profdata
+chrome-win32-main-1736746872-ba2ccbbd25a0aac7fc62f6c257502ea01fa19e22-77a482e6d2f3b2d4f7dd93761999631398997b02.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 912a641b..2531e4d 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1736693294-bfbd2286fc71300f1e548e64752a1510dddf234b-329ac413dbce89a9be8006c0af7eb42d0f4d832f.profdata
+chrome-win64-main-1736734285-b06cf7ee7cb98c458c0b381ee885749e8076d6b7-a3bd701e5fae7c121fb08bf3d815d34d966e9034.profdata
diff --git a/chrome/release_scripts b/chrome/release_scripts
index 2d23cdc..b37cf13 160000
--- a/chrome/release_scripts
+++ b/chrome/release_scripts
@@ -1 +1 @@
-Subproject commit 2d23cdc03824f73a4fce61d34cbbe9828e56b962
+Subproject commit b37cf13dae4ea8bdbff22cee2b4820c94c83bab8
diff --git a/chrome/test/data/webui/settings/ai_history_search_subpage_test.ts b/chrome/test/data/webui/settings/ai_history_search_subpage_test.ts
index 432a1451..dec0e63 100644
--- a/chrome/test/data/webui/settings/ai_history_search_subpage_test.ts
+++ b/chrome/test/data/webui/settings/ai_history_search_subpage_test.ts
@@ -29,6 +29,13 @@
     return CrSettingsPrefs.initialized;
   });
 
+  teardown(function() {
+    // Reset pref policy to ALLOW.
+    settingsPrefs.set(
+        `prefs.${AiEnterpriseFeaturePrefName.HISTORY_SEARCH}.value`,
+        ModelExecutionEnterprisePolicyValue.ALLOW);
+  });
+
   function createPage() {
     metricsBrowserProxy = new TestMetricsBrowserProxy();
     MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy);
@@ -54,6 +61,10 @@
     const toggle = subpage.shadowRoot!.querySelector('settings-toggle-button');
     assertTrue(!!toggle);
 
+    const policyIndicator =
+        subpage.shadowRoot!.querySelector('cr-policy-pref-indicator');
+    assertFalse(!!policyIndicator);
+
     // Check NOT_INITIALIZED case.
     assertEquals(
         FeatureOptInState.NOT_INITIALIZED,
@@ -83,6 +94,25 @@
     assertFalse(toggle.checked);
   });
 
+  test('historySearchToggleDisabled', async () => {
+    settingsPrefs.set(
+        `prefs.${AiEnterpriseFeaturePrefName.HISTORY_SEARCH}.value`,
+        ModelExecutionEnterprisePolicyValue.DISABLE);
+    await createPage();
+
+    const indicator =
+        subpage.shadowRoot!.querySelector('cr-policy-pref-indicator');
+    assertTrue(!!indicator);
+
+    const toggle = subpage.shadowRoot!.querySelector('settings-toggle-button');
+    assertTrue(!!toggle);
+    assertTrue(toggle.disabled);
+    assertFalse(toggle.checked);
+
+    const linkout = subpage.shadowRoot!.querySelector('cr-link-row');
+    assertFalse(!!linkout);
+  });
+
   test('historySearchLinkout', async function() {
     await createPage();
 
@@ -133,8 +163,14 @@
     }
 
     await createPage();
-    assertTrue(checkVisibility('#linkoutText'));
-    assertFalse(checkVisibility('#linkoutTextWithAnswers'));
+    const linkout =
+        subpage.shadowRoot!.querySelector<HTMLElement>('#linkoutText');
+    assertTrue(!!linkout);
+    assertEquals(
+        loadTimeData.getString('historySearchSettingSublabelV2') +
+            loadTimeData.getString('sentenceEnd'),
+        linkout.innerText.trim());
+
     assertTrue(checkVisibility('#whenOnPageContentText'));
     assertFalse(checkVisibility('#whenOnPageContentTextWithAnswers'));
     assertFalse(checkVisibility('#whenOnRecallInfoWithAnswers'));
@@ -145,8 +181,14 @@
 
     loadTimeData.overrideValues({historyEmbeddingsAnswersFeatureEnabled: true});
     await createPage();
-    assertFalse(checkVisibility('#linkoutText'));
-    assertTrue(checkVisibility('#linkoutTextWithAnswers'));
+    const linkoutWithAnswers =
+        subpage.shadowRoot!.querySelector<HTMLElement>('#linkoutText');
+    assertTrue(!!linkoutWithAnswers);
+    assertEquals(
+        loadTimeData.getString('historySearchWithAnswersSettingSublabelV2') +
+            loadTimeData.getString('sentenceEnd'),
+        linkoutWithAnswers.innerText.trim());
+
     assertFalse(checkVisibility('#whenOnPageContentText'));
     assertTrue(checkVisibility('#whenOnPageContentTextWithAnswers'));
     assertTrue(checkVisibility('#whenOnRecallInfoWithAnswers'));
diff --git a/chromeos/ash/components/mantis/DEPS b/chromeos/ash/components/mantis/DEPS
index 861f66e..1d1bef2 100644
--- a/chromeos/ash/components/mantis/DEPS
+++ b/chromeos/ash/components/mantis/DEPS
@@ -3,4 +3,6 @@
   # Individual components must explicitly declare their dependencies
   # on other components.
   "+chromeos/ash/components/mojo_service_manager",
+  "+chromeos/ash/components/specialized_features",
+  "+components/signin/public/identity_manager",
 ]
diff --git a/chromeos/ash/components/mantis/media_app/BUILD.gn b/chromeos/ash/components/mantis/media_app/BUILD.gn
index 3e7bf30..e63fda0 100644
--- a/chromeos/ash/components/mantis/media_app/BUILD.gn
+++ b/chromeos/ash/components/mantis/media_app/BUILD.gn
@@ -20,7 +20,9 @@
     "//base",
     "//chromeos/ash/components/mantis/mojom",
     "//chromeos/ash/components/mojo_service_manager",
+    "//chromeos/ash/components/specialized_features",
     "//components/prefs",
+    "//components/signin/public/identity_manager",
     "//mojo/public/cpp/bindings",
   ]
 }
diff --git a/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.cc b/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.cc
index e3a2a3f1..be1a82c 100644
--- a/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.cc
+++ b/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.cc
@@ -16,6 +16,8 @@
 #include "chromeos/ash/components/mantis/mojom/mantis_service.mojom.h"
 #include "chromeos/ash/components/mojo_service_manager/connection.h"
 #include "chromeos/ash/components/mojo_service_manager/mojom/mojo_service_manager.mojom.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
+#include "components/signin/public/identity_manager/account_capabilities.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/cros_system_api/mojo/service_constants.h"
@@ -51,7 +53,9 @@
 
 }  // namespace
 
-MantisUntrustedServiceManager::MantisUntrustedServiceManager() {
+MantisUntrustedServiceManager::MantisUntrustedServiceManager(
+    std::unique_ptr<specialized_features::FeatureAccessChecker> access_checker)
+    : access_checker_(std::move(access_checker)) {
   ash::mojo_service_manager::GetServiceManagerProxy()->Request(
       chromeos::mojo_services::kCrosMantisService, std::nullopt,
       cros_service_.BindNewPipeAndPassReceiver().PassPipe());
@@ -60,6 +64,18 @@
 
 MantisUntrustedServiceManager::~MantisUntrustedServiceManager() = default;
 
+// static
+specialized_features::FeatureAccessConfig
+MantisUntrustedServiceManager::GetFeatureAccessConfig() {
+  specialized_features::FeatureAccessConfig access_config;
+  // TODO(crbug.com/362993438): Check region restriction.
+  access_config.capability_callback =
+      base::BindRepeating([](AccountCapabilities capabilities) {
+        return capabilities.can_use_generative_ai_photo_editing();
+      });
+  return access_config;
+}
+
 void MantisUntrustedServiceManager::OnQueryDone(
     base::OnceCallback<void(bool)> callback,
     chromeos::mojo_service_manager::mojom::ErrorOrServiceStatePtr result) {
@@ -84,7 +100,13 @@
     return;
   }
 
-  // TODO(crbug.com/362993438): Check age restriction and region restriction.
+  specialized_features::FeatureAccessFailureSet failure_set =
+      access_checker_->Check();
+  if (!failure_set.empty()) {
+    std::move(callback).Run(false);
+    return;
+  }
+
   if (pref_service->GetInteger(ash::prefs::kGenAIPhotoEditingSettings) ==
       static_cast<int>(GenAIPhotoEditingSettings::kDisabled)) {
     std::move(callback).Run(false);
diff --git a/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h b/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h
index 062c729..ec6947a 100644
--- a/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h
+++ b/chromeos/ash/components/mantis/media_app/mantis_untrusted_service_manager.h
@@ -13,6 +13,7 @@
 #include "chromeos/ash/components/mantis/media_app/mantis_untrusted_service.h"
 #include "chromeos/ash/components/mantis/mojom/mantis_service.mojom.h"
 #include "chromeos/ash/components/mojo_service_manager/mojom/mojo_service_manager.mojom.h"
+#include "chromeos/ash/components/specialized_features/feature_access_checker.h"
 #include "components/prefs/pref_service.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -29,12 +30,16 @@
   using CreateCallback =
       base::OnceCallback<void(mojo::StructPtr<CreateResult>)>;
 
-  MantisUntrustedServiceManager();
+  explicit MantisUntrustedServiceManager(
+      std::unique_ptr<specialized_features::FeatureAccessChecker>
+          access_checker);
   MantisUntrustedServiceManager(const MantisUntrustedServiceManager&) = delete;
   MantisUntrustedServiceManager& operator=(
       const MantisUntrustedServiceManager&) = delete;
   ~MantisUntrustedServiceManager();
 
+  static specialized_features::FeatureAccessConfig GetFeatureAccessConfig();
+
   void IsAvailable(PrefService* pref_service,
                    base::OnceCallback<void(bool)> callback);
   void Create(
@@ -57,6 +62,7 @@
   mojo::UniqueReceiverSet<mantis::mojom::PlatformModelProgressObserver>
       progress_observers_;
 
+  std::unique_ptr<specialized_features::FeatureAccessChecker> access_checker_;
   std::unique_ptr<MantisUntrustedService> mantis_untrusted_service_;
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<MantisUntrustedServiceManager> weak_ptr_factory_{this};
diff --git a/clank b/clank
index c6c9102..2a16411 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit c6c9102b9d6c333bc6d52b2fd31c27d92f06b088
+Subproject commit 2a16411ff60d055cb1def36b935da824fd6ce71a
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 426bf5a..54e572e6 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -65,7 +65,10 @@
          {ADDRESS_HOME_OVERFLOW, HtmlFieldType::kAddressLine2},
          {ADDRESS_HOME_OVERFLOW, HtmlFieldType::kAddressLine3},
          {ADDRESS_HOME_HOUSE_NUMBER, HtmlFieldType::kStreetAddress},
-         {ADDRESS_HOME_STREET_NAME, HtmlFieldType::kStreetAddress}});
+         {ADDRESS_HOME_STREET_NAME, HtmlFieldType::kStreetAddress},
+         {NAME_LAST_PREFIX, HtmlFieldType::kAdditionalName},
+         {NAME_LAST_PREFIX, HtmlFieldType::kAdditionalNameInitial},
+         {NAME_LAST_CORE, HtmlFieldType::kFamilyName}});
 
 // This list includes pairs (heuristic_type, server_type) that express which
 // heuristics predictions should be prioritized over server predictions. The
@@ -99,7 +102,9 @@
          {ALTERNATIVE_GIVEN_NAME, NAME_FIRST},
          {ALTERNATIVE_FAMILY_NAME, NAME_LAST},
          {ALTERNATIVE_FAMILY_NAME, NAME_LAST_SECOND},
-         {ALTERNATIVE_FAMILY_NAME, NAME_LAST_CORE}});
+         {ALTERNATIVE_FAMILY_NAME, NAME_LAST_CORE},
+         {NAME_LAST_PREFIX, NAME_MIDDLE},
+         {NAME_LAST_CORE, NAME_LAST}});
 
 // Returns true, if the prediction is non-experimental and should be used by
 // autofill or password manager.
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index 42fb703e..e8ba2e8d7 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -413,7 +413,32 @@
             .html_field_type = HtmlFieldType::kUnspecified,
             .server_type = NAME_LAST_CORE,
             .heuristic_type = ALTERNATIVE_FAMILY_NAME,
-            .expected_result = ALTERNATIVE_FAMILY_NAME}));
+            .expected_result = ALTERNATIVE_FAMILY_NAME},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kAdditionalName,
+            .server_type = NAME_LAST_PREFIX,
+            .heuristic_type = NAME_LAST_PREFIX,
+            .expected_result = NAME_LAST_PREFIX},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kAdditionalNameInitial,
+            .server_type = NAME_LAST_PREFIX,
+            .heuristic_type = NAME_LAST_PREFIX,
+            .expected_result = NAME_LAST_PREFIX},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kFamilyName,
+            .server_type = NAME_LAST_CORE,
+            .heuristic_type = NAME_LAST_CORE,
+            .expected_result = NAME_LAST_CORE},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnspecified,
+            .server_type = NAME_MIDDLE,
+            .heuristic_type = NAME_LAST_PREFIX,
+            .expected_result = NAME_LAST_PREFIX},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnspecified,
+            .server_type = NAME_LAST,
+            .heuristic_type = NAME_LAST_CORE,
+            .expected_result = NAME_LAST_CORE}));
 
 // Tests that consecutive identical events are not added twice to the event log.
 TEST(AutofillFieldLogEventTypeTest, AppendLogEventIfNotRepeated) {
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
index 59bb9769..e967427 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator.cc
@@ -75,7 +75,7 @@
 }
 
 // Iterator for a string that processes punctuation and white space according to
-// |collapse_skippable_|.
+// `collapse_skippable_`.
 class NormalizingIterator {
  public:
   NormalizingIterator(
@@ -85,7 +85,7 @@
 
   // Advances to the next non-skippable character in the string. Whether a
   // punctuation or white space character is skippable depends on
-  // |collapse_skippable_|. Returns false if the end of the string has been
+  // `collapse_skippable_`. Returns false if the end of the string has been
   // reached.
   void Advance();
 
@@ -102,10 +102,10 @@
   int32_t GetNextChar();
 
  private:
-  // When |collapse_skippable_| is false, this member is initialized to false
+  // When `collapse_skippable_` is false, this member is initialized to false
   // and is not updated.
   //
-  // When |collapse_skippable_| is true, this member indicates whether the
+  // When `collapse_skippable_` is true, this member indicates whether the
   // previous character was punctuation or white space so that one or more
   // consecutive embedded punctuation and white space characters can be
   // collapsed to a single white space.
@@ -292,7 +292,7 @@
   // needing domain-specific logic.
   //
   // 1. Convert punctuation to spaces and normalize all whitespace to spaces if
-  //    |whitespace_spec| is RETAIN_WHITESPACE.
+  //    `whitespace_spec` is RETAIN_WHITESPACE.
   //    This will convert "Mid-Island Plz." -> "Mid Island Plz " (the trailing
   //    space will be trimmed off outside of the end of the loop).
   //
@@ -367,21 +367,22 @@
   return true;
 }
 
-bool AutofillProfileComparator::MergeNames(const AutofillProfile& p1,
-                                           const AutofillProfile& p2,
+bool AutofillProfileComparator::MergeNames(const AutofillProfile& new_profile,
+                                           const AutofillProfile& old_profile,
                                            NameInfo& name_info) const {
-  DCHECK(HaveMergeableNames(p1, p2));
-  DCHECK(HaveMergeableAlternativeNames(p1, p2));
+  DCHECK(HaveMergeableNames(new_profile, old_profile));
+  DCHECK(HaveMergeableAlternativeNames(new_profile, old_profile));
 
   auto name_full = std::make_unique<NameFull>();
   auto alternative_full_name = std::make_unique<AlternativeFullName>();
 
   // TODO(crbug.com/375383124): Update `MergeNamesImpl` to provide meaningful
   // return values.
-  MergeNamesImpl(p1, p2, NAME_FULL, *name_full);
+  MergeNamesImpl(new_profile, old_profile, NAME_FULL, *name_full);
   if (base::FeatureList::IsEnabled(
           features::kAutofillSupportPhoneticNameForJP)) {
-    MergeNamesImpl(p1, p2, ALTERNATIVE_FULL_NAME, *alternative_full_name);
+    MergeNamesImpl(new_profile, old_profile, ALTERNATIVE_FULL_NAME,
+                   *alternative_full_name);
   }
   name_info = NameInfo(std::move(name_full), std::move(alternative_full_name));
   return true;
@@ -433,13 +434,13 @@
 }
 
 bool AutofillProfileComparator::MergeEmailAddresses(
-    const AutofillProfile& p1,
-    const AutofillProfile& p2,
+    const AutofillProfile& new_profile,
+    const AutofillProfile& old_profile,
     EmailInfo& email_info) const {
-  DCHECK(HaveMergeableEmailAddresses(p1, p2));
+  DCHECK(HaveMergeableEmailAddresses(new_profile, old_profile));
 
-  const std::u16string& e1 = p1.GetInfo(EMAIL_ADDRESS, app_locale_);
-  const std::u16string& e2 = p2.GetInfo(EMAIL_ADDRESS, app_locale_);
+  const std::u16string& e1 = new_profile.GetInfo(EMAIL_ADDRESS, app_locale_);
+  const std::u16string& e2 = old_profile.GetInfo(EMAIL_ADDRESS, app_locale_);
   const std::u16string* best = nullptr;
 
   if (e1.empty()) {
@@ -447,7 +448,7 @@
   } else if (e2.empty()) {
     best = &e1;
   } else {
-    best = p2.use_date() > p1.use_date() ? &e2 : &e1;
+    best = old_profile.use_date() > new_profile.use_date() ? &e2 : &e1;
   }
 
   email_info.SetInfo(EMAIL_ADDRESS, *best, app_locale_);
@@ -455,14 +456,14 @@
 }
 
 bool AutofillProfileComparator::MergeCompanyNames(
-    const AutofillProfile& p1,
-    const AutofillProfile& p2,
+    const AutofillProfile& new_profile,
+    const AutofillProfile& old_profile,
     CompanyInfo& company_info) const {
-  const std::u16string& c1 = p1.GetInfo(COMPANY_NAME, app_locale_);
-  const std::u16string& c2 = p2.GetInfo(COMPANY_NAME, app_locale_);
+  const std::u16string& c1 = new_profile.GetInfo(COMPANY_NAME, app_locale_);
+  const std::u16string& c2 = old_profile.GetInfo(COMPANY_NAME, app_locale_);
   const std::u16string* best = nullptr;
 
-  DCHECK(HaveMergeableCompanyNames(p1, p2))
+  DCHECK(HaveMergeableCompanyNames(new_profile, old_profile))
       << "Company names are not mergeable: '" << c1 << "' vs '" << c2 << "'";
 
   CompareTokensResult result =
@@ -478,7 +479,7 @@
       best = &c2;
       break;
     case SAME_TOKENS:
-      best = p2.use_date() > p1.use_date() ? &c2 : &c1;
+      best = old_profile.use_date() > new_profile.use_date() ? &c2 : &c1;
       break;
   }
   company_info.SetInfo(COMPANY_NAME, *best, app_locale_);
@@ -486,14 +487,14 @@
 }
 
 bool AutofillProfileComparator::MergePhoneNumbers(
-    const AutofillProfile& p1,
-    const AutofillProfile& p2,
+    const AutofillProfile& new_profile,
+    const AutofillProfile& old_profile,
     PhoneNumber& phone_number) const {
   const FieldType kWholePhoneNumber = PHONE_HOME_WHOLE_NUMBER;
-  const std::u16string& s1 = p1.GetRawInfo(kWholePhoneNumber);
-  const std::u16string& s2 = p2.GetRawInfo(kWholePhoneNumber);
+  const std::u16string& s1 = new_profile.GetRawInfo(kWholePhoneNumber);
+  const std::u16string& s2 = old_profile.GetRawInfo(kWholePhoneNumber);
 
-  DCHECK(HaveMergeablePhoneNumbers(p1, p2))
+  DCHECK(HaveMergeablePhoneNumbers(new_profile, old_profile))
       << "Phone numbers are not mergeable: '" << s1 << "' vs '" << s2 << "'";
 
   if (HasOnlySkippableCharacters(s1) && HasOnlySkippableCharacters(s2)) {
@@ -511,10 +512,10 @@
   }
 
   // Figure out a country code hint.
-  // TODO(crbug.com/40221178) |GetNonEmptyOf()| prefers |p1| in case both are
-  // non empty.
-  std::string region = base::UTF16ToUTF8(
-      GetNonEmptyOf(p1, p2, AutofillType(HtmlFieldType::kCountryCode)));
+  // TODO(crbug.com/40221178) `GetNonEmptyOf()` prefers `new_profile` in case
+  // both are non empty.
+  std::string region = base::UTF16ToUTF8(GetNonEmptyOf(
+      new_profile, old_profile, AutofillType(HtmlFieldType::kCountryCode)));
   if (region.empty()) {
     region = AutofillCountry::CountryCodeForLocale(app_locale_);
   }
@@ -600,15 +601,16 @@
   return true;
 }
 
-bool AutofillProfileComparator::MergeAddresses(const AutofillProfile& p1,
-                                               const AutofillProfile& p2,
-                                               Address& address) const {
-  DCHECK(HaveMergeableAddresses(p1, p2));
+bool AutofillProfileComparator::MergeAddresses(
+    const AutofillProfile& new_profile,
+    const AutofillProfile& old_profile,
+    Address& address) const {
+  DCHECK(HaveMergeableAddresses(new_profile, old_profile));
 
-  // Note that p1 is the newer address. Using p2 as the base.
-  address = p2.GetAddress();
-  return address.MergeStructuredAddress(p1.GetAddress(),
-                                        p2.use_date() < p1.use_date());
+  address = old_profile.GetAddress();
+  return address.MergeStructuredAddress(
+      new_profile.GetAddress(),
+      old_profile.use_date() < new_profile.use_date());
 }
 
 std::optional<FieldTypeSet>
@@ -712,13 +714,13 @@
   std::set<std::u16string_view> t1 = UniqueTokens(s1);
   std::set<std::u16string_view> t2 = UniqueTokens(s2);
 
-  // Does s1 contain all of the tokens in s2? As a special case, return 0 if the
-  // two sets are exactly the same.
+  // Does `s1` contain all of the tokens in `s2`? As a special case, return 0 if
+  // the two sets are exactly the same.
   if (std::includes(t1.begin(), t1.end(), t2.begin(), t2.end())) {
     return t1.size() == t2.size() ? SAME_TOKENS : S1_CONTAINS_S2;
   }
 
-  // Does s2 contain all of the tokens in s1?
+  // Does `s2` contain all of the tokens in `s1`?
   if (std::includes(t2.begin(), t2.end(), t1.begin(), t1.end())) {
     return S2_CONTAINS_S1;
   }
@@ -789,8 +791,8 @@
 bool AutofillProfileComparator::HaveMergeableNames(
     const AutofillProfile& p1,
     const AutofillProfile& p2) const {
-  // TODO(crbug.com/328968064): Use GetValueForComparison() instead of
-  // GetInfo().
+  // TODO(crbug.com/328968064): Use `GetValueForComparison()` instead of
+  // `GetInfo()`.
   return AreNamesMergeable(p1.GetInfo(NAME_FULL, app_locale_),
                            p2.GetInfo(NAME_FULL, app_locale_));
 }
@@ -875,7 +877,6 @@
 bool AutofillProfileComparator::HaveMergeableAddresses(
     const AutofillProfile& p1,
     const AutofillProfile& p2) const {
-  // Note that p1 is the newer address. Using p2 as the base.
   return p2.GetAddress().IsStructuredAddressMergeable(p1.GetAddress());
 }
 
@@ -897,15 +898,15 @@
   std::u16string canon_full_name_1 = NormalizeForComparison(full_name_1);
   std::u16string canon_full_name_2 = NormalizeForComparison(full_name_2);
 
-  // Is it reasonable to merge the names from p1 and p2.
+  // Is it reasonable to merge the names from `p1` and `p2`?
   bool result = IsNameVariantOf(canon_full_name_1, canon_full_name_2) ||
                 IsNameVariantOf(canon_full_name_2, canon_full_name_1);
   return result;
 }
 
 void AutofillProfileComparator::MergeNamesImpl(
-    const AutofillProfile& p1,
-    const AutofillProfile& p2,
+    const AutofillProfile& new_profile,
+    const AutofillProfile& old_profile,
     FieldType name_type,
     AddressComponent& name_component) const {
   DCHECK(name_type == NAME_FULL || name_type == ALTERNATIVE_FULL_NAME);
@@ -914,18 +915,20 @@
   // GetInfo() for NAME_FULL too.
   const std::u16string full_name_1 =
       name_type == ALTERNATIVE_FULL_NAME
-          ? p1.GetNameInfo()
+          ? new_profile.GetNameInfo()
                 .GetStructuredAlternativeName()
                 .GetValueForComparisonForType(
-                    name_type, p2.GetNameInfo().GetStructuredAlternativeName())
-          : p1.GetInfo(name_type, app_locale_);
+                    name_type,
+                    old_profile.GetNameInfo().GetStructuredAlternativeName())
+          : new_profile.GetInfo(name_type, app_locale_);
   const std::u16string full_name_2 =
       name_type == ALTERNATIVE_FULL_NAME
-          ? p2.GetNameInfo()
+          ? old_profile.GetNameInfo()
                 .GetStructuredAlternativeName()
                 .GetValueForComparisonForType(
-                    name_type, p1.GetNameInfo().GetStructuredAlternativeName())
-          : p2.GetInfo(name_type, app_locale_);
+                    name_type,
+                    new_profile.GetNameInfo().GetStructuredAlternativeName())
+          : old_profile.GetInfo(name_type, app_locale_);
 
   // At this state it is already determined that the two names are mergeable.
   // This can mean of of the following things:
@@ -933,30 +936,35 @@
   // * The names are token equivalent: In this scenario a merge of the tree
   // structure should be possible.
   // * One name is a variant of the other. In this scenario, use the non-variant
-  // name. Note, p1 is the newer profile.
+  // name.
   // First, set info to the original profile.
-  name_component.CopyFrom(*p2.GetNameInfo().GetNodeForType(name_type));
-  // If the name of the |p1| is empty, just keep the state of p2.
+  name_component.CopyFrom(*old_profile.GetNameInfo().GetNodeForType(name_type));
+  // If the name of the `new_profile` is empty, just keep the state of
+  // `old_profile`.
   if (HasOnlySkippableCharacters(full_name_1)) {
     return;
   }
-  // Vice versa set name to the one of |p1| if |p2| has an empty name
+  // Vice versa set name to the one of `new_profile` if `old_profile` has an
+  // empty name
   if (HasOnlySkippableCharacters(full_name_2)) {
-    name_component.CopyFrom(*p1.GetNameInfo().GetNodeForType(name_type));
+    name_component.CopyFrom(
+        *new_profile.GetNameInfo().GetNodeForType(name_type));
     return;
   }
   // Try to apply a direct merging.
   if (name_component.MergeWithComponent(
-          *p1.GetNameInfo().GetNodeForType(name_type))) {
+          *new_profile.GetNameInfo().GetNodeForType(name_type))) {
     return;
   }
-  // If the name in |p2| is a variant of |p1| use the one in |p1|.
+  // If the name in `old_profile` is a variant of `new_profile` use the one in
+  // `new_profile`.
   if (IsNameVariantOf(NormalizeForComparison(full_name_1),
                       NormalizeForComparison(full_name_2))) {
-    name_component.CopyFrom(*p1.GetNameInfo().GetNodeForType(name_type));
+    name_component.CopyFrom(
+        *new_profile.GetNameInfo().GetNodeForType(name_type));
     return;
   }
-  // The only left case is that |p1| is a variant of |p2|.
+  // The only left case is that `new_profile` is a variant of `old_profile`.
   DCHECK(IsNameVariantOf(NormalizeForComparison(full_name_2),
                          NormalizeForComparison(full_name_1)));
 }
diff --git a/components/autofill/core/browser/data_model/autofill_profile_comparator.h b/components/autofill/core/browser/data_model/autofill_profile_comparator.h
index e8f139a..2da6c93 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_comparator.h
+++ b/components/autofill/core/browser/data_model/autofill_profile_comparator.h
@@ -43,7 +43,7 @@
 
   enum WhitespaceSpec { RETAIN_WHITESPACE, DISCARD_WHITESPACE };
 
-  // Returns true if |text1| matches |text2|. The following normalization
+  // Returns true if `text1` matches `text2`. The following normalization
   // techniques are applied to the given texts before comparing.
   //
   // (1) Diacritics are removed, e.g. Ø­ÙŽ to Ø­, ビ to ヒ, and é to e;
@@ -51,11 +51,11 @@
   // (3) Characters are converted to lowercase;
   // (4) For alternative name types, katakana is converted to hiragana.
   //
-  // If |whitespace_spec| is DISCARD_WHITESPACE, then punctuation and whitespace
+  // If `whitespace_spec` is DISCARD_WHITESPACE, then punctuation and whitespace
   // are discarded. For example, the postal codes "B15 3TR" and "B153TR" and
   // street addresses "16 Bridge St."" and "16 Bridge St" are considered equal.
   //
-  // If |whitespace_spec| is RETAIN_WHITESPACE, then the postal codes "B15 3TR"
+  // If `whitespace_spec` is RETAIN_WHITESPACE, then the postal codes "B15 3TR"
   // and "B153TR" are not considered equal, but "16 Bridge St."" and "16 Bridge
   // St" are because trailing whitespace and punctuation are ignored.
   bool Compare(std::u16string_view text1,
@@ -63,14 +63,14 @@
                WhitespaceSpec whitespace_spec = DISCARD_WHITESPACE,
                std::optional<FieldType> type = std::nullopt) const;
 
-  // Returns true if two AutofillProfiles |p1| and |p2| have at least one
+  // Returns true if two AutofillProfiles `p1` and `p2` have at least one
   // settings-visible value that is different.
   static bool ProfilesHaveDifferentSettingsVisibleValues(
       const AutofillProfile& p1,
       const AutofillProfile& p2,
       const std::string& app_locale);
 
-  // Returns true if |text| is empty or contains only skippable characters. A
+  // Returns true if `text` is empty or contains only skippable characters. A
   // character is skippable if it is punctuation or white space.
   bool HasOnlySkippableCharacters(std::u16string_view text) const;
 
@@ -89,88 +89,87 @@
                                       const AutofillProfile& second_profile,
                                       const std::string& app_locale);
 
-  // Returns a copy of |text| with uppercase converted to lowercase and
+  // Returns a copy of `text` with uppercase converted to lowercase and
   // diacritics removed.
   //
-  // If |whitespace_spec| is RETAIN_WHITESPACE, punctuation is converted to
+  // If `whitespace_spec` is RETAIN_WHITESPACE, punctuation is converted to
   // spaces, and extraneous whitespace is trimmed and collapsed. For example,
   // "Jean- François" becomes "jean francois".
   //
-  // If |whitespace_spec| is DISCARD_WHITESPACE, punctuation and whitespace are
+  // If `whitespace_spec` is DISCARD_WHITESPACE, punctuation and whitespace are
   // discarded. For example, +1 (234) 567-8900 becomes 12345678900.
   static std::u16string NormalizeForComparison(
       std::u16string_view text,
       WhitespaceSpec whitespace_spec = RETAIN_WHITESPACE);
 
-  // Returns true if |p1| and |p2| are viable merge candidates. This means that
-  // their names, addresses, email addreses, company names, and phone numbers
+  // Returns true if `p1` and `p2` are viable merge candidates. This means that
+  // their names, addresses, email addresses, company names, and phone numbers
   // are all pairwise equivalent or mergeable.
   //
   // Note that mergeability is non-directional; merging two profiles will likely
   // incorporate data from both profiles.
   bool AreMergeable(const AutofillProfile& p1, const AutofillProfile& p2) const;
 
-  // Populates |name_info| with the result of merging the names in |p1| and
-  // |p2|. Returns true if successful. Expects that |p1| and |p2| have already
-  // been found to be mergeable.
-  // Regular names are merged first, after they are done, merging of alternative
-  // names starts.
-  bool MergeNames(const AutofillProfile& p1,
-                  const AutofillProfile& p2,
+  // Populates `name_info` with the result of merging the names in `new_profile`
+  // and `old_profile`. Returns true if successful. Expects that `new_profile`
+  // and `old_profile` have already been found to be mergeable. Regular names
+  // are merged first, after they are done, merging of alternative names starts.
+  bool MergeNames(const AutofillProfile& new_profile,
+                  const AutofillProfile& old_profile,
                   NameInfo& name_info) const;
 
-  // Returns true if |full_name_2| is a variant of |full_name_1|.
+  // Returns true if `full_name_2` is a variant of `full_name_1`.
   //
-  // This function generates all variations of |full_name_1| and returns true if
-  // one of these variants is equal to |full_name_2|. For example, this function
-  // will return true if |full_name_2| is "john q public" and |full_name_1| is
-  // "john quincy public" because |full_name_2| can be derived from
-  // |full_name_1| by using the middle initial. Note that the reverse is not
+  // This function generates all variations of `full_name_1` and returns true if
+  // one of these variants is equal to `full_name_2`. For example, this function
+  // will return true if `full_name_2` is "john q public" and `full_name_1` is
+  // "john quincy public" because `full_name_2` can be derived from
+  // `full_name_1` by using the middle initial. Note that the reverse is not
   // true, "john quincy public" is not a name variant of "john q public".
   //
-  // Note: Expects that |full_name| is already normalized for comparison.
+  // Note: Expects that `full_name` is already normalized for comparison.
   bool IsNameVariantOf(const std::u16string& full_name_1,
                        const std::u16string& full_name_2) const;
 
-  // Populates |email_info| with the result of merging the email addresses in
-  // |p1| and |p2|. Returns true if successful. Expects that |p1| and |p2| have
-  // already been found to be mergeable.
+  // Populates `email_info` with the result of merging the email addresses in
+  // `new_profile` and `old_profile`. Returns true if successful. Expects that
+  // `new_profile` and `old_profile` have already been found to be mergeable.
   //
   // Heuristic: If one email address is empty, use the other; otherwise, prefer
   // the most recently used version of the email address.
-  bool MergeEmailAddresses(const AutofillProfile& p1,
-                           const AutofillProfile& p2,
+  bool MergeEmailAddresses(const AutofillProfile& new_profile,
+                           const AutofillProfile& old_profile,
                            EmailInfo& email_info) const;
 
-  // Populates |company_info| with the result of merging the company names in
-  // |p1| and |p2|. Returns true if successful. Expects that |p1| and |p2| have
-  // already been found to be mergeable.
+  // Populates `company_info` with the result of merging the company names in
+  // `new_profile` and `old_profile`. Returns true if successful. Expects that
+  // `new_profile` and `old_profile` have already been found to be mergeable.
   //
   // Heuristic: If one is empty, use the other; otherwise, if the tokens in one
   // company name are a superset of those in the other, prefer the former; and,
   // as a tiebreaker, prefer the most recently used version of the company name.
-  bool MergeCompanyNames(const AutofillProfile& p1,
-                         const AutofillProfile& p2,
+  bool MergeCompanyNames(const AutofillProfile& new_profile,
+                         const AutofillProfile& old_profile,
                          CompanyInfo& company_info) const;
 
-  // Populates |phone_number| with the result of merging the phone numbers in
-  // |p1| and |p2|. Returns true if successful. Expects that |p1| and |p2| have
-  // already been found to be mergeable.
+  // Populates `phone_number` with the result of merging the phone numbers in
+  // `new_profile` and `old_profile`. Returns true if successful. Expects that
+  // `new_profile` and `old_profile` have already been found to be mergeable.
   //
   // Heuristic: Populate the missing parts of each number from the other.
-  bool MergePhoneNumbers(const AutofillProfile& p1,
-                         const AutofillProfile& p2,
+  bool MergePhoneNumbers(const AutofillProfile& new_profile,
+                         const AutofillProfile& old_profile,
                          PhoneNumber& phone_number) const;
 
-  // Populates |address| with the result of merging the addresses in |p1| and
-  // |p2|. Returns true if successful. Expects that |p1| and |p2| have already
-  // been found to be mergeable.
+  // Populates `address` with the result of merging the addresses in
+  // `new_profile` and `old_profile`. Returns true if successful. Expects that
+  // `new_profile` and `old_profile` have already been found to be mergeable.
   //
   // Heuristic: Populate the missing parts of each address from the other.
   // Prefer the abbreviated state, the shorter zip code and routing code, the
   // more verbost city, dependent locality, and address.
-  bool MergeAddresses(const AutofillProfile& p1,
-                      const AutofillProfile& p2,
+  bool MergeAddresses(const AutofillProfile& new_profile,
+                      const AutofillProfile& old_profile,
                       Address& address) const;
 
   // Returns the subset of setting-visible types whose values in `a` and `b` are
@@ -200,24 +199,24 @@
     S2_CONTAINS_S1,
   };
 
-  // Returns the set of unique tokens in |s|. Note that the string data backing
-  // |s| is expected to have a lifetime which exceeds the call to UniqueTokens.
+  // Returns the set of unique tokens in `s`. Note that the string data backing
+  // `s` is expected to have a lifetime which exceeds the call to UniqueTokens.
   static std::set<std::u16string_view> UniqueTokens(std::u16string_view s);
 
   // Compares the unique tokens in s1 and s2.
   static CompareTokensResult CompareTokens(std::u16string_view s1,
                                            std::u16string_view s2);
 
-  // Returns the value of |t| from |p1| or |p2| depending on which is non-empty.
-  // This method expects that the value is either the same in |p1| and |p2| or
+  // Returns the value of `t` from `p1` or `p2` depending on which is non-empty.
+  // This method expects that the value is either the same in `p1` and `p2` or
   // empty in one of them.
   // TODO(crbug.com/40264633): Pass a `FieldType` instead of `AutofillType`.
   std::u16string GetNonEmptyOf(const AutofillProfile& p1,
                                const AutofillProfile& p2,
                                AutofillType t) const;
 
-  // Generate the set of full/initial variants for |name_part|, where
-  // |name_part| is the user's first or middle name. For example, given "jean
+  // Generate the set of full/initial variants for `name_part`, where
+  // `name_part` is the user's first or middle name. For example, given "jean
   // francois" (the normalized for comparison form of "Jean-François") this
   // function returns the set:
   //
@@ -225,21 +224,21 @@
   //     "j", "j f", "j francois",
   //     "jean", "jean f", "jean francois", "jf" }
   //
-  // Note: Expects that |name| is already normalized for comparison.
+  // Note: Expects that `name` is already normalized for comparison.
   static std::set<std::u16string> GetNamePartVariants(
       const std::u16string& name_part);
 
-  // Returns true if |p1| and |p2| have names which are equivalent for the
-  // purposes of merging the two profiles. This means one of the names is
-  // empty, the names are the same, or one name is a variation of the other.
-  // The name comparison is insensitive to case, punctuation and diacritics.
+  // Returns true if `p1` and `p2` have names which are equivalent for the
+  // purposes of merging the two profiles. This means one of the names is empty,
+  // the names are the same, or one name is a variation of the other. The name
+  // comparison is insensitive to case, punctuation and diacritics.
   //
   // Note that this method does not provide any guidance on actually merging
   // the names.
   bool HaveMergeableNames(const AutofillProfile& p1,
                           const AutofillProfile& p2) const;
 
-  // Returns true if |p1| and |p2| have alternative names which are equivalent
+  // Returns true if `p1` and `p2` have alternative names which are equivalent
   // for the purposes of merging the two profiles. This means one of the
   // alternative names is empty, the names are the same, or one name is a
   // variation of the other. The alternative name comparison is insensitive to
@@ -250,8 +249,8 @@
   bool HaveMergeableAlternativeNames(const AutofillProfile& p1,
                                      const AutofillProfile& p2) const;
 
-  // Returns true if |p1| and |p2| have email addresses which are equivalent for
-  // the purposes of merging the two profiles. This means one of the email
+  // Returns true if `p1` and `p2` have email addresses which are equivalent
+  // for the purposes of merging the two profiles. This means one of the email
   // addresses is empty, or the email addresses are the same (modulo case).
   //
   // Note that this method does not provide any guidance on actually merging
@@ -259,7 +258,7 @@
   bool HaveMergeableEmailAddresses(const AutofillProfile& p1,
                                    const AutofillProfile& p2) const;
 
-  // Returns true if |p1| and |p2| have company names which are equivalent for
+  // Returns true if `p1` and `p2` have company names which are equivalent for
   // the purposes of merging the two profiles. This means one of the company
   // names is empty, or the normalized company names are the same (modulo case).
   //
@@ -268,19 +267,18 @@
   bool HaveMergeableCompanyNames(const AutofillProfile& p1,
                                  const AutofillProfile& p2) const;
 
-  // Returns true if |p1| and |p2| have phone numbers which are equivalent for
+  // Returns true if `p1` and `p2` have phone numbers which are equivalent for
   // the purposes of merging the two profiles. This means one of the phone
-  // numbers is empty, or the phone numbers match modulo formatting
-  // differences or missing information. For example, if the phone numbers are
-  // the same but one has an extension, country code, or area code and the other
-  // does not.
+  // numbers is empty, or the phone numbers match modulo formatting differences
+  // or missing information. For example, if the phone numbers are the same but
+  // one has an extension, country code, or area code and the other does not.
   //
   // Note that this method does not provide any guidance on actually merging
   // the phone numbers.
   bool HaveMergeablePhoneNumbers(const AutofillProfile& p1,
                                  const AutofillProfile& p2) const;
 
-  // Returns true if |p1| and |p2| have addresses which are equivalent for the
+  // Returns true if `p1` and `p2` have addresses which are equivalent for the
   // purposes of merging the two profiles. This means one of the addresses is
   // empty, or the addresses are a match. A number of normalization and
   // comparison heuristics are employed to determine if the addresses match.
@@ -304,16 +302,16 @@
   bool AreNamesMergeable(const std::u16string& full_name_1,
                          const std::u16string& full_name_2) const;
 
-  // Populates |name_info| with the result of merging the `name_type` names in
-  // |p1| and |p2|. Returns true if successful. Expects that |p1| and |p2| have
-  // already been found to be mergeable.
+  // Populates `name_info` with the result of merging the `name_type` names in
+  // `new_profile` and `old_profile`. Returns true if successful. Expects that
+  // `new_profile` and `old_profile` have already been found to be mergeable.
   //
   // Heuristic: If one regular name is empty, select the other; otherwise,
   // attempt to parse the names in each profile and determine if one
   // name can be derived from the other. For example, J Smith can be derived
   // from John Smith, so prefer the latter.
-  void MergeNamesImpl(const AutofillProfile& p1,
-                      const AutofillProfile& p2,
+  void MergeNamesImpl(const AutofillProfile& new_profile,
+                      const AutofillProfile& old_profile,
                       FieldType name_type,
                       AddressComponent& name_component) const;
 
diff --git a/components/autofill/core/browser/data_model/entity_instance.cc b/components/autofill/core/browser/data_model/entity_instance.cc
index ce454011..e166cec6 100644
--- a/components/autofill/core/browser/data_model/entity_instance.cc
+++ b/components/autofill/core/browser/data_model/entity_instance.cc
@@ -34,7 +34,7 @@
         attributes,
     base::Uuid guid,
     std::string nickname,
-    base::TimeTicks date_modified,
+    base::Time date_modified,
     bool synced)
     : type_(type),
       attributes_(std::move(attributes)),
diff --git a/components/autofill/core/browser/data_model/entity_instance.h b/components/autofill/core/browser/data_model/entity_instance.h
index a409e12..7ee15164 100644
--- a/components/autofill/core/browser/data_model/entity_instance.h
+++ b/components/autofill/core/browser/data_model/entity_instance.h
@@ -67,7 +67,7 @@
   AttributeInstance& operator=(AttributeInstance&&);
   ~AttributeInstance();
 
-  AttributeType type() const { return AttributeType(type_); }
+  const AttributeType& type() const { return type_; }
 
   // Typically a user-entered string, e.g., a date.
   const std::string& value() const { return value_; }
@@ -112,7 +112,7 @@
                                 AttributeInstance::CompareByType> attributes,
                  base::Uuid guid,
                  std::string nickname,
-                 base::TimeTicks date_modified,
+                 base::Time date_modified,
                  bool synced);
 
   EntityInstance(const EntityInstance&);
@@ -121,7 +121,7 @@
   EntityInstance& operator=(EntityInstance&&);
   ~EntityInstance();
 
-  EntityType type() const { return EntityType(type_); }
+  const EntityType& type() const { return type_; }
 
   // The attributes present in this instance.
   // This is a subset of the attributes supported by the entity type.
@@ -144,7 +144,7 @@
   const std::string& nickname() const LIFETIME_BOUND { return nickname_; }
 
   // The latest time the instance, including any of its attributes, was edited.
-  base::TimeTicks date_modified() const { return date_modified_; }
+  base::Time date_modified() const { return date_modified_; }
 
   // Indicates if the instance is synced.
   bool synced() const { return synced_; }
@@ -155,7 +155,7 @@
       attributes_;
   base::Uuid guid_;
   std::string nickname_;
-  base::TimeTicks date_modified_;
+  base::Time date_modified_;
   bool synced_ = false;
 };
 
diff --git a/components/autofill/core/browser/data_model/entity_instance_unittest.cc b/components/autofill/core/browser/data_model/entity_instance_unittest.cc
index d639327..b6a0d41 100644
--- a/components/autofill/core/browser/data_model/entity_instance_unittest.cc
+++ b/components/autofill/core/browser/data_model/entity_instance_unittest.cc
@@ -18,7 +18,7 @@
        AttributeInstance(AttributeType(kPassportCountry), "USA", {}),
        AttributeInstance(AttributeType(kPassportExpiryDate), "09/2098", {}),
        AttributeInstance(AttributeType(kPassportIssueDate), "10/1998", {})},
-      base::Uuid::GenerateRandomV4(), "Passie", base::TimeTicks::Now(),
+      base::Uuid::GenerateRandomV4(), "Passie", base::Time::Now(),
       /*synced=*/false);
   return kMyPassport;
 }
@@ -32,7 +32,7 @@
        AttributeInstance(AttributeType(kLoyaltyCardProvider), "Duck Airways",
                          {}),
        AttributeInstance(AttributeType(kLoyaltyCardMemberId), "1", {})},
-      base::Uuid::GenerateRandomV4(), "Duckie", base::TimeTicks::Now(),
+      base::Uuid::GenerateRandomV4(), "Duckie", base::Time::Now(),
       /*synced=*/true);
   return kMyLoyaltyCard;
 }
diff --git a/components/autofill/core/browser/form_parsing/internal_resources b/components/autofill/core/browser/form_parsing/internal_resources
index 6672b487..d74d93a 160000
--- a/components/autofill/core/browser/form_parsing/internal_resources
+++ b/components/autofill/core/browser/form_parsing/internal_resources
@@ -1 +1 @@
-Subproject commit 6672b4874e193fd6790f6c9ce6c78a1c2195208b
+Subproject commit d74d93ad9bc077c106419510e7aa08fa5d618cf1
diff --git a/components/autofill/core/browser/form_parsing/name_field_parser.cc b/components/autofill/core/browser/form_parsing/name_field_parser.cc
index 26bd3c3..7f7fd21a 100644
--- a/components/autofill/core/browser/form_parsing/name_field_parser.cc
+++ b/components/autofill/core/browser/form_parsing/name_field_parser.cc
@@ -66,6 +66,7 @@
   std::optional<FieldAndMatchInfo> honorific_prefix_;
   std::optional<FieldAndMatchInfo> first_name_;
   std::optional<FieldAndMatchInfo> middle_name_;
+  std::optional<FieldAndMatchInfo> last_name_prefix_;
   std::optional<FieldAndMatchInfo> first_last_name_;
   std::optional<FieldAndMatchInfo> second_last_name_;
   bool middle_initial_{false};  // True if middle_name_ is a middle initial.
@@ -112,6 +113,7 @@
   std::optional<FieldAndMatchInfo> honorific_prefix_;
   std::optional<FieldAndMatchInfo> first_name_;
   std::optional<FieldAndMatchInfo> middle_name_;
+  std::optional<FieldAndMatchInfo> last_name_prefix_;
   std::optional<FieldAndMatchInfo> last_name_;
   bool middle_initial_{false};  // True if middle_name_ is a middle initial.
 };
@@ -212,6 +214,8 @@
       GetMatchPatterns("FIRST_NAME", context);
   base::span<const MatchPatternRef> middle_name_patterns =
       GetMatchPatterns("MIDDLE_NAME", context);
+  base::span<const MatchPatternRef> last_name_prefix_patterns =
+      GetMatchPatterns("LAST_NAME_PREFIX", context);
   base::span<const MatchPatternRef> first_last_name_patterns =
       GetMatchPatterns("LAST_NAME_FIRST", context);
   base::span<const MatchPatternRef> second_last_name_patterns =
@@ -253,6 +257,16 @@
       continue;
     }
 
+    // TODO(crbug.com/386916943) Remove check once feature is launched or
+    // removed.
+    if (base::FeatureList::IsEnabled(
+            features::kAutofillSupportLastNamePrefix) &&
+        !v->last_name_prefix_ &&
+        ParseField(context, scanner, last_name_prefix_patterns,
+                   &v->last_name_prefix_, "LAST_NAME_PREFIX")) {
+      continue;
+    }
+
     if (!v->first_last_name_ &&
         ParseField(context, scanner, first_last_name_patterns,
                    &v->first_last_name_, "LAST_NAME_FIRST")) {
@@ -284,6 +298,8 @@
                     kBaseNameParserScore, field_candidates);
   AddClassification(first_name_, NAME_FIRST, kBaseNameParserScore,
                     field_candidates);
+  AddClassification(last_name_prefix_, NAME_LAST_PREFIX, kBaseNameParserScore,
+                    field_candidates);
   AddClassification(first_last_name_, NAME_LAST_FIRST, kBaseNameParserScore,
                     field_candidates);
   AddClassification(second_last_name_, NAME_LAST_SECOND, kBaseNameParserScore,
@@ -304,6 +320,8 @@
       GetMatchPatterns("NAME_GENERIC", context);
   base::span<const MatchPatternRef> middle_name_patterns =
       GetMatchPatterns("MIDDLE_NAME", context);
+  base::span<const MatchPatternRef> last_name_prefix_patterns =
+      GetMatchPatterns("LAST_NAME_PREFIX", context);
   base::span<const MatchPatternRef> last_name_patterns =
       GetMatchPatterns("LAST_NAME", context);
   base::span<const MatchPatternRef> name_ignored_patterns =
@@ -330,6 +348,13 @@
     // Check for an optional middle name field.
     ParseField(context, scanner, middle_name_patterns, &v->middle_name_,
                "MIDDLE_NAME");
+    // TODO(crbug.com/386916943) Remove check once feature is launched or
+    // removed.
+    if (base::FeatureList::IsEnabled(
+            features::kAutofillSupportLastNamePrefix)) {
+      ParseField(context, scanner, last_name_prefix_patterns,
+                 &v->last_name_prefix_, "LAST_NAME_PREFIX");
+    }
     if (ParseField(context, scanner, last_name_patterns, &v->last_name_,
                    "LAST_NAME")) {
       return v;
@@ -401,6 +426,8 @@
       GetMatchPatterns("MIDDLE_INITIAL", context);
   base::span<const MatchPatternRef> middle_name_patterns =
       GetMatchPatterns("MIDDLE_NAME", context);
+  base::span<const MatchPatternRef> last_name_prefix_patterns =
+      GetMatchPatterns("LAST_NAME_PREFIX", context);
   base::span<const MatchPatternRef> last_name_patterns =
       GetMatchPatterns("LAST_NAME", context);
 
@@ -449,6 +476,16 @@
       continue;
     }
 
+    // TODO(crbug.com/386916943) Remove check once feature is launched or
+    // removed.
+    if (base::FeatureList::IsEnabled(
+            features::kAutofillSupportLastNamePrefix) &&
+        !v->last_name_prefix_ &&
+        ParseField(context, scanner, last_name_prefix_patterns,
+                   &v->last_name_prefix_, "LAST_NAME_PREFIX")) {
+      continue;
+    }
+
     if (!v->last_name_ && ParseField(context, scanner, last_name_patterns,
                                      &v->last_name_, "LAST_NAME")) {
       continue;
@@ -491,8 +528,10 @@
                     kBaseNameParserScore, field_candidates);
   AddClassification(first_name_, NAME_FIRST, kBaseNameParserScore,
                     field_candidates);
-  AddClassification(last_name_, NAME_LAST, kBaseNameParserScore,
+  AddClassification(last_name_prefix_, NAME_LAST_PREFIX, kBaseNameParserScore,
                     field_candidates);
+  AddClassification(last_name_, last_name_prefix_ ? NAME_LAST_CORE : NAME_LAST,
+                    kBaseNameParserScore, field_candidates);
   const FieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE;
   AddClassification(middle_name_, type, kBaseNameParserScore, field_candidates);
 }
diff --git a/components/autofill/core/browser/form_parsing/name_field_parser_unittest.cc b/components/autofill/core/browser/form_parsing/name_field_parser_unittest.cc
index 04b0ea06..71d6228a 100644
--- a/components/autofill/core/browser/form_parsing/name_field_parser_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/name_field_parser_unittest.cc
@@ -31,7 +31,12 @@
 class NameFieldParserTest : public FormFieldParserTestBase,
                             public testing::Test {
  public:
-  NameFieldParserTest() = default;
+  NameFieldParserTest() {
+    scoped_feature_list_.InitWithFeatures(
+        {features::kAutofillUseNegativePatternForAllAttributes,
+         features::kAutofillSupportLastNamePrefix},
+        {});
+  }
   NameFieldParserTest(const NameFieldParserTest&) = delete;
   NameFieldParserTest& operator=(const NameFieldParserTest&) = delete;
 
@@ -42,8 +47,7 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_features{
-      features::kAutofillUseNegativePatternForAllAttributes};
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(NameFieldParserTest, FirstMiddleLast) {
@@ -240,6 +244,33 @@
   ClassifyAndVerify(ParseResult::kNotParsed);
 }
 
+TEST_F(NameFieldParserTest, LastNamePrefix) {
+  AddTextFormFieldData("first_name", "First Name", NAME_FIRST);
+  AddTextFormFieldData("tussenvoegsel", "tussenvoegsel", NAME_LAST_PREFIX);
+  AddTextFormFieldData("last_name", "Last Name", NAME_LAST_CORE);
+
+  ClassifyAndVerify(ParseResult::kParsed);
+}
+
+TEST_F(NameFieldParserTest, LastNamePrefixWithMiddleName) {
+  AddTextFormFieldData("first_name", "First Name", NAME_FIRST);
+  AddTextFormFieldData("middle_name", "Middle Name", NAME_MIDDLE);
+  AddTextFormFieldData("tussenvoegsel", "tussenvoegsel", NAME_LAST_PREFIX);
+  AddTextFormFieldData("last_name", "Last Name", NAME_LAST_CORE);
+
+  ClassifyAndVerify(ParseResult::kParsed);
+}
+
+TEST_F(NameFieldParserTest, LastNamePrefixWithTwoLastNames) {
+  AddTextFormFieldData("first_name", "First Name", NAME_FIRST);
+  AddTextFormFieldData("tussenvoegsel", "tussenvoegsel", NAME_LAST_PREFIX);
+  AddTextFormFieldData("apellido_paterno", "apellido paterno", NAME_LAST_FIRST);
+  AddTextFormFieldData("segunda_apellido", "segunda apellido",
+                       NAME_LAST_SECOND);
+
+  ClassifyAndVerify(ParseResult::kParsed);
+}
+
 }  // namespace
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/heuristic_classification_unittests.cc b/components/autofill/core/browser/heuristic_classification_unittests.cc
index 911f8257..6323053f 100644
--- a/components/autofill/core/browser/heuristic_classification_unittests.cc
+++ b/components/autofill/core/browser/heuristic_classification_unittests.cc
@@ -642,6 +642,7 @@
       features::kAutofillUsePLAddressModel,
       features::kAutofillSupportPhoneticNameForJP,
       features::kAutofillEnableExpirationDateImprovements,
+      features::kAutofillSupportLastNamePrefix,
       // Other improvements.
       features::kAutofillEnableCacheForRegexMatching,
       features::kAutofillEnableSupportForParsingWithSharedLabels,
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
index ea3e0e9..5f4e94d 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
@@ -213,8 +213,6 @@
 
     public static final String RESTORE_TABS_PROMO_USED = "restore_tabs_promo_used";
 
-    public static final String TAB_GROUP_SYNC_ON_STRIP_USED = "tab_group_sync_on_strip_used";
-
     /** Description text for tab group sync functionality in the tab group creation dialog. */
     public static final String TAB_GROUP_CREATION_DIALOG_SHOWN = "tab_group_creation_dialog_shown";
 
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
index b132f8c..17a14cfa 100644
--- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
+++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
@@ -111,6 +111,7 @@
     FeatureConstants.IPH_RTL_GESTURE_NAVIGATION,
     FeatureConstants.TAB_GROUP_CREATION_DIALOG_SYNC_TEXT_FEATURE,
     FeatureConstants.TAB_GROUP_SYNC_ON_STRIP_FEATURE,
+    FeatureConstants.TAB_GROUP_SHARE_NOTIFICATION_BUBBLE_ON_STRIP_FEATURE,
 })
 @Retention(RetentionPolicy.SOURCE)
 @NullMarked
@@ -222,6 +223,13 @@
      */
     String TAB_GROUP_CREATION_DIALOG_SYNC_TEXT_FEATURE = "IPH_TabGroupCreationDialogSyncText";
 
+    /**
+     * An IPH feature that shows a notification bubble for updated tab groups. The bubble appears on
+     * the group title when the group is collapsed and on updated tabs when the group is expanded.
+     */
+    String TAB_GROUP_SHARE_NOTIFICATION_BUBBLE_ON_STRIP_FEATURE =
+            "IPH_TabGroupSharedNotificationBubbleOnStrip";
+
     /** An IPH feature to show when tab group is synced across devices. */
     String TAB_GROUP_SYNC_ON_STRIP_FEATURE = "IPH_TabGroupSyncOnStrip";
 
diff --git a/components/feature_engagement/public/feature_configurations.cc b/components/feature_engagement/public/feature_configurations.cc
index b3e25dd..83fefbf 100644
--- a/components/feature_engagement/public/feature_configurations.cc
+++ b/components/feature_engagement/public/feature_configurations.cc
@@ -723,6 +723,23 @@
     return config;
   }
 
+  if (kIPHTabGroupShareNotificationBubbleOnStripFeature.name == feature->name) {
+    // A config to show IPH for TabGroupShare notification bubble when a shared
+    // group is updated by a group member. This will only be shown the first
+    // time the notification bubble is displayed.
+    std::optional<FeatureConfig> config = FeatureConfig();
+    config->valid = true;
+    config->availability = Comparator(ANY, 0);
+    config->session_rate = Comparator(LESS_THAN, 1);
+    config->trigger = EventConfig(
+        "tab_group_share_notification_bubble_on_strip_iph_triggered",
+        Comparator(LESS_THAN, 1), 360, 360);
+    config->used =
+        EventConfig("tab_group_share_notification_bubble_clicked",
+                    Comparator(EQUAL, 0), k10YearsInDays, k10YearsInDays);
+    return config;
+  }
+
   if (kIPHTabGroupCreationDialogSyncTextFeature.name == feature->name) {
     // A config that allows the sync text IPH on the TabGroupCreationDialog to
     // be shown up to 3 times total (10 year max in place of unlimited window).
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 984c44e..1e516b0 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -401,12 +401,12 @@
 BASE_FEATURE(kIPHTabGroupCreationDialogSyncTextFeature,
              "IPH_TabGroupCreationDialogSyncText",
              base::FEATURE_ENABLED_BY_DEFAULT);
-BASE_FEATURE(kIPHTabGroupSyncOnStripFeature,
-             "IPH_TabGroupSyncOnStrip",
-             base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHTabGroupsDragAndDropFeature,
              "IPH_TabGroupsDragAndDrop",
              base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kIPHTabGroupShareNotificationBubbleOnStripFeature,
+             "IPH_TabGroupSharedNotificationBubbleOnStrip",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHTabGroupsRemoteGroupFeature,
              "IPH_TabGroupsRemoteGroup",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -416,6 +416,9 @@
 BASE_FEATURE(kIPHTabGroupsSurfaceOnHideFeature,
              "IPH_TabGroupsSurfaceOnHide",
              base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kIPHTabGroupSyncOnStripFeature,
+             "IPH_TabGroupSyncOnStrip",
+             base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHTabSwitcherButtonFeature,
              "IPH_TabSwitcherButton",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index ba04a3fd..2ad4e9c 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -180,11 +180,13 @@
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHShoppingListMenuItemFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHShoppingListSaveFlowFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupCreationDialogSyncTextFeature);
-FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupSyncOnStripFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupsDragAndDropFeature);
+FEATURE_CONSTANTS_DECLARE_FEATURE(
+    kIPHTabGroupShareNotificationBubbleOnStripFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupsRemoteGroupFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupsSurfaceFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupsSurfaceOnHideFeature);
+FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabGroupSyncOnStripFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabSwitcherButtonFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTabSwitcherButtonSwitchIncognitoFeature);
 FEATURE_CONSTANTS_DECLARE_FEATURE(kIPHTranslateMenuButtonFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index a21f624..c30e0a0 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -82,11 +82,12 @@
     &kIPHShoppingListMenuItemFeature,
     &kIPHShoppingListSaveFlowFeature,
     &kIPHTabGroupCreationDialogSyncTextFeature,
-    &kIPHTabGroupSyncOnStripFeature,
     &kIPHTabGroupsDragAndDropFeature,
+    &kIPHTabGroupShareNotificationBubbleOnStripFeature,
     &kIPHTabGroupsRemoteGroupFeature,
     &kIPHTabGroupsSurfaceFeature,
     &kIPHTabGroupsSurfaceOnHideFeature,
+    &kIPHTabGroupSyncOnStripFeature,
     &kIPHTabSwitcherButtonFeature,
     &kIPHTabSwitcherButtonSwitchIncognitoFeature,
     &kIPHTranslateMenuButtonFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index b4bb8b1..ef03bced 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -152,15 +152,17 @@
                        "IPH_ShoppingListSaveFlow");
 DEFINE_VARIATION_PARAM(kIPHTabGroupCreationDialogSyncTextFeature,
                        "IPH_TabGroupCreationDialogSyncText");
-DEFINE_VARIATION_PARAM(kIPHTabGroupSyncOnStripFeature,
-                       "IPH_TabGroupSyncOnStrip");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsDragAndDropFeature,
                        "IPH_TabGroupsDragAndDrop");
+DEFINE_VARIATION_PARAM(kIPHTabGroupShareNotificationBubbleOnStripFeature,
+                       "IPH_TabGroupSharedNotificationBubbleOnStrip");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsRemoteGroupFeature,
                        "IPH_TabGroupsRemoteGroup");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsSurfaceFeature, "IPH_TabGroupsSurface");
 DEFINE_VARIATION_PARAM(kIPHTabGroupsSurfaceOnHideFeature,
                        "IPH_TabGroupsSurfaceOnHide");
+DEFINE_VARIATION_PARAM(kIPHTabGroupSyncOnStripFeature,
+                       "IPH_TabGroupSyncOnStrip");
 DEFINE_VARIATION_PARAM(kIPHTabSwitcherButtonFeature, "IPH_TabSwitcherButton");
 DEFINE_VARIATION_PARAM(kIPHTabSwitcherButtonSwitchIncognitoFeature,
                        "IPH_TabSwitcherButtonSwitchIncognito");
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index 288d09b..8b6ce99 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/check_is_test.h"
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/location.h"
@@ -248,6 +249,7 @@
 bool PdfOcrInRenderer() {
   return !base::FeatureList::IsEnabled(chrome_pdf::features::kPdfSearchify);
 }
+
 }  // namespace
 
 PdfAccessibilityTree::PdfAccessibilityTree(
@@ -470,6 +472,7 @@
 
   ClearAccessibilityNodes();
   page_count_ = doc_info.page_count;
+  is_tagged_ = doc_info.is_tagged;
 
   doc_node_ =
       CreateNode(ax::mojom::Role::kPdfRoot, ax::mojom::Restriction::kReadOnly,
@@ -674,9 +677,9 @@
   auto obj = GetPluginContainerAXObject();
   CHECK(obj);
   PdfAccessibilityTreeBuilder tree_builder(
-      GetWeakPtr(), text_runs, chars, page_objects, page_info, page_index,
-      doc_node_.get(), &(*obj), &nodes_, &node_id_to_page_char_index_,
-      &node_id_to_annotation_info_
+      /*mark_headings_using_heuristic=*/!is_tagged_, text_runs, chars,
+      page_objects, page_info, page_index, doc_node_.get(), &(*obj), &nodes_,
+      &node_id_to_page_char_index_, &node_id_to_annotation_info_
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
       ,
       ocr_helper_.get(), had_accessible_text_
diff --git a/components/pdf/renderer/pdf_accessibility_tree.h b/components/pdf/renderer/pdf_accessibility_tree.h
index dae40cb..849a195 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/components/pdf/renderer/pdf_accessibility_tree.h
@@ -271,6 +271,7 @@
   uint32_t selection_end_page_index_ = 0;
   uint32_t selection_end_char_index_ = 0;
   uint32_t page_count_ = 0;
+  bool is_tagged_ = false;
   std::unique_ptr<ui::AXNodeData> doc_node_;
   // The banner node will have an appropriate ARIA landmark for easy navigation
   // for screen reader users. It will contain the status node below.
diff --git a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 73dded0..f0fad40 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "components/pdf/renderer/pdf_accessibility_tree.h"
 
+#include <algorithm>
+#include <iterator>
 #include <map>
 #include <memory>
 
@@ -68,11 +70,11 @@
 namespace {
 
 const chrome_pdf::AccessibilityTextRunInfo kFirstTextRun = {
-    15, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    15, "P", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityTextRunInfo kSecondTextRun = {
-    15, gfx::RectF(28.0f, 117.0f, 152.0f, 19.0f),
+    15, "P", gfx::RectF(28.0f, 117.0f, 152.0f, 19.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityCharInfo kDummyCharsData[] = {
@@ -83,19 +85,19 @@
     {'w', 16}, {'o', 12}, {'r', 8},  {'l', 4},  {'d', 12}, {'!', 2},
 };
 const chrome_pdf::AccessibilityTextRunInfo kFirstRunMultiLine = {
-    7, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    7, "P", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityTextRunInfo kSecondRunMultiLine = {
-    8, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    8, "P", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityTextRunInfo kThirdRunMultiLine = {
-    9, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    9, "P", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityTextRunInfo kFourthRunMultiLine = {
-    6, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    6, "P", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 
@@ -362,6 +364,7 @@
     viewport_info_.selection_start_char_index = 0u;
     viewport_info_.selection_end_page_index = 0u;
     viewport_info_.selection_end_char_index = 0u;
+    doc_info_.is_tagged = false;
     doc_info_.text_accessible = true;
     doc_info_.text_copyable = true;
     doc_info_.page_count = 1u;
@@ -602,6 +605,108 @@
             image_node->GetStringAttribute(ax::mojom::StringAttribute::kName));
 }
 
+TEST_F(PdfAccessibilityTreeTest, HeadingsDetectedByHeuristic) {
+  base::test::ScopedFeatureList pdf_tags;
+  pdf_tags.InitAndDisableFeature(chrome_pdf::features::kPdfTags);
+
+  CreatePdfAccessibilityTree();
+  text_runs_ = {kFirstTextRun, kSecondTextRun, kFirstTextRun, kSecondTextRun};
+  text_runs_[0].style.font_size = 16.0f;
+  text_runs_[1].style.font_size = 8.0f;
+  text_runs_[2].style.font_size = 8.0f;
+  text_runs_[3].style.font_size = 8.0f;
+
+  chars_ = {std::begin(kDummyCharsData), std::end(kDummyCharsData)};
+  std::copy(std::begin(kDummyCharsData), std::end(kDummyCharsData),
+            std::back_inserter(chars_));
+
+  page_info_.text_run_count = text_runs_.size();
+  page_info_.char_count = chars_.size();
+  pdf_accessibility_tree_->SetAccessibilityDocInfo(doc_info_);
+  pdf_accessibility_tree_->SetAccessibilityViewportInfo(viewport_info_);
+
+  pdf_accessibility_tree_->SetAccessibilityPageInfo(page_info_, text_runs_,
+                                                    chars_, page_objects_);
+  WaitForThreadTasks();
+  // Wait for `PdfAccessibilityTree::UnserializeNodes()`, a delayed task.
+  WaitForThreadDelayedTasks();
+
+  const ui::AXNode* pdf_root = pdf_accessibility_tree_->GetRoot();
+  CheckRootAndStatusNodes(pdf_root, doc_info_.page_count,
+                          /*is_pdf_ocr_test=*/false, /*is_ocr_completed=*/false,
+                          /*create_empty_ocr_results=*/false);
+
+  ASSERT_GT(pdf_root->GetChildCount(), 1u);
+  const ui::AXNode* page = pdf_root->GetChildAtIndex(1u);
+  ASSERT_NE(nullptr, page);
+  ASSERT_EQ(4u, page->GetChildCount());
+
+  const ui::AXNode* heuristic_heading = page->GetChildAtIndex(0u);
+  ASSERT_NE(nullptr, heuristic_heading);
+  EXPECT_EQ(ax::mojom::Role::kHeading, heuristic_heading->GetRole());
+  EXPECT_EQ(2, heuristic_heading->GetIntAttribute(
+                   ax::mojom::IntAttribute::kHierarchicalLevel));
+  EXPECT_EQ("h2", heuristic_heading->GetStringAttribute(
+                      ax::mojom::StringAttribute::kHtmlTag));
+
+  const ui::AXNode* paragraph1 = page->GetChildAtIndex(1u);
+  ASSERT_NE(nullptr, paragraph1);
+  EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph1->GetRole());
+
+  const ui::AXNode* paragraph2 = page->GetChildAtIndex(2u);
+  ASSERT_NE(nullptr, paragraph2);
+  EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph2->GetRole());
+
+  const ui::AXNode* paragraph3 = page->GetChildAtIndex(3u);
+  ASSERT_NE(nullptr, paragraph3);
+  EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph3->GetRole());
+}
+
+TEST_F(PdfAccessibilityTreeTest, HeadingsDetectedFromTags) {
+  base::test::ScopedFeatureList pdf_tags;
+  pdf_tags.InitAndEnableFeature(chrome_pdf::features::kPdfTags);
+  doc_info_.is_tagged = true;
+
+  CreatePdfAccessibilityTree();
+  text_runs_ = {kFirstTextRun, kSecondTextRun};
+  text_runs_[0].tag_type = "H1";
+  text_runs_[1].tag_type = "H2";
+
+  chars_ = {std::begin(kDummyCharsData), std::end(kDummyCharsData)};
+  page_info_.text_run_count = text_runs_.size();
+  page_info_.char_count = chars_.size();
+  pdf_accessibility_tree_->SetAccessibilityDocInfo(doc_info_);
+  pdf_accessibility_tree_->SetAccessibilityViewportInfo(viewport_info_);
+
+  pdf_accessibility_tree_->SetAccessibilityPageInfo(page_info_, text_runs_,
+                                                    chars_, page_objects_);
+  WaitForThreadTasks();
+  // Wait for `PdfAccessibilityTree::UnserializeNodes()`, a delayed task.
+  WaitForThreadDelayedTasks();
+
+  const ui::AXNode* pdf_root = pdf_accessibility_tree_->GetRoot();
+  CheckRootAndStatusNodes(pdf_root, doc_info_.page_count,
+                          /*is_pdf_ocr_test=*/false, /*is_ocr_completed=*/false,
+                          /*create_empty_ocr_results=*/false);
+
+  ASSERT_GT(pdf_root->GetChildCount(), 1u);
+  const ui::AXNode* page = pdf_root->GetChildAtIndex(1u);
+  ASSERT_NE(nullptr, page);
+  ASSERT_EQ(2u, page->GetChildCount());
+
+  const ui::AXNode* heading1 = page->GetChildAtIndex(0u);
+  ASSERT_NE(nullptr, heading1);
+  EXPECT_EQ(ax::mojom::Role::kHeading, heading1->GetRole());
+  EXPECT_EQ(1, heading1->GetIntAttribute(
+                   ax::mojom::IntAttribute::kHierarchicalLevel));
+
+  const ui::AXNode* heading2 = page->GetChildAtIndex(1u);
+  ASSERT_NE(nullptr, heading2);
+  EXPECT_EQ(ax::mojom::Role::kHeading, heading2->GetRole());
+  EXPECT_EQ(2, heading2->GetIntAttribute(
+                   ax::mojom::IntAttribute::kHierarchicalLevel));
+}
+
 TEST_F(PdfAccessibilityTreeTest, TestOverlappingAnnots) {
   text_runs_.emplace_back(kFirstRunMultiLine);
   text_runs_.emplace_back(kSecondRunMultiLine);
diff --git a/components/pdf/renderer/pdf_accessibility_tree_builder.cc b/components/pdf/renderer/pdf_accessibility_tree_builder.cc
index ccc7803..5f2406f 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_builder.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_builder.cc
@@ -4,9 +4,11 @@
 
 #include "components/pdf/renderer/pdf_accessibility_tree_builder.h"
 
+#include <optional>
 #include <queue>
 #include <string>
 
+#include "base/containers/fixed_flat_map.h"
 #include "base/i18n/break_iterator.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "components/pdf/renderer/pdf_ocr_helper.h"
@@ -15,6 +17,8 @@
 #include "pdf/pdf_features.h"
 #include "services/strings/grit/services_strings.h"
 #include "third_party/blink/public/web/web_ax_object.h"
+#include "ui/accessibility/accessibility_features.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -297,12 +301,84 @@
       current_text_run_index ? current_text_run_index - 1 : 0);
 }
 
+// Please keep the below map as close as possible to the list defined in the PDF
+// Specification, ISO 32000-1:2008, table 333.
+ax::mojom::Role StructureElementTypeToAccessibilityRole(
+    const std::string& element_type) {
+  static constexpr auto kStructureElementTypeToAccessibilityRoleMap =
+      base::MakeFixedFlatMap<std::string_view, ax::mojom::Role>(
+          {{"Document", ax::mojom::Role::kDocument},
+           {"Part", ax::mojom::Role::kDocPart},
+           {"Art", ax::mojom::Role::kArticle},
+           {"Sect", ax::mojom::Role::kSection},
+           {"Div", ax::mojom::Role::kGenericContainer},
+           {"BlockQuote", ax::mojom::Role::kBlockquote},
+           {"Caption", ax::mojom::Role::kCaption},
+           {"TOC", ax::mojom::Role::kDocToc},
+           {"TOCI", ax::mojom::Role::kListItem},
+           {"Index", ax::mojom::Role::kDocIndex},
+           {"P", ax::mojom::Role::kParagraph},
+           {"H", ax::mojom::Role::kHeading},
+           {"H1", ax::mojom::Role::kHeading},
+           {"H2", ax::mojom::Role::kHeading},
+           {"H3", ax::mojom::Role::kHeading},
+           {"H4", ax::mojom::Role::kHeading},
+           {"H5", ax::mojom::Role::kHeading},
+           {"H6", ax::mojom::Role::kHeading},
+           {"L", ax::mojom::Role::kList},
+           {"LI", ax::mojom::Role::kListItem},
+           {"Lbl", ax::mojom::Role::kListMarker},
+           {"LBody", ax::mojom::Role::kNone},  // Presentational.
+           {"Table", ax::mojom::Role::kTable},
+           {"TR", ax::mojom::Role::kRow},
+           {"TH", ax::mojom::Role::kRowHeader},
+           {"THead", ax::mojom::Role::kRowGroup},
+           {"TBody", ax::mojom::Role::kRowGroup},
+           {"TFoot", ax::mojom::Role::kRowGroup},
+           {"TD", ax::mojom::Role::kCell},
+           {"Span", ax::mojom::Role::kStaticText},
+           {"Link", ax::mojom::Role::kLink},
+           {"Figure", ax::mojom::Role::kFigure},
+           {"Formula", ax::mojom::Role::kMath},
+           {"Form", ax::mojom::Role::kForm}});
+
+  if (auto iter =
+          kStructureElementTypeToAccessibilityRoleMap.find(element_type);
+      iter != kStructureElementTypeToAccessibilityRoleMap.end()) {
+    return iter->second;
+  }
+  // Return something that could at least make some sense, other than
+  // `kUnknown`.
+  return ax::mojom::Role::kParagraph;
+}
+
+std::optional<uint32_t> StructureElementTypeToHeadingLevel(
+    const std::string& element_type) {
+  if (StructureElementTypeToAccessibilityRole(element_type) ==
+      ax::mojom::Role::kHeading) {
+    if (element_type == "H" || element_type == "H1") {
+      return 1;
+    } else if (element_type == "H2") {
+      return 2;
+    } else if (element_type == "H3") {
+      return 3;
+    } else if (element_type == "H4") {
+      return 4;
+    } else if (element_type == "H5") {
+      return 5;
+    } else if (element_type == "H6") {
+      return 6;
+    }
+  }
+  return std::nullopt;
+}
+
 }  // namespace
 
 namespace pdf {
 
 PdfAccessibilityTreeBuilder::PdfAccessibilityTreeBuilder(
-    base::WeakPtr<PdfAccessibilityTree> pdf_accessibility_tree,
+    bool mark_headings_using_heuristic,
     const std::vector<chrome_pdf::AccessibilityTextRunInfo>& text_runs,
     const std::vector<chrome_pdf::AccessibilityCharInfo>& chars,
     const chrome_pdf::AccessibilityPageObjects& page_objects,
@@ -321,7 +397,7 @@
     bool has_accessible_text
 #endif  // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
     )
-    : pdf_accessibility_tree_(std::move(pdf_accessibility_tree)),
+    : mark_headings_using_heuristic_(mark_headings_using_heuristic),
       text_runs_(text_runs),
       chars_(chars),
       links_(page_objects.links),
@@ -370,7 +446,7 @@
                                        &heading_font_size_threshold_,
                                        &paragraph_spacing_threshold_);
 
-  ui::AXNodeData* para_node = nullptr;
+  ui::AXNodeData* block_node = nullptr;
   ui::AXNodeData* static_text_node = nullptr;
   ui::AXNodeData* previous_on_line_node = nullptr;
   std::string static_text;
@@ -389,16 +465,16 @@
     bool ocr_block_start = text_run.is_searchified && !ocr_block;
     bool ocr_block_end = !text_run.is_searchified && ocr_block;
     if (ocr_block_start || ocr_block_end) {
-      // If already inside a paragraph, end it.
+      // If already inside a block, end it.
       // The searchifier adds the text at the exact position that it is seen in
       // the image and does not deal with paragraphs or other structures.
       // The function that creates the text runs only considers text positions
       // and separates the blocks based on that. Therefore there can be cases
-      // that OCR text will be added in the middle of a paragraph.
+      // that OCR text will be added in the middle of a block.
       // TODO(crbug.com/360803943): Add browser tests to verify.
-      if (para_node) {
+      if (block_node) {
         BuildStaticNode(&static_text_node, &static_text);
-        para_node = nullptr;
+        block_node = nullptr;
       }
       CHECK(ocr_block_start || text_run_index);
       gfx::PointF position =
@@ -411,21 +487,21 @@
       has_ocr_text = true;
     }
 
-    // If we don't have a paragraph, create one.
-    if (!para_node) {
-      para_node =
-          CreateParagraphNode((*text_runs_)[text_run_index].style.font_size);
-      page_node_->child_ids.push_back(para_node->id);
+    // If we don't have a block level node, create one.
+    if (!block_node) {
+      block_node =
+          CreateBlockLevelNode(text_run.tag_type, text_run.style.font_size);
+      page_node_->child_ids.push_back(block_node->id);
     }
 
     // If the `text_run_index` is less than or equal to the link's
-    // `text_run_index`, then push the link node in the paragraph.
+    // `text_run_index`, then push the link node in the block.
     if (IsObjectWithRangeInTextRun(*links_, current_link_index_,
                                    text_run_index)) {
       BuildStaticNode(&static_text_node, &static_text);
       const chrome_pdf::AccessibilityLinkInfo& link =
           (*links_)[current_link_index_++];
-      AddLinkToParaNode(link, para_node, &previous_on_line_node,
+      AddLinkToParaNode(link, block_node, &previous_on_line_node,
                         &text_run_index);
 
       if (link.text_range.count == 0) {
@@ -435,27 +511,27 @@
     } else if (IsObjectInTextRun(*images_, current_image_index_,
                                  text_run_index)) {
       BuildStaticNode(&static_text_node, &static_text);
-      AddImageToParaNode((*images_)[current_image_index_++], para_node,
+      AddImageToParaNode((*images_)[current_image_index_++], block_node,
                          &text_run_index);
       continue;
     } else if (IsObjectWithRangeInTextRun(
                    *highlights_, current_highlight_index_, text_run_index)) {
       BuildStaticNode(&static_text_node, &static_text);
       AddHighlightToParaNode((*highlights_)[current_highlight_index_++],
-                             para_node, &previous_on_line_node,
+                             block_node, &previous_on_line_node,
                              &text_run_index);
     } else if (IsObjectInTextRun(*text_fields_, current_text_field_index_,
                                  text_run_index) &&
                pdf_forms_enabled) {
       BuildStaticNode(&static_text_node, &static_text);
       AddTextFieldToParaNode((*text_fields_)[current_text_field_index_++],
-                             para_node, &text_run_index);
+                             block_node, &text_run_index);
       continue;
     } else if (IsObjectInTextRun(*buttons_, current_button_index_,
                                  text_run_index) &&
                pdf_forms_enabled) {
       BuildStaticNode(&static_text_node, &static_text);
-      AddButtonToParaNode((*buttons_)[current_button_index_++], para_node,
+      AddButtonToParaNode((*buttons_)[current_button_index_++], block_node,
                           &text_run_index);
       continue;
     } else if (IsObjectInTextRun(*choice_fields_, current_choice_field_index_,
@@ -463,17 +539,17 @@
                pdf_forms_enabled) {
       BuildStaticNode(&static_text_node, &static_text);
       AddChoiceFieldToParaNode((*choice_fields_)[current_choice_field_index_++],
-                               para_node, &text_run_index);
+                               block_node, &text_run_index);
       continue;
     } else {
       chrome_pdf::PageCharacterIndex page_char_index = {
           page_index_, text_run_start_indices_[text_run_index]};
 
-      // This node is for the text inside the paragraph, it includes
-      // the text of all of the text runs.
+      // This node is for the text inside the block, it includes the text of all
+      // of the text runs.
       if (!static_text_node) {
         static_text_node = CreateStaticTextNode(page_char_index);
-        para_node->child_ids.push_back(static_text_node->id);
+        block_node->child_ids.push_back(static_text_node->id);
       }
 
       // Add this text run to the current static text node.
@@ -484,7 +560,7 @@
       static_text += inline_text_box_node->GetStringAttribute(
           ax::mojom::StringAttribute::kName);
 
-      para_node->relative_bounds.bounds.Union(
+      block_node->relative_bounds.bounds.Union(
           inline_text_box_node->relative_bounds.bounds);
       static_text_node->relative_bounds.bounds.Union(
           inline_text_box_node->relative_bounds.bounds);
@@ -517,7 +593,7 @@
       if (BreakParagraph(*text_runs_, text_run_index,
                          paragraph_spacing_threshold_)) {
         BuildStaticNode(&static_text_node, &static_text);
-        para_node = nullptr;
+        block_node = nullptr;
       }
     }
   }
@@ -530,7 +606,7 @@
             ->id);
   }
 
-  AddRemainingAnnotations(para_node, has_ocr_text);
+  AddRemainingAnnotations(block_node, has_ocr_text);
 }
 
 void PdfAccessibilityTreeBuilder::AddWordStartsAndEnds(
@@ -575,23 +651,31 @@
   return node_ptr;
 }
 
-ui::AXNodeData* PdfAccessibilityTreeBuilder::CreateParagraphNode(
+ui::AXNodeData* PdfAccessibilityTreeBuilder::CreateBlockLevelNode(
+    const std::string& text_run_type,
     float font_size) {
-  ui::AXNodeData* para_node = CreateAndAppendNode(
-      ax::mojom::Role::kParagraph, ax::mojom::Restriction::kReadOnly);
-  para_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
-                              true);
-
-  // If font size exceeds the `heading_font_size_threshold_`, then classify
-  // it as a Heading.
-  if (heading_font_size_threshold_ > 0 &&
-      font_size > heading_font_size_threshold_) {
-    para_node->role = ax::mojom::Role::kHeading;
-    para_node->AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 2);
-    para_node->AddStringAttribute(ax::mojom::StringAttribute::kHtmlTag, "h2");
+  ui::AXNodeData* block_node = CreateAndAppendNode(
+      StructureElementTypeToAccessibilityRole(text_run_type),
+      ax::mojom::Restriction::kReadOnly);
+  block_node->AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
+                               true);
+  if (std::optional<uint32_t> level =
+          StructureElementTypeToHeadingLevel(text_run_type);
+      level) {
+    block_node->AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel,
+                                *level);
+    // TODO(crbug.com/40707542): Set the HTML tag to "h*" by creating a helper
+    // in `AXEnumUtils`.
   }
 
-  return para_node;
+  if (mark_headings_using_heuristic_ && heading_font_size_threshold_ > 0 &&
+      font_size > heading_font_size_threshold_) {
+    block_node->role = ax::mojom::Role::kHeading;
+    block_node->AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 2);
+    block_node->AddStringAttribute(ax::mojom::StringAttribute::kHtmlTag, "h2");
+  }
+
+  return block_node;
 }
 
 ui::AXNodeData* PdfAccessibilityTreeBuilder::CreateStaticTextNode() {
diff --git a/components/pdf/renderer/pdf_accessibility_tree_builder.h b/components/pdf/renderer/pdf_accessibility_tree_builder.h
index d55c4ce..bde5931 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_builder.h
+++ b/components/pdf/renderer/pdf_accessibility_tree_builder.h
@@ -30,7 +30,7 @@
 class PdfAccessibilityTreeBuilder {
  public:
   PdfAccessibilityTreeBuilder(
-      base::WeakPtr<PdfAccessibilityTree> pdf_accessibility_tree,
+      bool mark_headings_using_heuristic,
       const std::vector<chrome_pdf::AccessibilityTextRunInfo>& text_runs,
       const std::vector<chrome_pdf::AccessibilityCharInfo>& chars,
       const chrome_pdf::AccessibilityPageObjects& page_objects,
@@ -61,7 +61,8 @@
   void AddWordStartsAndEnds(ui::AXNodeData* inline_text_box);
   ui::AXNodeData* CreateAndAppendNode(ax::mojom::Role role,
                                       ax::mojom::Restriction restriction);
-  ui::AXNodeData* CreateParagraphNode(float font_size);
+  ui::AXNodeData* CreateBlockLevelNode(const std::string& text_run_type,
+                                       float font_size);
   ui::AXNodeData* CreateStaticTextNode();
   ui::AXNodeData* CreateStaticTextNode(
       const chrome_pdf::PageCharacterIndex& page_char_index);
@@ -128,7 +129,7 @@
       size_t* text_run_index);
   void AddRemainingAnnotations(ui::AXNodeData* para_node, bool ocr_applied);
 
-  base::WeakPtr<PdfAccessibilityTree> pdf_accessibility_tree_;
+  const bool mark_headings_using_heuristic_;
   std::vector<uint32_t> text_run_start_indices_;
   const raw_ref<const std::vector<chrome_pdf::AccessibilityTextRunInfo>>
       text_runs_;
diff --git a/components/pdf/renderer/pdf_accessibility_tree_unittest.cc b/components/pdf/renderer/pdf_accessibility_tree_unittest.cc
index 743ad81..be92b2d2 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_unittest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_unittest.cc
@@ -13,11 +13,11 @@
 namespace pdf {
 
 const chrome_pdf::AccessibilityTextRunInfo kFirstTextRun = {
-    15, gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
+    15, "Span", gfx::RectF(26.0f, 189.0f, 84.0f, 13.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityTextRunInfo kSecondTextRun = {
-    15, gfx::RectF(28.0f, 117.0f, 152.0f, 19.0f),
+    15, "Span", gfx::RectF(28.0f, 117.0f, 152.0f, 19.0f),
     chrome_pdf::AccessibilityTextDirection::kNone,
     chrome_pdf::AccessibilityTextStyleInfo()};
 const chrome_pdf::AccessibilityCharInfo kDummyCharsData[] = {
diff --git a/components/signin/core/browser/signin_metrics_service.cc b/components/signin/core/browser/signin_metrics_service.cc
index d2bf51bb..47fdfbd 100644
--- a/components/signin/core/browser/signin_metrics_service.cc
+++ b/components/signin/core/browser/signin_metrics_service.cc
@@ -193,7 +193,6 @@
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return;
   }
 
@@ -399,14 +398,12 @@
           signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN) {
         base::UmaHistogramEnumeration(
             "Signin.SigninPending.ResolutionSourceStarted",
-            account_info.access_point,
-            signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+            account_info.access_point);
       }
 
       base::UmaHistogramEnumeration(
           "Signin.SigninPending.ResolutionSourceCompleted",
-          account_info.access_point,
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+          account_info.access_point);
     }
   }
 }
@@ -475,9 +472,8 @@
     if (start_time.has_value()) {
       MaybeRecordWebSigninToChromeSigninTimes(start_time.value(), access_point);
 
-      base::UmaHistogramEnumeration(
-          "Signin.WebSignin.SourceToChromeSignin", access_point,
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+      base::UmaHistogramEnumeration("Signin.WebSignin.SourceToChromeSignin",
+                                    access_point);
     }
     // Clear all related web signin information on the first Chrome signin
     // event.
@@ -495,8 +491,8 @@
                                 signin_choice);
   if (signin_choice == ChromeSigninUserChoice::kDoNotSignin) {
     base::UmaHistogramEnumeration(
-        "Signin.Settings.ChromeSignin.AccessPointWithDoNotSignin", access_point,
-        signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+        "Signin.Settings.ChromeSignin.AccessPointWithDoNotSignin",
+        access_point);
   }
 }
 
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index aefc281..4690c781 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -72,8 +72,7 @@
       DCHECK(event_details.GetSetPrimaryAccountAccessPoint().has_value());
       base::UmaHistogramEnumeration(
           "Signin.SignIn.Completed",
-          event_details.GetSetPrimaryAccountAccessPoint().value(),
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+          event_details.GetSetPrimaryAccountAccessPoint().value());
       break;
 
     case PrimaryAccountChangeEvent::Type::kCleared:
@@ -92,8 +91,7 @@
       DCHECK(event_details.GetSetPrimaryAccountAccessPoint().has_value());
       base::UmaHistogramEnumeration(
           "Signin.SyncOptIn.Completed",
-          event_details.GetSetPrimaryAccountAccessPoint().value(),
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+          event_details.GetSetPrimaryAccountAccessPoint().value());
       break;
 
     case PrimaryAccountChangeEvent::Type::kCleared:
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 0a50001e..792e217 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -80,70 +80,54 @@
 
 void LogSigninAccessPointStarted(AccessPoint access_point,
                                  PromoAction promo_action) {
-  UMA_HISTOGRAM_ENUMERATION("Signin.SigninStartedAccessPoint",
-                            static_cast<int>(access_point),
-                            static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+  UMA_HISTOGRAM_ENUMERATION("Signin.SigninStartedAccessPoint", access_point);
   switch (promo_action) {
     case PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO:
       break;
     case PromoAction::PROMO_ACTION_WITH_DEFAULT:
-      UMA_HISTOGRAM_ENUMERATION(
-          "Signin.SigninStartedAccessPoint.WithDefault",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+      UMA_HISTOGRAM_ENUMERATION("Signin.SigninStartedAccessPoint.WithDefault",
+                                access_point);
       break;
     case PromoAction::PROMO_ACTION_NOT_DEFAULT:
-      UMA_HISTOGRAM_ENUMERATION(
-          "Signin.SigninStartedAccessPoint.NotDefault",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+      UMA_HISTOGRAM_ENUMERATION("Signin.SigninStartedAccessPoint.NotDefault",
+                                access_point);
       break;
     case PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT:
       UMA_HISTOGRAM_ENUMERATION(
           "Signin.SigninStartedAccessPoint.NewAccountNoExistingAccount",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+          access_point);
       break;
     case PromoAction::PROMO_ACTION_NEW_ACCOUNT_EXISTING_ACCOUNT:
       UMA_HISTOGRAM_ENUMERATION(
           "Signin.SigninStartedAccessPoint.NewAccountExistingAccount",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+          access_point);
       break;
   }
 }
 
 void LogSigninAccessPointCompleted(AccessPoint access_point,
                                    PromoAction promo_action) {
-  UMA_HISTOGRAM_ENUMERATION("Signin.SigninCompletedAccessPoint",
-                            static_cast<int>(access_point),
-                            static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+  UMA_HISTOGRAM_ENUMERATION("Signin.SigninCompletedAccessPoint", access_point);
   switch (promo_action) {
     case PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO:
       break;
     case PromoAction::PROMO_ACTION_WITH_DEFAULT:
-      UMA_HISTOGRAM_ENUMERATION(
-          "Signin.SigninCompletedAccessPoint.WithDefault",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+      UMA_HISTOGRAM_ENUMERATION("Signin.SigninCompletedAccessPoint.WithDefault",
+                                access_point);
       break;
     case PromoAction::PROMO_ACTION_NOT_DEFAULT:
-      UMA_HISTOGRAM_ENUMERATION(
-          "Signin.SigninCompletedAccessPoint.NotDefault",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+      UMA_HISTOGRAM_ENUMERATION("Signin.SigninCompletedAccessPoint.NotDefault",
+                                access_point);
       break;
     case PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT:
       UMA_HISTOGRAM_ENUMERATION(
           "Signin.SigninCompletedAccessPoint.NewAccountNoExistingAccount",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+          access_point);
       break;
     case PromoAction::PROMO_ACTION_NEW_ACCOUNT_EXISTING_ACCOUNT:
       UMA_HISTOGRAM_ENUMERATION(
           "Signin.SigninCompletedAccessPoint.NewAccountExistingAccount",
-          static_cast<int>(access_point),
-          static_cast<int>(AccessPoint::ACCESS_POINT_MAX));
+          access_point);
       break;
   }
 }
@@ -153,8 +137,7 @@
       "Signin.SignIn.Offered";
 
   // Log the generic offered histogram.
-  base::UmaHistogramEnumeration(signin_offered_base_histogram, access_point,
-                                AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration(signin_offered_base_histogram, access_point);
 
   // Do not record the histogram with a promo suffix if this is invoked/recorded
   // from a non-promo context.
@@ -166,12 +149,11 @@
   base::UmaHistogramEnumeration(
       base::StrCat({signin_offered_base_histogram,
                     GetPromoActionHistogramSuffix(promo_action)}),
-      access_point, AccessPoint::ACCESS_POINT_MAX);
+      access_point);
 }
 
 void LogSignInStarted(AccessPoint access_point) {
-  base::UmaHistogramEnumeration("Signin.SignIn.Started", access_point,
-                                AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration("Signin.SignIn.Started", access_point);
 }
 
 #if BUILDFLAG(IS_IOS)
@@ -182,13 +164,12 @@
 #endif  // BUILDFLAG(IS_IOS)
 
 void LogSyncOptInStarted(AccessPoint access_point) {
-  base::UmaHistogramEnumeration("Signin.SyncOptIn.Started", access_point,
-                                AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration("Signin.SyncOptIn.Started", access_point);
 }
 
 void LogSyncSettingsOpened(AccessPoint access_point) {
   base::UmaHistogramEnumeration("Signin.SyncOptIn.OpenedSyncSettings",
-                                access_point, AccessPoint::ACCESS_POINT_MAX);
+                                access_point);
 }
 
 void RecordAccountsPerProfile(int total_number_accounts) {
@@ -363,7 +344,7 @@
     base::UmaHistogramEnumeration(
         base::StrCat(
             {"Signin.HistoryAlreadyOptedInAccessPoint", consent_level_token}),
-        access_point, AccessPoint::ACCESS_POINT_MAX);
+        access_point);
   }
 }
 
@@ -593,8 +574,6 @@
       base::RecordAction(
           base::UserMetricsAction("Signin_Signin_FromAddressBubble"));
       break;
-    case AccessPoint::ACCESS_POINT_MAX:
-      NOTREACHED();
   }
 }
 
@@ -769,7 +748,6 @@
     case AccessPoint::ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Signin_Impression_From* user actions are not recorded "
                       "for access point "
                    << static_cast<int>(access_point);
@@ -877,8 +855,7 @@
       break;
   }
 
-  base::UmaHistogramEnumeration(histogram, access_point,
-                                AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration(histogram, access_point);
 }
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
 
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index 436d60f..50dff943 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -256,7 +256,7 @@
   // Add values above this line with a corresponding label to the
   // "SigninAccessPoint" enum in
   // tools/metrics/histograms/metadata/signin/enums.xml.
-  ACCESS_POINT_MAX,  // This must be last.
+  kMaxValue = ACCESS_POINT_COLLABORATION_TAB_GROUP,  // This must be last.
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/signin/enums.xml)
 
diff --git a/components/signin/public/base/signin_metrics_unittest.cc b/components/signin/public/base/signin_metrics_unittest.cc
index 0e0b374..854f2315 100644
--- a/components/signin/public/base/signin_metrics_unittest.cc
+++ b/components/signin/public/base/signin_metrics_unittest.cc
@@ -216,8 +216,6 @@
         return "DriveFilePickerIOS";
       case AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
         return "ShareGroupCollaboration";
-      case AccessPoint::ACCESS_POINT_MAX:
-        NOTREACHED();
     }
   }
 };
diff --git a/components/signin/public/base/signin_switches.cc b/components/signin/public/base/signin_switches.cc
index 44f9810..8c785c3 100644
--- a/components/signin/public/base/signin_switches.cc
+++ b/components/signin/public/base/signin_switches.cc
@@ -158,12 +158,6 @@
 #endif
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
-BASE_FEATURE(kPreconnectAccountCapabilitiesPostSignin,
-             "PreconnectAccountCapabilitiesPostSignin",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-#endif
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 BASE_FEATURE(kBatchUploadDesktop,
              "BatchUploadDesktop",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/signin/public/base/signin_switches.h b/components/signin/public/base/signin_switches.h
index b64b92c..de1b3e78 100644
--- a/components/signin/public/base/signin_switches.h
+++ b/components/signin/public/base/signin_switches.h
@@ -128,13 +128,6 @@
 BASE_DECLARE_FEATURE(kEnableASWebAuthenticationSession);
 #endif
 
-// Pre-connectes the network socket for the Account Capabilities fetch, after
-// receiving the signin response header from Gaia.
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-COMPONENT_EXPORT(SIGNIN_SWITCHES)
-BASE_DECLARE_FEATURE(kPreconnectAccountCapabilitiesPostSignin);
-#endif
-
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 COMPONENT_EXPORT(SIGNIN_SWITCHES)
 BASE_DECLARE_FEATURE(kBatchUploadDesktop);
diff --git a/docs/adding_to_third_party.md b/docs/adding_to_third_party.md
index 9f0b30e..e54d2d2 100644
--- a/docs/adding_to_third_party.md
+++ b/docs/adding_to_third_party.md
@@ -311,10 +311,66 @@
 different parts have different restrictions, these are inherently 'and'. This is
 very different to a project allowing multiple license options.
 
-The license field in README.chromium must use a _comma-separated list_ of licenses
+The `License:` field in README.chromium must use a _comma-separated list_ of licenses
 that are actively in use. Complex license expressions are not allowed or
 supported.
 
+Use SPDX license identifiers (https://spdx.org/licenses/) when possible e.g.
+['Apache-2.0'](https://spdx.org/licenses/Apache-2.0.html). You can find the full
+allowlist in
+[depot_tools/+/main:metadata/fields/custom/license_allowlist.py](https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:metadata/fields/custom/license_allowlist.py).
+If the dependency uses a license that is not in the allowlist, you will need to
+add it to the
+[allowlist](https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:metadata/fields/custom/license_allowlist.py).
+This requires approval from the ATLs who will check that the license
+classification is one of [unencumbered/permissive/notice/reciprocal]. If the
+license is more restrictive than reciprocal, engage with the ATLs to determine
+if the dependency is appropriate for Chromium. The license identifier will still
+need to be added to the restricted list
+['WITH_PERMISSION_ONLY'](https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:metadata/fields/custom/license_allowlist.py).
+Do not use a license on that list without approval from the ATLs.
+
+#### License Classifications
+
+Licenses used in our codebase fall into several categories of increasing
+restrictiveness, with notice-level and less restrictive licenses being allowed
+in all projects:
+
+* **Public Domain/Unencumbered/Permissive Licenses** - These licenses allow
+  you to do almost anything with the code, they may require attribution e.g.:
+  * [CC0-1.0](https://spdx.org/licenses/CC0-1.0.html).
+  * [Unlicense](https://spdx.org/licenses/Unlicense.html).
+* **Notice Licenses** - (Most open source licenses fall into this category)
+  These licenses are similar to permissive but have additional notice
+  requirements e.g.:
+  * [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html): [`Any modified files
+      must carry prominent notices stating that you changed the
+      files`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/catapult/third_party/coverage/LICENSE.txt;l=98).
+  * [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause): [`3. Neither the
+     name of the copyright holder nor the names of its contributors may be
+     used to endorse or promote products derived from this software without
+     specific prior written
+     permission.`](https://source.chromium.org/chromium/chromium/src/+/main:ios/third_party/fishhook/LICENSE;drc=1308ce89bbb959047a73145a0ca4a2f5f7dde894;l=10).
+
+Additionally, open source projects like Chromium are also allowed to use reciprocal licenses:
+
+*   **Reciprocal Licenses** - These licenses require sharing modifications under
+    the same terms:
+
+    *   [MPL-1.1](https://spdx.org/licenses/MPL-1.1.html).
+    *   [APSL-2.0](https://spdx.org/licenses/APSL-2.0.html).
+
+*   **Restricted Licenses !Case-by-case Approval Required!** - These licenses
+    have stricter requirements but are allowed in some circumstances. These
+    licenses may require you to publish the code under the same terms and
+    conditions:
+
+    *   [LGPL-2.1](https://spdx.org/licenses/LGPL-2.1.html).
+    *   [GPL-2.0](https://spdx.org/licenses/GPL-2.0.html).
+
+Make sure you understand the license terms before checking in a dependency, and
+when making any local modifications or forks.
+
 ## Get a review
 
 All third party additions and substantive changes like re-licensing need the
diff --git a/docs/website b/docs/website
index cfc3c3cb..fb143e8 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit cfc3c3cbd1b88b84ebecbf11e57faf79c2530e7f
+Subproject commit fb143e8ce76fcf5f67792fbbd6c219c5d03ec2d9
diff --git a/infra/config/generated/builders/ci/ToTMac/targets/chromium.clang.json b/infra/config/generated/builders/ci/ToTMac/targets/chromium.clang.json
index 744f21e..8196550 100644
--- a/infra/config/generated/builders/ci/ToTMac/targets/chromium.clang.json
+++ b/infra/config/generated/builders/ci/ToTMac/targets/chromium.clang.json
@@ -38,80 +38,6 @@
     "isolated_scripts": [
       {
         "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_python_tests",
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
-        },
-        "test": "blink_web_tests",
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "merge": {
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "chrome_sizes",
@@ -128,319 +54,6 @@
         },
         "test": "chrome_sizes",
         "test_id_prefix": "ninja://chrome/test:chrome_sizes/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "chrome_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_wpt_tests",
-        "test_id_prefix": "ninja://:chrome_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_py_tests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests_headless_shell",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_py_tests_headless_shell",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests_headless_shell/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_replay_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_perftests",
-        "test_id_prefix": "ninja://components:components_perftests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_shell_crash_test",
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "flatbuffers_unittests",
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "grit_python_unittests",
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "args": [
-          "--test-type",
-          "testharness",
-          "reftest",
-          "crashtest",
-          "print-reftest",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/content_shell.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "headless_shell_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 18
-        },
-        "test": "headless_shell_wpt",
-        "test_id_prefix": "ninja://:headless_shell_wpt/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mac_signing_tests",
-        "test_id_prefix": "ninja://chrome/installer/mac:mac_signing_tests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_python_unittests",
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "telemetry_gpu_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--extra-browser-args=--enable-crashpad"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_perf_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test": "telemetry_perf_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/"
-      },
-      {
-        "args": [
-          "--jobs=1",
-          "--extra-browser-args=--disable-gpu"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 8
-        },
-        "test": "telemetry_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_perftests",
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
       }
     ]
   }
diff --git a/infra/config/generated/testing/gn_isolate_map.pyl b/infra/config/generated/testing/gn_isolate_map.pyl
index 2a1426b0..4681d56 100644
--- a/infra/config/generated/testing/gn_isolate_map.pyl
+++ b/infra/config/generated/testing/gn_isolate_map.pyl
@@ -201,6 +201,7 @@
   "blink_python_tests": {
     "label": "//:blink_python_tests",
     "type": "generated_script",
+    "skip_usage_check": True,
   },
   "blink_pytype": {
     "label": "//third_party/blink/tools:blink_pytype",
@@ -560,6 +561,7 @@
     "label": "//chrome/test/chromedriver:chromedriver_py_tests",
     "type": "script",
     "script": "//testing/xvfb.py",
+    "skip_usage_check": True,
     "args": [
       "../../testing/scripts/run_chromedriver_tests.py",
       "../../chrome/test/chromedriver/test/run_py_tests.py",
@@ -572,6 +574,7 @@
     "label": "//chrome/test/chromedriver:chromedriver_py_tests_headless_shell",
     "type": "script",
     "script": "//testing/scripts/run_chromedriver_tests.py",
+    "skip_usage_check": True,
     "args": [
       "../../chrome/test/chromedriver/test/run_py_tests.py",
       "--chromedriver=chromedriver",
@@ -583,6 +586,7 @@
     "label": "//chrome/test/chromedriver:chromedriver_replay_unittests",
     "type": "script",
     "script": "//chrome/test/chromedriver/log_replay/client_replay_unittest.py",
+    "skip_usage_check": True,
   },
   "chromedriver_unittests": {
     "label": "//chrome/test/chromedriver:chromedriver_unittests",
@@ -673,6 +677,7 @@
     "label": "//components:components_perftests",
     "type": "script",
     "script": "//testing/scripts/run_performance_tests.py",
+    "skip_usage_check": True,
     "args": [
       "--xvfb",
       "--non-telemetry=true",
@@ -925,6 +930,7 @@
     "label": "//third_party/flatbuffers:flatbuffers_unittests",
     "type": "script",
     "script": "//testing/scripts/run_flatbuffers_unittests.py",
+    "skip_usage_check": True,
   },
   "fuchsia_pytype": {
     "label": "//testing:fuchsia_pytype",
@@ -1013,6 +1019,7 @@
     "label": "//tools/grit:grit_python_unittests",
     "type": "script",
     "script": "//testing/scripts/run_isolated_script_test.py",
+    "skip_usage_check": True,
     "args": [
       "../../tools/grit/grit/test_suite_all.py",
     ],
@@ -1224,6 +1231,7 @@
   "mac_signing_tests": {
     "label": "//chrome/installer/mac:mac_signing_tests",
     "type": "generated_script",
+    "skip_usage_check": True,
   },
   "media_base_junit_tests": {
     "label": "//media/base/android:media_base_junit_tests",
@@ -1299,6 +1307,7 @@
     "label": "//mojo/public/tools:mojo_python_unittests",
     "type": "script",
     "script": "//testing/scripts/run_isolated_script_test.py",
+    "skip_usage_check": True,
     "args": [
       "../../mojo/public/tools/run_all_python_unittests.py",
     ],
@@ -1979,6 +1988,7 @@
     "label": "//ui/views:views_perftests",
     "type": "script",
     "script": "//testing/scripts/run_performance_tests.py",
+    "skip_usage_check": True,
     "args": [
       "--xvfb",
       "--non-telemetry=true",
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index 5e38dbd..74a87e7d 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -152,30 +152,6 @@
       },
     },
 
-    'chromedriver_py_tests_isolated_scripts': {
-      'chromedriver_py_tests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-        'args': [
-          '--test-type=integration',
-        ],
-      },
-      'chromedriver_py_tests_headless_shell': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-        'args': [
-          '--test-type=integration',
-        ],
-      },
-      'chromedriver_replay_unittests': {},
-    },
-
     'chromeos_chrome_all_tast_tests': {
       'chrome_all_tast_tests': {
         'skylab': {
@@ -854,180 +830,6 @@
       },
     },
 
-    'components_perftests_isolated_scripts': {
-      'components_perftests': {
-        'test_common': {
-          'merge': {
-            'script': '//tools/perf/process_perf_results.py',
-            'args': [
-              '--smoke-test-mode',
-            ],
-          },
-        },
-        'args': [
-          '--gtest-benchmark-name=components_perftests',
-        ],
-      },
-    },
-
-    'desktop_chromium_isolated_scripts': {
-      'blink_python_tests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-      },
-      'blink_web_tests': {
-        'test_common': {
-          'mixins': [
-            'has_native_resultdb_integration',
-            'blink_tests_write_run_histories',
-          ],
-          'args': [
-            '--num-retries=3',
-          ],
-          'merge': {
-            'script': '//third_party/blink/tools/merge_web_test_results.py',
-            'args': [
-              '--verbose',
-            ],
-          },
-        },
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 5,
-        },
-      },
-      'blink_wpt_tests': {
-        'test_common': {
-          'mixins': [
-            'has_native_resultdb_integration',
-            'blink_tests_write_run_histories',
-          ],
-          'args': [
-            '--num-retries=3',
-          ],
-          'merge': {
-            'script': '//third_party/blink/tools/merge_web_test_results.py',
-            'args': [
-              '--verbose',
-            ],
-          },
-        },
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 7,
-        },
-      },
-      'chrome_wpt_tests': {
-        'test_common': {
-          'mixins': [
-            'has_native_resultdb_integration',
-          ],
-          'args': [
-            '--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter',
-          ],
-          'merge': {
-            'script': '//third_party/blink/tools/merge_web_test_results.py',
-            'args': [
-              '--verbose',
-            ],
-          },
-        },
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 1,
-        },
-      },
-      'content_shell_crash_test': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-            'result_format': 'single',
-          },
-        },
-      },
-      'flatbuffers_unittests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-            'result_format': 'single',
-          },
-        },
-      },
-      'grit_python_unittests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-      },
-      'headless_shell_wpt_tests': {
-        'test_common': {
-          'mixins': [
-            'has_native_resultdb_integration',
-          ],
-          'args': [
-            '--test-type',
-            'testharness',
-            'reftest',
-            'crashtest',
-            'print-reftest',
-            '--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter',
-            '--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/content_shell.filter',
-          ],
-          'merge': {
-            'script': '//third_party/blink/tools/merge_web_test_results.py',
-            'args': [
-              '--verbose',
-            ],
-          },
-        },
-        'test': 'headless_shell_wpt',
-        'results_handler': 'layout tests',
-        'swarming': {
-          'shards': 18,
-        },
-      },
-      'telemetry_gpu_unittests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-        'swarming': {
-          'idempotent': False,
-        },
-      },
-      'telemetry_unittests': {
-        'args': [
-          '--jobs=1',
-          '--extra-browser-args=--disable-gpu',
-        ],
-        'swarming': {
-          'shards': 8,
-          'idempotent': False,
-        },
-        'resultdb': {
-          'enable': True,
-        },
-      },
-      'views_perftests': {
-        'test_common': {
-          'merge': {
-            'script': '//tools/perf/process_perf_results.py',
-            'args': [
-              '--smoke-test-mode',
-            ],
-          },
-        },
-        'args': [
-          '--gtest-benchmark-name=views_perftests',
-        ],
-      },
-    },
-
     'devtools_browser_tests_suite': {
       'devtools_browser_tests': {
         'test_common': {
@@ -2432,10 +2234,6 @@
       },
     },
 
-    'mac_specific_isolated_scripts': {
-      'mac_signing_tests': {},
-    },
-
     'model_validation_tests_light_suite': {
       'model_validation_tests_light': {
         'mixins': [
@@ -2480,16 +2278,6 @@
       },
     },
 
-    'mojo_python_unittests_isolated_scripts': {
-      'mojo_python_unittests': {
-        'test_common': {
-          'resultdb': {
-            'enable': True,
-          },
-        },
-      },
-    },
-
     'non_android_chromium_gtests': {
       'accessibility_unittests': {},
       'app_shell_unittests': {},
@@ -2641,21 +2429,6 @@
       },
     },
 
-    'telemetry_perf_unittests_isolated_scripts': {
-      'telemetry_perf_unittests': {
-        'args': [
-          '--extra-browser-args=--enable-crashpad',
-        ],
-        'swarming': {
-          'shards': 12,
-          'idempotent': False,
-        },
-        'resultdb': {
-          'enable': True,
-        },
-      },
-    },
-
     'vulkan_swiftshader_isolated_scripts': {
       'vulkan_swiftshader_blink_web_tests': {
         'test_common': {
@@ -2773,16 +2546,6 @@
       'vulkan_swiftshader_isolated_scripts',
     ],
 
-    'chromium_mac_rel_isolated_scripts_and_sizes': [
-      'chrome_sizes_suite',
-      'chromedriver_py_tests_isolated_scripts',
-      'components_perftests_isolated_scripts',
-      'desktop_chromium_isolated_scripts',
-      'mac_specific_isolated_scripts',
-      'mojo_python_unittests_isolated_scripts',
-      'telemetry_perf_unittests_isolated_scripts',
-    ],
-
     'devtools_gtests': [
       'blink_unittests_suite',
       'devtools_browser_tests_suite',
diff --git a/infra/config/subprojects/chromium/ci/chromium.clang.star b/infra/config/subprojects/chromium/ci/chromium.clang.star
index ce1c1106..a158433f 100644
--- a/infra/config/subprojects/chromium/ci/chromium.clang.star
+++ b/infra/config/subprojects/chromium/ci/chromium.clang.star
@@ -1905,7 +1905,7 @@
     targets = targets.bundle(
         targets = [
             "clang_tot_gtests",
-            "chromium_mac_rel_isolated_scripts_and_sizes",
+            "chrome_sizes_suite",
         ],
         additional_compile_targets = [
             "all",
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index 72485d6..61c5bb2 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -82,23 +82,6 @@
 )
 
 targets.legacy_basic_suite(
-    name = "chromedriver_py_tests_isolated_scripts",
-    tests = {
-        "chromedriver_py_tests": targets.legacy_test_config(
-            args = [
-                "--test-type=integration",
-            ],
-        ),
-        "chromedriver_py_tests_headless_shell": targets.legacy_test_config(
-            args = [
-                "--test-type=integration",
-            ],
-        ),
-        "chromedriver_replay_unittests": targets.legacy_test_config(),
-    },
-)
-
-targets.legacy_basic_suite(
     name = "chromeos_chrome_all_tast_tests",
     tests = {
         "chrome_all_tast_tests": targets.legacy_test_config(
@@ -644,72 +627,6 @@
 )
 
 targets.legacy_basic_suite(
-    name = "components_perftests_isolated_scripts",
-    tests = {
-        "components_perftests": targets.legacy_test_config(
-            args = [
-                "--gtest-benchmark-name=components_perftests",
-            ],
-        ),
-    },
-)
-
-targets.legacy_basic_suite(
-    name = "desktop_chromium_isolated_scripts",
-    tests = {
-        "blink_python_tests": targets.legacy_test_config(),
-        "blink_web_tests": targets.legacy_test_config(
-            swarming = targets.swarming(
-                shards = 5,
-            ),
-        ),
-        "blink_wpt_tests": targets.legacy_test_config(
-            swarming = targets.swarming(
-                shards = 7,
-            ),
-        ),
-        "chrome_wpt_tests": targets.legacy_test_config(
-            swarming = targets.swarming(
-                shards = 1,
-            ),
-        ),
-        "headless_shell_wpt_tests": targets.legacy_test_config(
-            swarming = targets.swarming(
-                shards = 18,
-            ),
-        ),
-        "content_shell_crash_test": targets.legacy_test_config(),
-        "flatbuffers_unittests": targets.legacy_test_config(),
-        "grit_python_unittests": targets.legacy_test_config(),
-        "telemetry_gpu_unittests": targets.legacy_test_config(
-            swarming = targets.swarming(
-                idempotent = False,  # https://crbug.com/549140
-            ),
-        ),
-        "telemetry_unittests": targets.legacy_test_config(
-            args = [
-                "--jobs=1",
-                # Disable GPU compositing, telemetry_unittests runs on VMs.
-                # https://crbug.com/871955
-                "--extra-browser-args=--disable-gpu",
-            ],
-            swarming = targets.swarming(
-                shards = 8,
-                idempotent = False,  # https://crbug.com/549140
-            ),
-            resultdb = targets.resultdb(
-                enable = True,
-            ),
-        ),
-        "views_perftests": targets.legacy_test_config(
-            args = [
-                "--gtest-benchmark-name=views_perftests",
-            ],
-        ),
-    },
-)
-
-targets.legacy_basic_suite(
     name = "devtools_browser_tests_suite",
     tests = {
         "devtools_browser_tests": targets.legacy_test_config(
@@ -1724,13 +1641,6 @@
 )
 
 targets.legacy_basic_suite(
-    name = "mac_specific_isolated_scripts",
-    tests = {
-        "mac_signing_tests": targets.legacy_test_config(),
-    },
-)
-
-targets.legacy_basic_suite(
     name = "model_validation_tests_light_suite",
     tests = {
         "model_validation_tests_light": targets.legacy_test_config(
@@ -1781,13 +1691,6 @@
 )
 
 targets.legacy_basic_suite(
-    name = "mojo_python_unittests_isolated_scripts",
-    tests = {
-        "mojo_python_unittests": targets.legacy_test_config(),
-    },
-)
-
-targets.legacy_basic_suite(
     name = "non_android_chromium_gtests",
     tests = {
         "accessibility_unittests": targets.legacy_test_config(),
@@ -1976,25 +1879,6 @@
 )
 
 targets.legacy_basic_suite(
-    name = "telemetry_perf_unittests_isolated_scripts",
-    tests = {
-        "telemetry_perf_unittests": targets.legacy_test_config(
-            args = [
-                # TODO(crbug.com/40129085): Remove this once Crashpad is the default.
-                "--extra-browser-args=--enable-crashpad",
-            ],
-            swarming = targets.swarming(
-                shards = 12,
-                idempotent = False,  # https://crbug.com/549140
-            ),
-            resultdb = targets.resultdb(
-                enable = True,
-            ),
-        ),
-    },
-)
-
-targets.legacy_basic_suite(
     name = "vulkan_swiftshader_isolated_scripts",
     tests = {
         "vulkan_swiftshader_blink_web_tests": targets.legacy_test_config(),
diff --git a/infra/config/targets/binaries.star b/infra/config/targets/binaries.star
index ef5af01b..50bc0ddd 100644
--- a/infra/config/targets/binaries.star
+++ b/infra/config/targets/binaries.star
@@ -233,6 +233,8 @@
 targets.binaries.generated_script(
     name = "blink_python_tests",
     label = "//:blink_python_tests",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     resultdb = targets.resultdb(
         enable = True,
     ),
@@ -561,6 +563,8 @@
     name = "chromedriver_py_tests",
     label = "//chrome/test/chromedriver:chromedriver_py_tests",
     script = "//testing/xvfb.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "../../testing/scripts/run_chromedriver_tests.py",
         "../../chrome/test/chromedriver/test/run_py_tests.py",
@@ -577,6 +581,8 @@
     name = "chromedriver_py_tests_headless_shell",
     label = "//chrome/test/chromedriver:chromedriver_py_tests_headless_shell",
     script = "//testing/scripts/run_chromedriver_tests.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "../../chrome/test/chromedriver/test/run_py_tests.py",
         "--chromedriver=chromedriver",
@@ -631,6 +637,8 @@
     name = "chromedriver_replay_unittests",
     label = "//chrome/test/chromedriver:chromedriver_replay_unittests",
     script = "//chrome/test/chromedriver/log_replay/client_replay_unittest.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
 )
 
 targets.binaries.windowed_test_launcher(
@@ -684,6 +692,8 @@
     name = "components_perftests",
     label = "//components:components_perftests",
     script = "//testing/scripts/run_performance_tests.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "--xvfb",
         "--non-telemetry=true",
@@ -994,6 +1004,8 @@
     name = "flatbuffers_unittests",
     label = "//third_party/flatbuffers:flatbuffers_unittests",
     script = "//testing/scripts/run_flatbuffers_unittests.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     resultdb = targets.resultdb(
         enable = True,
         result_format = "single",
@@ -1106,6 +1118,8 @@
     name = "grit_python_unittests",
     label = "//tools/grit:grit_python_unittests",
     script = "//testing/scripts/run_isolated_script_test.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "../../tools/grit/grit/test_suite_all.py",
     ],
@@ -1332,6 +1346,8 @@
 targets.binaries.generated_script(
     name = "mac_signing_tests",
     label = "//chrome/installer/mac:mac_signing_tests",
+    # All references have been moved to starlark
+    skip_usage_check = True,
 )
 
 targets.binaries.generated_script(
@@ -1439,6 +1455,8 @@
     name = "mojo_python_unittests",
     label = "//mojo/public/tools:mojo_python_unittests",
     script = "//testing/scripts/run_isolated_script_test.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "../../mojo/public/tools/run_all_python_unittests.py",
     ],
@@ -2219,6 +2237,8 @@
     name = "views_perftests",
     label = "//ui/views:views_perftests",
     script = "//testing/scripts/run_performance_tests.py",
+    # All references have been moved to starlark
+    skip_usage_check = True,
     args = [
         "--xvfb",
         "--non-telemetry=true",
diff --git a/infra/config/targets/bundles.star b/infra/config/targets/bundles.star
index d011783..396db454 100644
--- a/infra/config/targets/bundles.star
+++ b/infra/config/targets/bundles.star
@@ -1051,6 +1051,27 @@
 )
 
 targets.bundle(
+    name = "chromedriver_py_tests_isolated_scripts",
+    targets = [
+        "chromedriver_py_tests",
+        "chromedriver_py_tests_headless_shell",
+        "chromedriver_replay_unittests",
+    ],
+    per_test_modifications = {
+        "chromedriver_py_tests": targets.mixin(
+            args = [
+                "--test-type=integration",
+            ],
+        ),
+        "chromedriver_py_tests_headless_shell": targets.mixin(
+            args = [
+                "--test-type=integration",
+            ],
+        ),
+    },
+)
+
+targets.bundle(
     name = "chromeos_annotation_scripts",
     targets = [
         "check_network_annotations",
@@ -2113,6 +2134,20 @@
     ],
 )
 
+targets.bundle(
+    name = "components_perftests_isolated_scripts",
+    targets = [
+        "components_perftests",
+    ],
+    per_test_modifications = {
+        "components_perftests": targets.mixin(
+            args = [
+                "--gtest-benchmark-name=components_perftests",
+            ],
+        ),
+    },
+)
+
 # Compilable unit tests of cronet dependencies in:
 # //components/cronet/android/dependencies.txt
 # TODO(crbug.com/333888734): Add component_unittests or a subset of it.
@@ -2234,6 +2269,68 @@
 )
 
 targets.bundle(
+    name = "desktop_chromium_isolated_scripts",
+    targets = [
+        "blink_python_tests",
+        "blink_web_tests",
+        "blink_wpt_tests",
+        "chrome_wpt_tests",
+        "content_shell_crash_test",
+        "flatbuffers_unittests",
+        "grit_python_unittests",
+        "headless_shell_wpt_tests",
+        "telemetry_gpu_unittests",
+        "telemetry_unittests",
+        "views_perftests",
+    ],
+    per_test_modifications = {
+        "blink_web_tests": targets.mixin(
+            swarming = targets.swarming(
+                shards = 5,
+            ),
+        ),
+        "blink_wpt_tests": targets.mixin(
+            swarming = targets.swarming(
+                shards = 7,
+            ),
+        ),
+        "chrome_wpt_tests": targets.mixin(
+            swarming = targets.swarming(
+                shards = 1,
+            ),
+        ),
+        "headless_shell_wpt_tests": targets.mixin(
+            swarming = targets.swarming(
+                shards = 18,
+            ),
+        ),
+        "telemetry_gpu_unittests": targets.mixin(
+            swarming = targets.swarming(
+                idempotent = False,
+            ),
+        ),
+        "telemetry_unittests": targets.mixin(
+            args = [
+                "--jobs=1",
+                "--extra-browser-args=--disable-gpu",
+            ],
+            swarming = targets.swarming(
+                shards = 8,
+                idempotent = False,
+            ),
+            resultdb = targets.resultdb(
+                enable = True,
+            ),
+        ),
+        "views_perftests": targets.mixin(
+            args = [
+                "--gtest-benchmark-name=views_perftests",
+            ],
+        ),
+    },
+)
+
+targets.bundle(
     name = "desktop_chromium_mac_osxbeta_scripts",
     targets = [
         "content_shell_crash_test",
@@ -5327,6 +5424,13 @@
 )
 
 targets.bundle(
+    name = "mac_specific_isolated_scripts",
+    targets = [
+        "mac_signing_tests",
+    ],
+)
+
+targets.bundle(
     name = "mac_vm_tests",
     targets = [
         "base_unittests",
@@ -5342,6 +5446,13 @@
 )
 
 targets.bundle(
+    name = "mojo_python_unittests_isolated_scripts",
+    targets = [
+        "mojo_python_unittests",
+    ],
+)
+
+targets.bundle(
     name = "monochrome_public_apk_checker_isolated_script",
     targets = [
         "monochrome_public_apk_checker",
@@ -5852,6 +5963,27 @@
 )
 
 targets.bundle(
+    name = "telemetry_perf_unittests_isolated_scripts",
+    targets = [
+        "telemetry_perf_unittests",
+    ],
+    per_test_modifications = {
+        "telemetry_perf_unittests": targets.mixin(
+            args = [
+                "--extra-browser-args=--enable-crashpad",
+            ],
+            swarming = targets.swarming(
+                shards = 12,
+                idempotent = False,
+            ),
+            resultdb = targets.resultdb(
+                enable = True,
+            ),
+        ),
+    },
+)
+
+targets.bundle(
     name = "telemetry_perf_unittests_isolated_scripts_android",
     targets = [
         "telemetry_perf_unittests_android_chrome",
diff --git a/infra/config/targets/compound_suites.star b/infra/config/targets/compound_suites.star
index 88b9cce..d0b6080 100644
--- a/infra/config/targets/compound_suites.star
+++ b/infra/config/targets/compound_suites.star
@@ -30,19 +30,6 @@
 )
 
 targets.legacy_compound_suite(
-    name = "chromium_mac_rel_isolated_scripts_and_sizes",
-    basic_suites = [
-        "chrome_sizes_suite",
-        "chromedriver_py_tests_isolated_scripts",
-        "components_perftests_isolated_scripts",
-        "desktop_chromium_isolated_scripts",
-        "mac_specific_isolated_scripts",
-        "mojo_python_unittests_isolated_scripts",
-        "telemetry_perf_unittests_isolated_scripts",
-    ],
-)
-
-targets.legacy_compound_suite(
     name = "devtools_gtests",
     basic_suites = [
         "devtools_browser_tests_suite",
diff --git a/internal b/internal
index 3ce4702c..07d1b81 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 3ce4702c33df16bb3cc2619173d8f80639872707
+Subproject commit 07d1b817873ca3c81870063eceec46298d475541
diff --git a/ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_coordinator.mm
index ab203e73..dbf546b 100644
--- a/ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_coordinator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/history_sync/history_sync_coordinator.mm
@@ -62,16 +62,14 @@
     case history_sync::HistorySyncSkipReason::kSyncForbiddenByPolicies:
     case history_sync::HistorySyncSkipReason::kDeclinedTooOften:
       base::RecordAction(base::UserMetricsAction("Signin_HistorySync_Skipped"));
-      base::UmaHistogramEnumeration(
-          "Signin.HistorySyncOptIn.Skipped", accessPoint,
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+      base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Skipped",
+                                    accessPoint);
       break;
     case history_sync::HistorySyncSkipReason::kAlreadyOptedIn:
       base::RecordAction(
           base::UserMetricsAction("Signin_HistorySync_AlreadyOptedIn"));
-      base::UmaHistogramEnumeration(
-          "Signin.HistorySyncOptIn.AlreadyOptedIn", accessPoint,
-          signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+      base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.AlreadyOptedIn",
+                                    accessPoint);
       break;
     case history_sync::HistorySyncSkipReason::kNone:
       // This method should not be called if the screen should be shown.
@@ -144,8 +142,8 @@
                                   first_run::kHistorySyncScreenStart);
   }
   base::RecordAction(base::UserMetricsAction("Signin_HistorySync_Started"));
-  base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Started", _accessPoint,
-                                signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+  base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Started",
+                                _accessPoint);
   _recordOptInEndAtStop = YES;
   BOOL animated = self.baseNavigationController.topViewController != nil;
   [self.baseNavigationController setViewControllers:@[ _viewController ]
@@ -163,9 +161,8 @@
     // This can also occur during the FRE, for instance if Chrome shuts down
     // when the screen is shown, or if FRE is dismissed due to policies change.
     base::RecordAction(base::UserMetricsAction("Signin_HistorySync_Aborted"));
-    base::UmaHistogramEnumeration(
-        "Signin.HistorySyncOptIn.Aborted", _accessPoint,
-        signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+    base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Aborted",
+                                  _accessPoint);
     _recordOptInEndAtStop = NO;
   }
   [_mediator disconnect];
@@ -202,8 +199,7 @@
         first_run::kHistorySyncScreenCompletionWithSync);
   }
   base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Completed",
-                                _accessPoint,
-                                signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+                                _accessPoint);
   _recordOptInEndAtStop = NO;
 
   [_delegate closeHistorySyncCoordinator:self declinedByUser:NO];
@@ -219,8 +215,7 @@
         first_run::kHistorySyncScreenCompletionWithoutSync);
   }
   base::UmaHistogramEnumeration("Signin.HistorySyncOptIn.Declined",
-                                _accessPoint,
-                                signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+                                _accessPoint);
   _recordOptInEndAtStop = NO;
 
   [_delegate closeHistorySyncCoordinator:self declinedByUser:YES];
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
index 59aa66e..e063f55 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
@@ -163,8 +163,6 @@
       // with an arbitrary entry point, API-wise. In doubt, no label is a good,
       // generic default that fits all entry points.
       return nil;
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
-      NOTREACHED();
   }
 }
 
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm b/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
index 39b4060c..26d559d9 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
@@ -140,7 +140,6 @@
     case signin_metrics::AccessPoint::ACCESS_POINT_ADDRESS_BUBBLE:
     case signin_metrics::AccessPoint::
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
 
@@ -246,7 +245,6 @@
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
   }
@@ -350,7 +348,6 @@
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
   }
@@ -443,7 +440,6 @@
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
 }
@@ -535,7 +531,6 @@
         ACCESS_POINT_CCT_ACCOUNT_MISMATCH_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_DRIVE_FILE_PICKER_IOS:
     case signin_metrics::AccessPoint::ACCESS_POINT_COLLABORATION_TAB_GROUP:
-    case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
 }
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index 74c155d..2073d2e48 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -100,6 +100,7 @@
     "//ios/chrome/browser/start_surface/ui_bundled:feature_flags",
     "//ios/chrome/browser/tabs/model/inactive_tabs:features",
     "//ios/chrome/browser/text_selection/model:model_utils",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/browser/ui/popup_menu/overflow_menu:feature_flags",
     "//ios/chrome/browser/ui/whats_new:util",
     "//ios/chrome/browser/web/model:feature_flags",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index e3b7fa6..e3208796 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -107,6 +107,7 @@
 #import "ios/chrome/browser/start_surface/ui_bundled/start_surface_features.h"
 #import "ios/chrome/browser/tabs/model/inactive_tabs/features.h"
 #import "ios/chrome/browser/text_selection/model/text_selection_util.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/chrome/browser/ui/popup_menu/overflow_menu/feature_flags.h"
 #import "ios/chrome/browser/ui/whats_new/whats_new_util.h"
 #import "ios/chrome/browser/web/model/features.h"
@@ -659,6 +660,41 @@
     {"(Always)", kLensTranslateToggleModeAlways,
      std::size(kLensTranslateToggleModeAlways), nullptr}};
 
+const FeatureEntry::FeatureParam kTabGroupIndicatorAboveButtonsVisble[] = {
+    {kTabGroupIndicatorVisible, "true"},
+    {kTabGroupIndicatorBelowOmnibox, "false"},
+    {kTabGroupIndicatorButtonsUpdate, "true"}};
+const FeatureEntry::FeatureParam kTabGroupIndicatorBelowButtonsVisble[] = {
+    {kTabGroupIndicatorVisible, "true"},
+    {kTabGroupIndicatorBelowOmnibox, "true"},
+    {kTabGroupIndicatorButtonsUpdate, "true"}};
+const FeatureEntry::FeatureParam kTabGroupIndicatorAboveVisble[] = {
+    {kTabGroupIndicatorVisible, "true"},
+    {kTabGroupIndicatorBelowOmnibox, "false"},
+    {kTabGroupIndicatorButtonsUpdate, "false"}};
+const FeatureEntry::FeatureParam kTabGroupIndicatorBelowVisble[] = {
+    {kTabGroupIndicatorVisible, "true"},
+    {kTabGroupIndicatorBelowOmnibox, "true"},
+    {kTabGroupIndicatorButtonsUpdate, "false"}};
+const FeatureEntry::FeatureParam kTabGroupIndicatorButtons[] = {
+    {kTabGroupIndicatorVisible, "false"},
+    {kTabGroupIndicatorBelowOmnibox, "false"},
+    {kTabGroupIndicatorButtonsUpdate, "true"}};
+
+const FeatureEntry::FeatureVariation kTabGroupIndicatorVariations[] = {
+    {"Indicator above omnibox + buttons update",
+     kTabGroupIndicatorAboveButtonsVisble,
+     std::size(kTabGroupIndicatorAboveButtonsVisble), nullptr},
+    {"Indicator below omnibox + buttons update",
+     kTabGroupIndicatorBelowButtonsVisble,
+     std::size(kTabGroupIndicatorBelowButtonsVisble), nullptr},
+    {"Indicator above omnibox", kTabGroupIndicatorAboveVisble,
+     std::size(kTabGroupIndicatorAboveVisble), nullptr},
+    {"Indicator below omnibox", kTabGroupIndicatorBelowVisble,
+     std::size(kTabGroupIndicatorBelowVisble), nullptr},
+    {"buttons update only", kTabGroupIndicatorButtons,
+     std::size(kTabGroupIndicatorButtons), nullptr}};
+
 const FeatureEntry::FeatureParam
     kMlUrlPiecewiseMappedSearchBlendingAdjustedBy0[] = {
         {"MlUrlPiecewiseMappedSearchBlending", "true"},
@@ -2065,7 +2101,9 @@
      FEATURE_VALUE_TYPE(kAutofillIsolatedWorldForJavascriptIos)},
     {"tab-group-indicator", flag_descriptions::kTabGroupIndicatorName,
      flag_descriptions::kTabGroupIndicatorDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kTabGroupIndicator)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(kTabGroupIndicator,
+                                    kTabGroupIndicatorVariations,
+                                    "TabGroupIndicator")},
     {"safe-browsing-local-lists-use-sbv5",
      flag_descriptions::kSafeBrowsingLocalListsUseSBv5Name,
      flag_descriptions::kSafeBrowsingLocalListsUseSBv5Description,
diff --git a/ios/chrome/browser/ntp/ui_bundled/BUILD.gn b/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
index 22f6cfe..1165e79 100644
--- a/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/ntp/ui_bundled/BUILD.gn
@@ -155,6 +155,7 @@
     "//ios/chrome/browser/supervised_user/model:capabilities",
     "//ios/chrome/browser/sync/model",
     "//ios/chrome/browser/toolbar/ui_bundled/public",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator",
     "//ios/chrome/browser/ui/content_suggestions",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_ui",
diff --git a/ios/chrome/browser/ntp/ui_bundled/DEPS b/ios/chrome/browser/ntp/ui_bundled/DEPS
index 1bfc1446..41a43586 100644
--- a/ios/chrome/browser/ntp/ui_bundled/DEPS
+++ b/ios/chrome/browser/ntp/ui_bundled/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ios/chrome/browser/toolbar/ui_bundled",
   "+ios/chrome/browser/bubble/ui_bundled",
   "+ios/chrome/browser/context_menu/ui_bundled/link_preview",
   "+ios/chrome/browser/favicon/ui_bundled",
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
index c24c53a2..fb5541c 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -1878,11 +1878,10 @@
     // for which of the access points they are triggered.
     base::UmaHistogramEnumeration(
         "Signin.ShowSigninCoordinatorWhenAlreadyPresent.NewAccessPoint",
-        accessPoint, signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+        accessPoint);
     base::UmaHistogramEnumeration(
         "Signin.ShowSigninCoordinatorWhenAlreadyPresent.OldAccessPoint",
-        self.signinCoordinator.accessPoint,
-        signin_metrics::AccessPoint::ACCESS_POINT_MAX);
+        self.signinCoordinator.accessPoint);
     // The goal of this histogram is to understand if the issue is related to
     // a double tap (duration less than 1s), or if `self.signinCoordinator`
     // is not visible anymore on the screen (duration more than 1s).
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/tab_group_grid_view_controller.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/tab_group_grid_view_controller.mm
index 9948f61..f9b4d24 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/tab_group_grid_view_controller.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/tab_group_grid_view_controller.mm
@@ -208,7 +208,6 @@
   [self.diffableDataSource applySnapshot:snapshot animatingDifferences:YES];
 }
 
-// TODO(crbug.com/370899564): Hide the summary after the several impressions.
 // Removes the activity summary cell from the current snapshot.
 - (void)removeActivitySummaryCell {
   GridSnapshot* snapshot = self.diffableDataSource.snapshot;
@@ -229,6 +228,7 @@
 }
 
 - (void)activityButtonForActivitySummaryTapped {
+  [self removeActivitySummaryCell];
   [self.viewDelegate showRecentActivity];
 }
 
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
index 72de8f8..a71002f 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/BUILD.gn
@@ -166,6 +166,7 @@
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:grid_view_delegate",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid:tab_group_grid_ui",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars:toolbars_ui",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/table_view:cells_constants",
     "//ios/chrome/common/ui/util",
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/DEPS b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/DEPS
index a62ac50..bb4f7796 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/DEPS
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/DEPS
@@ -4,4 +4,5 @@
   "+components/data_sharing/public",
   "+components/saved_tab_groups/public",
   "+components/saved_tab_groups/test_support",
+  "+ios/chrome/browser/toolbar/ui_bundled",
 ]
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
index 2a6cdb4..c37768e 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_mediator.mm
@@ -484,11 +484,6 @@
           [self.consumer removeItemWithIdentifier:tabIdentifierToAddToGroup
                            selectedItemIdentifier:[self activeIdentifier]];
           [self removeObservationForWebState:currentWebState];
-
-          // Remove a moved WebState from `_dirtyTabs`, otherwise `_dirtyTabs`
-          // keeps holding old tabs when the tab is moved locally.
-          _dirtyTabs.erase(currentWebState->GetUniqueIdentifier().identifier());
-          [self updateActivitySummaryCell];
         }
 
         if (newGroup == _tabGroup.get()) {
@@ -544,11 +539,6 @@
           [self.consumer removeItemWithIdentifier:item
                            selectedItemIdentifier:[self activeIdentifier]];
           [self removeObservationForWebState:webState];
-
-          // Remove a moved WebState from `_dirtyTabs`, otherwise `_dirtyTabs`
-          // keeps holding old tabs when the tab is moved locally.
-          _dirtyTabs.erase(webState->GetUniqueIdentifier().identifier());
-          [self updateActivitySummaryCell];
         } else if (moveChange.new_group() == _tabGroup.get()) {
           // The tab joined the group.
           [self insertInConsumerWebState:webState
@@ -571,18 +561,6 @@
       [self addObservationForWebState:insertChange.inserted_web_state()];
       break;
     }
-    case WebStateListChange::Type::kDetach: {
-      const WebStateListChangeDetach& detachChange =
-          change.As<WebStateListChangeDetach>();
-
-      // Remove a detached WebState from `_dirtyTabs`, otherwise `_dirtyTabs`
-      // keeps holding old tabs when the tab is removed locally.
-      _dirtyTabs.erase(detachChange.detached_web_state()
-                           ->GetUniqueIdentifier()
-                           .identifier());
-      [self updateActivitySummaryCell];
-      break;
-    }
     default:
       [super didChangeWebStateList:webStateList change:change status:status];
       break;
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_view_controller.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_view_controller.mm
index dd0e251c..2f65bb9e 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_view_controller.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_view_controller.mm
@@ -26,6 +26,7 @@
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_bottom_toolbar.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_toolbars_grid_delegate.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_group_action_type.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
@@ -375,7 +376,7 @@
         [[UIBarButtonItem alloc] initWithCustomView:facePileButton];
   }
 
-  if (IsTabGroupIndicatorEnabled()) {
+  if (IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()) {
     if (facePileBarButton) {
       navigationItem.rightBarButtonItems = @[ dotsItem, facePileBarButton ];
     } else {
@@ -492,7 +493,7 @@
 
 // Adds the bottom toolbar containing the "plus" button.
 - (void)configureBottomToolbar {
-  if (!IsTabGroupIndicatorEnabled()) {
+  if (!IsTabGroupIndicatorEnabled() || !HasTabGroupIndicatorButtonsUpdated()) {
     return;
   }
 
@@ -636,7 +637,7 @@
 // bottom toolbar, except the top one as the grid is below a toolbar.
 - (void)updateGridInsets {
   CGFloat bottomToolbarInset = 0;
-  if (IsTabGroupIndicatorEnabled()) {
+  if (IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()) {
     BOOL shouldUseCompactLayout = self.traitCollection.verticalSizeClass ==
                                       UIUserInterfaceSizeClassRegular &&
                                   self.traitCollection.horizontalSizeClass ==
diff --git a/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn b/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
index c274da8..7b7cff5 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/toolbar/ui_bundled/BUILD.gn
@@ -94,6 +94,7 @@
     "//ios/chrome/browser/toolbar/ui_bundled/buttons",
     "//ios/chrome/browser/toolbar/ui_bundled/public",
     "//ios/chrome/browser/toolbar/ui_bundled/public:constants",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator",
     "//ios/chrome/browser/ui/popup_menu/public",
     "//ios/chrome/browser/url_loading/model",
diff --git a/ios/chrome/browser/toolbar/ui_bundled/adaptive_toolbar_mediator.mm b/ios/chrome/browser/toolbar/ui_bundled/adaptive_toolbar_mediator.mm
index 6d6b553..8d79c30 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/adaptive_toolbar_mediator.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/adaptive_toolbar_mediator.mm
@@ -29,6 +29,7 @@
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_group_state.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/toolbar_consumer.h"
 #import "ios/chrome/browser/url_loading/model/image_search_param_generator.h"
 #import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"
@@ -552,8 +553,9 @@
     return _webStateList->count();
   }
 
-  return IsTabGroupIndicatorEnabled() ? activeTabGroup->range().count()
-                                      : _webStateList->count();
+  return IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()
+             ? activeTabGroup->range().count()
+             : _webStateList->count();
 }
 
 // Returns the tab group state to display in the Tab Grid button.
@@ -562,8 +564,9 @@
   if (activeTabGroup == nullptr) {
     return ToolbarTabGroupState::kNormal;
   }
-  return IsTabGroupIndicatorEnabled() ? ToolbarTabGroupState::kTabGroup
-                                      : ToolbarTabGroupState::kNormal;
+  return IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()
+             ? ToolbarTabGroupState::kTabGroup
+             : ToolbarTabGroupState::kNormal;
 }
 
 @end
diff --git a/ios/chrome/browser/toolbar/ui_bundled/buttons/BUILD.gn b/ios/chrome/browser/toolbar/ui_bundled/buttons/BUILD.gn
index 2858d1f..af1c54d 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/buttons/BUILD.gn
+++ b/ios/chrome/browser/toolbar/ui_bundled/buttons/BUILD.gn
@@ -40,6 +40,7 @@
     "//ios/chrome/browser/toolbar/ui_bundled/buttons/resources",
     "//ios/chrome/browser/toolbar/ui_bundled/public",
     "//ios/chrome/browser/toolbar/ui_bundled/public:constants",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant",
     "//ios/chrome/browser/web/model",
     "//ios/chrome/common/ui/colors",
diff --git a/ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_grid_button.mm b/ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_grid_button.mm
index 1084f16..d3c59f7 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_grid_button.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_grid_button.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_group_state.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/public/toolbar_constants.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ui/base/l10n/l10n_util.h"
@@ -79,7 +80,7 @@
 
 - (void)setTabGroupState:(ToolbarTabGroupState)tabGroupState {
   CHECK(tabGroupState == ToolbarTabGroupState::kNormal ||
-        IsTabGroupIndicatorEnabled());
+        (IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()));
   if (_tabGroupState == tabGroupState) {
     return;
   }
diff --git a/ios/chrome/browser/toolbar/ui_bundled/secondary_toolbar_mediator.mm b/ios/chrome/browser/toolbar/ui_bundled/secondary_toolbar_mediator.mm
index 51ad9fe..cae9737b 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/secondary_toolbar_mediator.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/secondary_toolbar_mediator.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/buttons/toolbar_tab_group_state.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/secondary_toolbar_consumer.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/web/public/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state.h"
 
@@ -235,8 +236,9 @@
   if ([self activeWebStateTabGroup] == nullptr) {
     return ToolbarTabGroupState::kNormal;
   }
-  return IsTabGroupIndicatorEnabled() ? ToolbarTabGroupState::kTabGroup
-                                      : ToolbarTabGroupState::kNormal;
+  return IsTabGroupIndicatorEnabled() && HasTabGroupIndicatorButtonsUpdated()
+             ? ToolbarTabGroupState::kTabGroup
+             : ToolbarTabGroupState::kNormal;
 }
 
 // Updates the blue dot in the Tab Grid button depending on the messages and the
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/BUILD.gn b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/BUILD.gn
new file mode 100644
index 0000000..26756c1
--- /dev/null
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("features_utils") {
+  sources = [
+    "tab_group_indicator_features_utils.h",
+    "tab_group_indicator_features_utils.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/shared/public/features",
+  ]
+}
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/BUILD.gn b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/BUILD.gn
index 2d4b66d..edc5467 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/BUILD.gn
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/BUILD.gn
@@ -39,6 +39,7 @@
     "//ios/chrome/browser/tab_switcher/ui_bundled:tab_group_confirmation",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups",
     "//ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups:tab_group_creation",
+    "//ios/chrome/browser/toolbar/ui_bundled/tab_groups:features_utils",
     "//ios/chrome/browser/toolbar/ui_bundled/tab_groups/ui",
     "//ios/chrome/browser/url_loading/model",
     "//ios/third_party/material_components_ios",
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
index 8be4972..43fdb84 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator.mm
@@ -27,6 +27,7 @@
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/tab_group_sync_service_observer_bridge.h"
 #import "ios/chrome/browser/tab_switcher/ui_bundled/tab_group_action_type.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/coordinator/tab_group_indicator_mediator_delegate.h"
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
 #import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/ui/tab_group_indicator_consumer.h"
 #import "ios/chrome/browser/url_loading/model/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/model/url_loading_params.h"
@@ -133,7 +134,8 @@
   web::WebState* webState = status.new_active_web_state;
   if ((status.active_web_state_change() || groupUpdate) && webState) {
     const TabGroup* tabGroup = [self currentTabGroup];
-    if (tabGroup && IsTabGroupIndicatorEnabled()) {
+    if (tabGroup && IsTabGroupIndicatorEnabled() &&
+        HasTabGroupIndicatorVisible()) {
       [_consumer setTabGroupTitle:tabGroup->GetTitle()
                        groupColor:tabGroup->GetColor()];
       BOOL shared =
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h
new file mode 100644
index 0000000..40306c3
--- /dev/null
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h
@@ -0,0 +1,23 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_TOOLBAR_UI_BUNDLED_TAB_GROUPS_TAB_GROUP_INDICATOR_FEATURES_UTILS_H_
+#define IOS_CHROME_BROWSER_TOOLBAR_UI_BUNDLED_TAB_GROUPS_TAB_GROUP_INDICATOR_FEATURES_UTILS_H_
+
+// Feature parameters for the tab group indicator.
+extern const char kTabGroupIndicatorVisible[];
+extern const char kTabGroupIndicatorBelowOmnibox[];
+extern const char kTabGroupIndicatorButtonsUpdate[];
+
+// Whether the tab group indicator is visible.
+bool HasTabGroupIndicatorVisible();
+
+// Whether the tab group indicator is below the omnibox.
+bool HasTabGroupIndicatorBelowOmnibox();
+
+// Whether the grid and the group view buttons are updated when the tab group
+// indicator feature is enabled.
+bool HasTabGroupIndicatorButtonsUpdated();
+
+#endif  // IOS_CHROME_BROWSER_TOOLBAR_UI_BUNDLED_TAB_GROUPS_TAB_GROUP_INDICATOR_FEATURES_UTILS_H_
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.mm b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.mm
new file mode 100644
index 0000000..31754fec
--- /dev/null
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.mm
@@ -0,0 +1,30 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/toolbar/ui_bundled/tab_groups/tab_group_indicator_features_utils.h"
+
+#import "ios/chrome/browser/shared/public/features/features.h"
+
+const char kTabGroupIndicatorVisible[] = "tab-group-indicator-visible";
+const char kTabGroupIndicatorBelowOmnibox[] =
+    "tab-group-indicator-below-omnibox";
+const char kTabGroupIndicatorButtonsUpdate[] = "tab-group-indicator-buttons";
+
+bool HasTabGroupIndicatorVisible() {
+  CHECK(IsTabGroupIndicatorEnabled());
+  return GetFieldTrialParamByFeatureAsBool(kTabGroupIndicator,
+                                           kTabGroupIndicatorVisible, true);
+}
+
+bool HasTabGroupIndicatorBelowOmnibox() {
+  CHECK(IsTabGroupIndicatorEnabled());
+  return GetFieldTrialParamByFeatureAsBool(
+      kTabGroupIndicator, kTabGroupIndicatorBelowOmnibox, false);
+}
+
+bool HasTabGroupIndicatorButtonsUpdated() {
+  CHECK(IsTabGroupIndicatorEnabled());
+  return GetFieldTrialParamByFeatureAsBool(
+      kTabGroupIndicator, kTabGroupIndicatorButtonsUpdate, true);
+}
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index c134aae..0873740 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-73104c70ba90a53d47644a4b3162934297bc34ed
\ No newline at end of file
+aa8cf6acf5e19c2c34fa65e11fd641d66db69922
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
index c1a8b427..4f893ce 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-a6716428df82652f576d965b94656a5d019ffe89
\ No newline at end of file
+1aa84e3683d38fb700807bd2c980e95849476faf
\ No newline at end of file
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 e02262a..913b6e0 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 @@
-8f423a58d94ee368a3481e338e93eb8285848842
\ No newline at end of file
+e44ecffdc76a63a4a0c8fc0d4e417eec046a42c8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
index 08dc4689..88504b3 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-80ff5ecd6daf11673bd0c1b3e2632de40f0ec2bf
\ No newline at end of file
+3bc60f53c6e08de9ef5940d0212409d8f3dbc2d1
\ 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 40f9f46e..32b2d41 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 @@
-224ca816d9cc5fde3bf6ab5ea7c6952f148928d9
\ No newline at end of file
+6b6905682ef4fba4e49e272e4f7ef5efd5cc49ac
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
index 94aa3f8..bcfe9598 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-62e557732702e12b3092d1a1e07aaa941b2a9c8b
\ No newline at end of file
+84c2a656fa28331d33c8ef8aa000c53f7d6b5d59
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index 8fbce7f..e6c5762 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-ec8c14c89b6f0a9c9450555965308fa162fee791
\ No newline at end of file
+e582e06e185785e2591a9cada0c796b9c789bb59
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
index a2278ba..dc0c453 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-af51aec6ca953ec4d839ed2a4079bb332f32654c
\ No newline at end of file
+b6e27b3269682a5be4385a16cc0201abbc5bdc11
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index e86b1e4c..5c460da 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-4eba3ec59b547db51d6c4b35afa2a2af22605c6c
\ No newline at end of file
+4e95ecff31ac344203da9cbb4e4d88d608b2220b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 4741a0a..20885c7 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-3a5469c24ed1935559e59de7c34922a8ec49069b
\ No newline at end of file
+d20ffaf39593f471e53a04bc5a0d28b546162a4a
\ 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 a4da5e7..2909cf44 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 @@
-81ed715c3dc7b079362f03d3c14f59671141dc72
\ No newline at end of file
+c7d948e9266f21e434a2189949b65884fb8584d1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
index c8ff21d..218ae73d 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-2de5c7d3ca4505d88fedcde7d5d57123157b48ae
\ No newline at end of file
+d6a9b95d85b361406e52c6291a523beca92e6806
\ 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 017dde3..250a064 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 @@
-73a1588084753e7ea0d8855df78d6a65c3d076c1
\ No newline at end of file
+0468c1689cc4364cffd81a1fec6b952a6e2a47d5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 936904f..82ea1f7be 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-408ceefb2703ad374cbff8e957094e0ff893fac4
\ No newline at end of file
+300ec4efb8160babcc21d751b07e7c8fc7b8f1a4
\ 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 97c3b55..fc79fd7a 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 @@
-0f7177b4a7dec3e9af217e18ed438045e7678685
\ No newline at end of file
+a0c7c6c090ba42a04f2a84f7189fdd59fe757e9c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
index 166b9228..812252f7 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-63fa11c3a0268d5021a8d129bf6bf8ba930caeb2
\ No newline at end of file
+c65c8208c744d696f1b0b95abb1fc96516a46222
\ 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 94b0f8c..8add769 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 @@
-b64cd70f977c6950968a345198935e8788ad1e83
\ No newline at end of file
+daf0177267dee5c0067a36074b5e526f80f0743c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 2cc752e2..f889340 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-ea08e56545feecff314af1981231465bdadaa873
\ No newline at end of file
+415991b5d338741e0b1e74da3e6b5feb86b196f0
\ 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 286d5a13..b79751b4 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 @@
-0d5678df8fc5193e8f61dcac53e5b46f0ecd3e9e
\ No newline at end of file
+066d0fd8ef1ef69187cb127b1e8651ae2cf06d7c
\ 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 517e022..c958c316 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 @@
-fcca7f22412edec47113fa9e236cf85b4c45e810
\ No newline at end of file
+0085addececc99b32262e61a901743cb2b06b252
\ 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 1bcf0f8..5642218 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 @@
-aeaf3eab9d73dcef23e35c5936b31d7e9cbf60af
\ No newline at end of file
+94db464706d519ea64877e8036fcca2031c9dd61
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
index 73d86fa..6004dad 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-1e363269e0759522b01deabeb4c83919c57c5c21
\ No newline at end of file
+caf40f2dce2278a316241d65f5d309a573dc1a00
\ 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 74cb1f21..6d711f4 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 @@
-7d26aa890e8e934b3eb72d06f7132c21dec8244d
\ No newline at end of file
+cf24e646e70804992455a7ff494d3dac15115c6f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 442eaef..2ff9573 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-e554fa671d311934867bdfefabecb13abd0daa7a
\ No newline at end of file
+261c36fd4374059728ee92297231d24880e85bbd
\ 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 66b2514..a021a92 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 @@
-0586da8fe433f8bda89ac1d58c57494766716f0d
\ No newline at end of file
+08be24b0f90c1803d73d7f4288911caeb140778b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
index 81b0d64a..21bdf424 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-46a062e44db68db74eea7e112c724c710955f00c
\ No newline at end of file
+5c2fb28a9bf778d7cabfe2180d1ab10aacf53a78
\ 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 75a184b..b22037b4 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 @@
-3eb892d2bab10efd4da0f0922e04fd800ac85bf7
\ No newline at end of file
+05331d180128738fc8ee1744dbbefc31997819ff
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
index ded25be..8f47b803 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-7f51e12c6efb09482300e8c5241ff6c2ddbe9d01
\ No newline at end of file
+c2092e50932a6404e5fdc3b46803ff574f2aa241
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index 7ef8f196..728f205 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 7ef8f19635a1aab0f89f14854cc7732534811bc3
+Subproject commit 728f2050ecc1547009c1ec095855a100e6554117
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 5d6a129..ee5c16f 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -5817,7 +5817,7 @@
   result.public_key_hashes.push_back(HashValue(intermediate_hash));
   result.public_key_hashes.push_back(HashValue(root_hash));
 
-  const base::HistogramBase::Sample kGTSRootR4HistogramID = 486;
+  const base::HistogramBase::Sample32 kGTSRootR4HistogramID = 486;
 
   auto verify_proc = base::MakeRefCounted<MockCertVerifyProc>(result);
 
@@ -5864,7 +5864,7 @@
   result.public_key_hashes.push_back(HashValue(gts_root_r3_hash));
   result.public_key_hashes.push_back(HashValue(gts_root_r4_hash));
 
-  const base::HistogramBase::Sample kGTSRootR3HistogramID = 485;
+  const base::HistogramBase::Sample32 kGTSRootR3HistogramID = 485;
 
   auto verify_proc = base::MakeRefCounted<MockCertVerifyProc>(result);
 
@@ -5916,7 +5916,7 @@
       /*ocsp_response=*/std::string(),
       /*sct_list=*/std::string(), flags, &verify_result, NetLogWithSource());
   EXPECT_EQ(OK, error);
-  const base::HistogramBase::Sample kUnknownRootHistogramID = 0;
+  const base::HistogramBase::Sample32 kUnknownRootHistogramID = 0;
   histograms.ExpectUniqueSample(kTrustAnchorVerifyHistogram,
                                 kUnknownRootHistogramID, 1);
   histograms.ExpectUniqueSample(kTrustAnchorVerifyOutOfDateHistogram, true, 1);
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index 1dbbf50..464d346 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -38,8 +38,9 @@
     const std::string& line,
     const std::vector<std::unique_ptr<CanonicalCookie>>& cookies) {
   std::vector<CanonicalCookie> list;
-  for (const auto& cookie : cookies)
+  for (const auto& cookie : cookies) {
     list.push_back(*cookie);
+  }
   EXPECT_EQ(line, CanonicalCookie::BuildCookieLine(list));
 }
 
@@ -1734,8 +1735,9 @@
     std::vector<CookieAccessSemantics> access_semantics = {
         CookieAccessSemantics::UNKNOWN, CookieAccessSemantics::LEGACY,
         CookieAccessSemantics::NONLEGACY};
-    if (test.access_semantics.has_value())
+    if (test.access_semantics.has_value()) {
       access_semantics = {*test.access_semantics};
+    }
 
     for (const auto& cookie : cookies) {
       for (const auto semantics : access_semantics) {
@@ -6022,8 +6024,8 @@
   base::HistogramTester histograms;
   const char kFromStorageWithValidLengthHistogram[] =
       "Cookie.FromStorageWithValidLength";
-  const base::HistogramBase::Sample kInValid = 0;
-  const base::HistogramBase::Sample kValid = 1;
+  const base::HistogramBase::Sample32 kInValid = 0;
+  const base::HistogramBase::Sample32 kValid = 1;
 
   base::Time two_hours_ago = base::Time::Now() - base::Hours(2);
   base::Time one_hour_ago = base::Time::Now() - base::Hours(1);
diff --git a/net/disk_cache/simple/simple_index.cc b/net/disk_cache/simple/simple_index.cc
index 7c415cc..dc6abd4 100644
--- a/net/disk_cache/simple/simple_index.cc
+++ b/net/disk_cache/simple/simple_index.cc
@@ -612,10 +612,10 @@
                    entries_set_.size(), 0, 100000, 50);
   SIMPLE_CACHE_UMA(
       MEMORY_KB, "CacheSizeOnInit", cache_type_,
-      static_cast<base::HistogramBase::Sample>(cache_size_ / kBytesInKb));
+      static_cast<base::HistogramBase::Sample32>(cache_size_ / kBytesInKb));
   SIMPLE_CACHE_UMA(
       MEMORY_KB, "MaxCacheSizeOnInit", cache_type_,
-      static_cast<base::HistogramBase::Sample>(max_size_ / kBytesInKb));
+      static_cast<base::HistogramBase::Sample32>(max_size_ / kBytesInKb));
 
   // Run all callbacks waiting for the index to come up.
   for (auto& callback : to_run_when_initialized_) {
diff --git a/net/dns/resolve_context.cc b/net/dns/resolve_context.cc
index c33c25f..5d4484e 100644
--- a/net/dns/resolve_context.cc
+++ b/net/dns/resolve_context.cc
@@ -98,7 +98,7 @@
   RttBuckets() : base::BucketRanges(kRttBucketCount + 1) {
     base::Histogram::InitializeBucketRanges(
         1,
-        base::checked_cast<base::HistogramBase::Sample>(
+        base::checked_cast<base::HistogramBase::Sample32>(
             kRttMax.InMilliseconds()),
         this);
   }
@@ -114,7 +114,7 @@
   std::unique_ptr<base::SampleVector> histogram =
       std::make_unique<base::SampleVector>(GetRttBuckets());
   // Seed histogram with 2 samples at |rtt_estimate|.
-  histogram->Accumulate(base::checked_cast<base::HistogramBase::Sample>(
+  histogram->Accumulate(base::checked_cast<base::HistogramBase::Sample32>(
                             rtt_estimate.InMilliseconds()),
                         kNumSeeds);
   return histogram;
@@ -295,7 +295,7 @@
 
   // Histogram-based method.
   stats->rtt_histogram->Accumulate(
-      base::saturated_cast<base::HistogramBase::Sample>(rtt.InMilliseconds()),
+      base::saturated_cast<base::HistogramBase::Sample32>(rtt.InMilliseconds()),
       1);
 }
 
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index bf1ccfc..1bab3b0 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -2364,7 +2364,7 @@
       // decrypted - kNoCrypto. Functionality for an already-migrated store (v24
       // and above) with both plaintext and encrypted values is tested in the
       // `OverridePlaintextValue` test below.
-      const base::Histogram::Sample expected_bucket =
+      const base::Histogram::Sample32 expected_bucket =
           drop_dup_values && place_unencrypted_too
               ? /*CookieLoadProblem::kValuesExistInBothEncryptedAndPlaintext*/ 8
               : /*CookieLoadProblem::kNoCrypto*/ 7;
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 1b59d7e2..a8ea23b 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -1141,10 +1141,10 @@
   if (stats.max_sequence_reordering == 0) {
     return;
   }
-  const base::HistogramBase::Sample kMaxReordering = 100;
-  base::HistogramBase::Sample reordering = kMaxReordering;
+  const base::HistogramBase::Sample32 kMaxReordering = 100;
+  base::HistogramBase::Sample32 reordering = kMaxReordering;
   if (stats.min_rtt_us > 0) {
-    reordering = static_cast<base::HistogramBase::Sample>(
+    reordering = static_cast<base::HistogramBase::Sample32>(
         100 * stats.max_time_reordering_us / stats.min_rtt_us);
   }
   UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
@@ -1153,9 +1153,9 @@
     UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
                                 reordering, 1, kMaxReordering, 50);
   }
-  UMA_HISTOGRAM_COUNTS_1M(
-      "Net.QuicSession.MaxReordering",
-      static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
+  UMA_HISTOGRAM_COUNTS_1M("Net.QuicSession.MaxReordering",
+                          static_cast<base::HistogramBase::Sample32>(
+                              stats.max_sequence_reordering));
 }
 
 void QuicChromiumClientSession::Initialize() {
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 951f283..df66fc74 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -294,7 +294,7 @@
       // delivery.
       UMA_HISTOGRAM_COUNTS_1M(
           "Net.QuicSession.PacketGapReceived",
-          static_cast<base::HistogramBase::Sample>(delta - 1));
+          static_cast<base::HistogramBase::Sample32>(delta - 1));
     }
     largest_received_packet_number_ = header.packet_number;
   }
@@ -306,17 +306,18 @@
   if (last_received_packet_number_.IsInitialized() &&
       header.packet_number < last_received_packet_number_) {
     ++num_out_of_order_received_packets_;
-    if (previous_received_packet_size_ < last_received_packet_size_)
+    if (previous_received_packet_size_ < last_received_packet_size_) {
       ++num_out_of_order_large_received_packets_;
+    }
     UMA_HISTOGRAM_COUNTS_1M(
         "Net.QuicSession.OutOfOrderGapReceived",
-        static_cast<base::HistogramBase::Sample>(last_received_packet_number_ -
-                                                 header.packet_number));
+        static_cast<base::HistogramBase::Sample32>(
+            last_received_packet_number_ - header.packet_number));
   } else if (no_packet_received_after_ping_) {
     if (last_received_packet_number_.IsInitialized()) {
       UMA_HISTOGRAM_COUNTS_1M(
           "Net.QuicSession.PacketGapReceivedNearPing",
-          static_cast<base::HistogramBase::Sample>(
+          static_cast<base::HistogramBase::Sample32>(
               header.packet_number - last_received_packet_number_));
     }
     no_packet_received_after_ping_ = false;
@@ -518,8 +519,9 @@
 }
 
 float QuicConnectionLogger::ReceivedPacketLossRate() const {
-  if (!largest_received_packet_number_.IsInitialized())
+  if (!largest_received_packet_number_.IsInitialized()) {
     return 0.0f;
+  }
   float num_packets =
       largest_received_packet_number_ - first_received_packet_number_ + 1;
   float num_missing = num_packets - num_packets_received_;
@@ -528,8 +530,9 @@
 
 void QuicConnectionLogger::OnRttChanged(quic::QuicTime::Delta rtt) const {
   // Notify socket performance watcher of the updated RTT value.
-  if (!socket_performance_watcher_)
+  if (!socket_performance_watcher_) {
     return;
+  }
 
   int64_t microseconds = rtt.ToMicroseconds();
   if (microseconds != 0 &&
@@ -578,7 +581,7 @@
   base::HistogramBase* histogram = base::Histogram::FactoryGet(
       prefix + connection_description_, 1, 1000, 75,
       base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram->Add(static_cast<base::HistogramBase::Sample>(
+  histogram->Add(static_cast<base::HistogramBase::Sample32>(
       ReceivedPacketLossRate() * 1000));
 }
 
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc
index 6384274..0ff8fe3 100644
--- a/net/url_request/url_request_http_job_unittest.cc
+++ b/net/url_request/url_request_http_job_unittest.cc
@@ -914,7 +914,7 @@
       HashValue(intermediate_hash));
   ssl_socket_data.ssl_info.public_key_hashes.push_back(HashValue(root_hash));
 
-  const base::HistogramBase::Sample kGTSRootR4HistogramID = 486;
+  const base::HistogramBase::Sample32 kGTSRootR4HistogramID = 486;
 
   socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
 
@@ -1001,7 +1001,7 @@
   ssl_socket_data.ssl_info.public_key_hashes.push_back(
       HashValue(gts_root_r4_hash));
 
-  const base::HistogramBase::Sample kGTSRootR3HistogramID = 485;
+  const base::HistogramBase::Sample32 kGTSRootR3HistogramID = 485;
 
   socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data);
 
diff --git a/pdf/accessibility.cc b/pdf/accessibility.cc
index 54c8e876..4a0b4d9 100644
--- a/pdf/accessibility.cc
+++ b/pdf/accessibility.cc
@@ -54,6 +54,8 @@
     chars[i].unicode_character = page->GetCharUnicode(i);
   }
 
+  // TODO(crbug.com/40707542): Move the entire logic present in the following
+  // while loop to `PDFiumPage` class.
   uint32_t char_index = 0;
   while (char_index < char_count) {
     std::optional<AccessibilityTextRunInfo> text_run_info_result =
@@ -106,6 +108,7 @@
     char_index += text_run_info.len;
   }
 
+  page->PopulateTextRunTypeAndImageAltText(text_runs);
   page_info.text_run_count = text_runs.size();
   page_objects.links = page->GetLinkInfo(text_runs);
   page_objects.images = page->GetImageInfo(page_info.text_run_count);
diff --git a/pdf/accessibility_structs.cc b/pdf/accessibility_structs.cc
index fbc5edf..3f552878 100644
--- a/pdf/accessibility_structs.cc
+++ b/pdf/accessibility_structs.cc
@@ -7,7 +7,7 @@
 namespace chrome_pdf {
 
 bool AccessibilityDocInfo::operator==(const AccessibilityDocInfo& other) const {
-  return page_count == other.page_count &&
+  return page_count == other.page_count && is_tagged == other.is_tagged &&
          text_accessible == other.text_accessible &&
          text_copyable == other.text_copyable;
 }
@@ -45,10 +45,12 @@
 
 AccessibilityTextRunInfo::AccessibilityTextRunInfo(
     uint32_t len,
+    const std::string& tag_type,
     const gfx::RectF& bounds,
     AccessibilityTextDirection direction,
     const AccessibilityTextStyleInfo& style)
     : AccessibilityTextRunInfo(len,
+                               tag_type,
                                bounds,
                                direction,
                                style,
@@ -56,11 +58,13 @@
 
 AccessibilityTextRunInfo::AccessibilityTextRunInfo(
     uint32_t len,
+    const std::string& tag_type,
     const gfx::RectF& bounds,
     AccessibilityTextDirection direction,
     const AccessibilityTextStyleInfo& style,
     bool is_searchified)
     : len(len),
+      tag_type(tag_type),
       bounds(bounds),
       direction(direction),
       style(style),
diff --git a/pdf/accessibility_structs.h b/pdf/accessibility_structs.h
index a799775..88c48b7 100644
--- a/pdf/accessibility_structs.h
+++ b/pdf/accessibility_structs.h
@@ -22,6 +22,7 @@
   bool operator!=(const AccessibilityDocInfo& other) const;
 
   uint32_t page_count = 0;
+  bool is_tagged = false;
   bool text_accessible = false;
   bool text_copyable = false;
 };
@@ -85,10 +86,12 @@
 struct AccessibilityTextRunInfo {
   AccessibilityTextRunInfo();
   AccessibilityTextRunInfo(uint32_t len,
+                           const std::string& tag_type,
                            const gfx::RectF& bounds,
                            AccessibilityTextDirection direction,
                            const AccessibilityTextStyleInfo& style);
   AccessibilityTextRunInfo(uint32_t len,
+                           const std::string& tag_type,
                            const gfx::RectF& bounds,
                            AccessibilityTextDirection direction,
                            const AccessibilityTextStyleInfo& style,
@@ -97,6 +100,9 @@
   ~AccessibilityTextRunInfo();
 
   uint32_t len = 0;
+  // One of various types defined in a PDF tag, such as "Span", "P", "H1", "LI",
+  // etc.
+  std::string tag_type;
   gfx::RectF bounds;
   AccessibilityTextDirection direction = AccessibilityTextDirection::kNone;
   AccessibilityTextStyleInfo style;
diff --git a/pdf/pdf_features.cc b/pdf/pdf_features.cc
index ad41cde..387174b3e 100644
--- a/pdf/pdf_features.cc
+++ b/pdf/pdf_features.cc
@@ -47,6 +47,12 @@
              "PdfSearchifySave",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables accessibility tags in PDFs to be parsed and integrated into the
+// accessibility tree by Chrome's PDF Viewer. Accessibility tags provide
+// structure and semantics to the text found in a PDF, e.g. they could mark a
+// specific piece of text as a heading, or a block of text as a paragraph.
+BASE_FEATURE(kPdfTags, "PdfTags", base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kPdfUseShowSaveFilePicker,
              "PdfUseShowSaveFilePicker",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/pdf/pdf_features.h b/pdf/pdf_features.h
index 86b9146..c0c068ec 100644
--- a/pdf/pdf_features.h
+++ b/pdf/pdf_features.h
@@ -24,6 +24,7 @@
 BASE_DECLARE_FEATURE(kPdfPortfolio);
 BASE_DECLARE_FEATURE(kPdfSearchify);
 BASE_DECLARE_FEATURE(kPdfSearchifySave);
+BASE_DECLARE_FEATURE(kPdfTags);
 BASE_DECLARE_FEATURE(kPdfUseShowSaveFilePicker);
 BASE_DECLARE_FEATURE(kPdfUseSkiaRenderer);
 BASE_DECLARE_FEATURE(kPdfXfaSupport);
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index b5628eb8..5122f07 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -2777,6 +2777,9 @@
 AccessibilityDocInfo PdfViewWebPlugin::GetAccessibilityDocInfo() const {
   AccessibilityDocInfo doc_info;
   doc_info.page_count = engine_->GetNumberOfPages();
+  if (base::FeatureList::IsEnabled(chrome_pdf::features::kPdfTags)) {
+    doc_info.is_tagged = engine_->IsTagged();
+  }
   doc_info.text_accessible =
       engine_->HasPermission(DocumentPermission::kCopyAccessible);
   doc_info.text_copyable = engine_->HasPermission(DocumentPermission::kCopy);
diff --git a/pdf/pdfium/accessibility_unittest.cc b/pdf/pdfium/accessibility_unittest.cc
index 6ea8b8f..37d6ac20 100644
--- a/pdf/pdfium/accessibility_unittest.cc
+++ b/pdf/pdfium/accessibility_unittest.cc
@@ -4,10 +4,14 @@
 
 #include "pdf/accessibility.h"
 
+#include <array>
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/types/zip.h"
 #include "pdf/accessibility_structs.h"
+#include "pdf/pdf_features.h"
 #include "pdf/pdfium/pdfium_engine.h"
 #include "pdf/pdfium/pdfium_test_base.h"
 #include "pdf/test/test_client.h"
@@ -123,6 +127,55 @@
   });
 }
 
+TEST_P(AccessibilityTest, GetAccessibilityPageWithTags) {
+  base::test::ScopedFeatureList pdf_tags;
+  pdf_tags.InitAndEnableFeature(features::kPdfTags);
+
+  struct TestTextRun {
+    uint32_t len;
+    std::string tag_type;
+  };
+  static constexpr std::array<TestTextRun, 5> kExpectedTextRuns = {
+      TestTextRun{/*"Article\r\n"*/ 9, "Art"},
+      TestTextRun{/*"BlockQuote\r\n"*/ 12, "BlockQuote"},
+      TestTextRun{/*"Paragraph\r\n"*/ 11, "P"},
+      TestTextRun{/*"Heading1\r\n"*/ 10, "H1"},
+      TestTextRun{/*"Heading2"*/ 8, "H2"},
+  };
+
+  static constexpr char kExpectedChars[] =
+      "Article\r\nBlockQuote\r\nParagraph\r\nHeading1\r\nHeading2";
+
+  TestClient client;
+  std::unique_ptr<PDFiumEngine> engine =
+      InitializeEngine(&client, FILE_PATH_LITERAL("tags.pdf"));
+  ASSERT_TRUE(engine);
+
+  ASSERT_EQ(1, engine->GetNumberOfPages());
+  AccessibilityPageInfo page_info;
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  std::vector<AccessibilityCharInfo> chars;
+  AccessibilityPageObjects page_objects;
+  GetAccessibilityInfo(engine.get(), 0, page_info, text_runs, chars,
+                       page_objects);
+  EXPECT_EQ(0u, page_info.page_index);
+  EXPECT_EQ(gfx::Rect(5, 3, 816, 1056), page_info.bounds);
+  EXPECT_EQ(text_runs.size(), page_info.text_run_count);
+  EXPECT_EQ(chars.size(), page_info.char_count);
+
+  ASSERT_EQ(kExpectedTextRuns.size(), text_runs.size());
+  for (const auto [expected, actual] :
+       base::zip(kExpectedTextRuns, text_runs)) {
+    EXPECT_EQ(expected.len, actual.len);
+    EXPECT_EQ(expected.tag_type, actual.tag_type);
+  }
+
+  ASSERT_EQ(std::size(kExpectedChars) - 1, chars.size());
+  for (const auto [expected, actual] : base::zip(kExpectedChars, chars)) {
+    EXPECT_EQ(static_cast<uint32_t>(expected), actual.unicode_character);
+  }
+}
+
 TEST_P(AccessibilityTest, GetAccessibilityImageInfo) {
   static const auto kExpectedImageInfo = std::to_array<AccessibilityImageInfo>({
       {"Image 1", 0, {380, 78, 67, 68}, {}},
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 80ea005..5fc3b57 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -2233,6 +2233,10 @@
   ClearTextSelection();
 }
 
+bool PDFiumEngine::IsTagged() const {
+  return FPDFCatalog_IsTagged(doc());
+}
+
 void PDFiumEngine::SetDocumentLayout(DocumentLayout::PageSpread page_spread) {
   SaveSelection();
   desired_layout_options_.set_page_spread(page_spread);
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 5452ff7..3e7f09bc 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -219,6 +219,7 @@
   void RotateCounterclockwise();
   bool IsReadOnly() const;
   void SetReadOnly(bool read_only);
+  bool IsTagged() const;
   void SetDocumentLayout(DocumentLayout::PageSpread page_spread);
   void DisplayAnnotations(bool display);
 
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 72150ac..4f7476f 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -874,7 +874,6 @@
     return image_info;
 
   CalculateImages();
-
   image_info.reserve(images_.size());
   for (const Image& image : images_) {
     AccessibilityImageInfo cur_info;
@@ -996,6 +995,49 @@
   return text_field_info;
 }
 
+void PDFiumPage::PopulateTextRunTypeAndImageAltText(
+    std::vector<AccessibilityTextRunInfo>& text_runs) {
+  CalculateImages();
+  ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(GetPage()));
+  if (!struct_tree) {
+    return;
+  }
+
+  // TODO(crbug.com/40707542): Consolidate `Accessibility"TextRunInfo` building
+  // logic into this class and remove the following block.
+  MarkedContentIdToTextRunInfoMap marked_content_id_text_run_info_map;
+  if (base::FeatureList::IsEnabled(chrome_pdf::features::kPdfTags)) {
+    FPDF_TEXTPAGE text_page = GetTextPage();
+    uint32_t char_index = 0;
+    for (auto& text_run : text_runs) {
+      FPDF_PAGEOBJECT text_object =
+          FPDFText_GetTextObject(text_page, char_index);
+      int marked_content_id = FPDFPageObj_GetMarkedContentID(text_object);
+      if (marked_content_id == -1) {
+        continue;
+      }
+      auto [iter, _] = marked_content_id_text_run_info_map.emplace(
+          marked_content_id, std::vector<raw_ptr<AccessibilityTextRunInfo>>());
+      iter->second.push_back(&text_run);
+      char_index += text_run.len;
+    }
+  }
+
+  if (marked_content_id_text_run_info_map.empty() &&
+      marked_content_id_image_map_.empty()) {
+    return;
+  }
+
+  std::set<FPDF_STRUCTELEMENT> visited_elements;
+  int tree_children_count = FPDF_StructTree_CountChildren(struct_tree.get());
+  for (int i = 0; i < tree_children_count; ++i) {
+    FPDF_STRUCTELEMENT current_element =
+        FPDF_StructTree_GetChildAtIndex(struct_tree.get(), i);
+    PopulateTextRunTypeAndImageAltTextForStructElement(
+        current_element, visited_elements, marked_content_id_text_run_info_map);
+  }
+}
+
 PDFiumPage::Area PDFiumPage::GetLinkTargetAtIndex(int link_index,
                                                   LinkTarget* target) {
   if (!available_ || link_index < 0)
@@ -1385,8 +1427,6 @@
   calculated_images_ = true;
   FPDF_PAGE page = GetPage();
   int page_object_count = FPDFPage_CountObjects(page);
-  MarkedContentIdToImageMap marked_content_id_image_map;
-  bool is_tagged = FPDFCatalog_IsTagged(engine_->doc());
   for (int i = 0; i < page_object_count; ++i) {
     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
     if (FPDFPageObj_GetType(page_object) != FPDF_PAGEOBJ_IMAGE)
@@ -1403,7 +1443,7 @@
     image.bounding_rect = PageToScreen(gfx::Point(), 1.0, left, top, right,
                                        bottom, PageOrientation::kOriginal);
 
-    if (is_tagged) {
+    if (engine_->IsTagged()) {
       // Collect all marked content IDs for image objects so that they can
       // later be used to retrieve alt text from struct tree for the page.
       FPDF_IMAGEOBJ_METADATA image_metadata;
@@ -1412,64 +1452,65 @@
         if (marked_content_id >= 0) {
           // If `marked_content_id` is already present, ignore the one being
           // inserted.
-          marked_content_id_image_map.insert(
+          marked_content_id_image_map_.insert(
               {marked_content_id, images_.size()});
         }
       }
     }
     images_.push_back(image);
   }
-
-  if (!marked_content_id_image_map.empty())
-    PopulateImageAltText(marked_content_id_image_map);
 }
 
-void PDFiumPage::PopulateImageAltText(
-    const MarkedContentIdToImageMap& marked_content_id_image_map) {
-  ScopedFPDFStructTree struct_tree(FPDF_StructTree_GetForPage(GetPage()));
-  if (!struct_tree)
-    return;
-
-  std::set<FPDF_STRUCTELEMENT> visited_elements;
-  int tree_children_count = FPDF_StructTree_CountChildren(struct_tree.get());
-  for (int i = 0; i < tree_children_count; ++i) {
-    FPDF_STRUCTELEMENT current_element =
-        FPDF_StructTree_GetChildAtIndex(struct_tree.get(), i);
-    PopulateImageAltTextForStructElement(marked_content_id_image_map,
-                                         current_element, &visited_elements);
-  }
-}
-
-void PDFiumPage::PopulateImageAltTextForStructElement(
-    const MarkedContentIdToImageMap& marked_content_id_image_map,
+void PDFiumPage::PopulateTextRunTypeAndImageAltTextForStructElement(
     FPDF_STRUCTELEMENT current_element,
-    std::set<FPDF_STRUCTELEMENT>* visited_elements) {
-  if (!current_element)
+    std::set<FPDF_STRUCTELEMENT>& visited_elements,
+    MarkedContentIdToTextRunInfoMap& marked_content_id_text_run_info_map) {
+  if (!current_element) {
     return;
+  }
 
-  bool inserted = visited_elements->insert(current_element).second;
-  if (!inserted)
+  bool inserted = visited_elements.insert(current_element).second;
+  if (!inserted) {
     return;
+  }
 
-  int marked_content_id =
-      FPDF_StructElement_GetMarkedContentID(current_element);
+  int marked_content_id = -1;
+  if (FPDF_StructElement_GetMarkedContentIdCount(current_element)) {
+    marked_content_id =
+        FPDF_StructElement_GetMarkedContentIdAtIndex(current_element, 0);
+  }
   if (marked_content_id >= 0) {
-    auto it = marked_content_id_image_map.find(marked_content_id);
-    if (it != marked_content_id_image_map.end() &&
-        images_[it->second].alt_text.empty()) {
-      images_[it->second].alt_text =
+    if (base::FeatureList::IsEnabled(chrome_pdf::features::kPdfTags)) {
+      auto text_runs_iter =
+          marked_content_id_text_run_info_map.find(marked_content_id);
+      if (text_runs_iter != marked_content_id_text_run_info_map.end()) {
+        std::vector<raw_ptr<AccessibilityTextRunInfo>>& text_runs =
+            text_runs_iter->second;
+        for (raw_ptr<AccessibilityTextRunInfo>& text_run : text_runs) {
+          text_run->tag_type = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+              base::BindRepeating(&FPDF_StructElement_GetType, current_element),
+              /*check_expected_size=*/true));
+        }
+      }
+    }
+
+    auto image_iter = marked_content_id_image_map_.find(marked_content_id);
+    if (image_iter != marked_content_id_image_map_.end() &&
+        images_[image_iter->second].alt_text.empty()) {
+      images_[image_iter->second].alt_text =
           base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
               base::BindRepeating(&FPDF_StructElement_GetAltText,
                                   current_element),
               /*check_expected_size=*/true));
     }
   }
+
   int children_count = FPDF_StructElement_CountChildren(current_element);
   for (int i = 0; i < children_count; ++i) {
     FPDF_STRUCTELEMENT child =
         FPDF_StructElement_GetChildAtIndex(current_element, i);
-    PopulateImageAltTextForStructElement(marked_content_id_image_map, child,
-                                         visited_elements);
+    PopulateTextRunTypeAndImageAltTextForStructElement(
+        child, visited_elements, marked_content_id_text_run_info_map);
   }
 }
 
diff --git a/pdf/pdfium/pdfium_page.h b/pdf/pdfium/pdfium_page.h
index ed71201..b3bb118 100644
--- a/pdf/pdfium/pdfium_page.h
+++ b/pdf/pdfium/pdfium_page.h
@@ -143,6 +143,13 @@
   std::vector<AccessibilityTextFieldInfo> GetTextFieldInfo(
       uint32_t text_run_count);
 
+  // Traverses the entire struct tree of the page recursively and extracts the
+  // text run type or the alt text from struct tree elements corresponding to
+  // the marked content IDs associated with `text_runs` or present in
+  // `marked_content_id_image_map_` respectively.
+  void PopulateTextRunTypeAndImageAltText(
+      std::vector<AccessibilityTextRunInfo>& text_runs);
+
   enum Area {
     NONSELECTABLE_AREA,
     TEXT_AREA,       // Area contains regular, selectable text not
@@ -274,7 +281,7 @@
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageForOcrTest, HighResolutionImage);
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageForOcrTest, RotatedPage);
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageForOcrTest, NonImage);
-  FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageTest, CalculateImages);
+  FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageTest, PopulateImageAltText);
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageImageTest, ImageAltText);
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageLinkTest, AnnotLinkGeneration);
   FRIEND_TEST_ALL_PREFIXES(PDFiumPageLinkTest, GetLinkTarget);
@@ -429,23 +436,27 @@
   // broken for page objects such as links and images.
   void CalculatePageObjectTextRunBreaks();
 
+  // Key    :  Marked content id for the text element as specified in the struct
+  //           tree.
+  // Value:    A list of pointers to the associated text runs.
+  using MarkedContentIdToTextRunInfoMap =
+      std::map<int, std::vector<raw_ptr<AccessibilityTextRunInfo>>>;
+
   // Key    :  Marked content id for the image element as specified in the
-  //           struct tree.
-  // Value  :  Index of image in the `images_` vector.
+  // struct tree.
+  // Value  :  Index of the image in the `images_` vector.
   using MarkedContentIdToImageMap = std::map<int, size_t>;
-  // Traverses the entire struct tree of the page recursively and extracts the
-  // alt text from struct tree elements corresponding to the marked content IDs
-  // present in `marked_content_id_image_map`.
-  void PopulateImageAltText(
-      const MarkedContentIdToImageMap& marked_content_id_image_map);
+
   // Traverses a struct element and its sub-tree recursively and extracts the
-  // alt text from struct elements corresponding to the marked content IDs
-  // present in `marked_content_id_image_map`. Uses `visited_elements` to guard
-  // against malformed struct trees.
-  void PopulateImageAltTextForStructElement(
-      const MarkedContentIdToImageMap& marked_content_id_image_map,
+  // text run type or the alt text from struct elements corresponding to the
+  // marked content IDs present in `marked_content_id_text_run_info_map` or
+  // `marked_content_id_image_map_` respectively. Uses `visited_elements` to
+  // guard against malformed struct trees.
+  void PopulateTextRunTypeAndImageAltTextForStructElement(
       FPDF_STRUCTELEMENT current_element,
-      std::set<FPDF_STRUCTELEMENT>* visited_elements);
+      std::set<FPDF_STRUCTELEMENT>& visited_elements,
+      MarkedContentIdToTextRunInfoMap& marked_content_id_text_run_info_map);
+
   bool PopulateFormFieldProperties(FPDF_ANNOTATION annot,
                                    FormField* form_field);
 
@@ -470,6 +481,7 @@
   bool calculated_links_ = false;
   std::vector<Link> links_;
   bool calculated_images_ = false;
+  MarkedContentIdToImageMap marked_content_id_image_map_;
   std::vector<Image> images_;
   bool calculated_annotations_ = false;
   std::vector<Highlight> highlights_;
diff --git a/pdf/pdfium/pdfium_page_unittest.cc b/pdf/pdfium/pdfium_page_unittest.cc
index 618127d..6a0ba06 100644
--- a/pdf/pdfium/pdfium_page_unittest.cc
+++ b/pdf/pdfium/pdfium_page_unittest.cc
@@ -64,6 +64,7 @@
 void CompareTextRuns(const AccessibilityTextRunInfo& expected_text_run,
                      const AccessibilityTextRunInfo& actual_text_run) {
   EXPECT_EQ(expected_text_run.len, actual_text_run.len);
+  EXPECT_EQ(expected_text_run.tag_type, actual_text_run.tag_type);
   EXPECT_RECTF_EQ(expected_text_run.bounds, actual_text_run.bounds);
   EXPECT_EQ(expected_text_run.direction, actual_text_run.direction);
 
@@ -508,7 +509,7 @@
 
 using PDFiumPageImageTest = PDFiumTestBase;
 
-TEST_P(PDFiumPageImageTest, CalculateImages) {
+TEST_P(PDFiumPageImageTest, PopulateImageAltText) {
   TestClient client;
   std::unique_ptr<PDFiumEngine> engine =
       InitializeEngine(&client, FILE_PATH_LITERAL("image_alt_text.pdf"));
@@ -516,7 +517,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(3u, page.images_.size());
   EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect);
   EXPECT_EQ("Image 1", page.images_[0].alt_text);
@@ -534,7 +536,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(3u, page.images_.size());
   EXPECT_EQ(gfx::Rect(380, 78, 67, 68), page.images_[0].bounding_rect);
   EXPECT_EQ("Image 1", page.images_[0].alt_text);
@@ -577,7 +580,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(3u, page.images_.size());
 
   ASSERT_FALSE(page.images_[0].alt_text.empty());
@@ -605,7 +609,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(1u, page.images_.size());
 
   SkBitmap image_bitmap = engine->GetImageForOcr(
@@ -625,7 +630,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(1u, page.images_.size());
 
   // This page is rotated, therefore the extracted image size is 25x100 while
@@ -644,7 +650,8 @@
   ASSERT_EQ(1, engine->GetNumberOfPages());
 
   PDFiumPage& page = GetPDFiumPageForTest(*engine, 0);
-  page.CalculateImages();
+  std::vector<AccessibilityTextRunInfo> text_runs;
+  page.PopulateTextRunTypeAndImageAltText(text_runs);
   ASSERT_EQ(3u, page.images_.size());
   ASSERT_EQ(1, page.images_[0].page_object_index);
 
@@ -765,21 +772,21 @@
   // text run lengths respectively. There are text runs preceding and
   // succeeding them.
   auto expected_text_runs = std::to_array<AccessibilityTextRunInfo>({
-      {7, gfx::RectF(26.666666f, 189.333333f, 38.666672f, 13.333344f),
+      {7, "", gfx::RectF(26.666666f, 189.333333f, 38.666672f, 13.333344f),
        AccessibilityTextDirection::kLeftToRight, expected_style_1},
-      {16, gfx::RectF(70.666664f, 189.333333f, 108.0f, 14.666672f),
+      {16, "", gfx::RectF(70.666664f, 189.333333f, 108.0f, 14.666672f),
        AccessibilityTextDirection::kLeftToRight, expected_style_1},
-      {20, gfx::RectF(181.333333f, 189.333333f, 117.333333f, 14.666672f),
+      {20, "", gfx::RectF(181.333333f, 189.333333f, 117.333333f, 14.666672f),
        AccessibilityTextDirection::kLeftToRight, expected_style_1},
-      {9, gfx::RectF(28.0f, 117.33334f, 89.333328f, 20.0f),
+      {9, "", gfx::RectF(28.0f, 117.33334f, 89.333328f, 20.0f),
        AccessibilityTextDirection::kLeftToRight, expected_style_2},
-      {15, gfx::RectF(126.66666f, 117.33334f, 137.33334f, 20.0f),
+      {15, "", gfx::RectF(126.66666f, 117.33334f, 137.33334f, 20.0f),
        AccessibilityTextDirection::kLeftToRight, expected_style_2},
-      {20, gfx::RectF(266.66666f, 118.66666f, 169.33334f, 18.666664f),
+      {20, "", gfx::RectF(266.66666f, 118.66666f, 169.33334f, 18.666664f),
        AccessibilityTextDirection::kLeftToRight, expected_style_2},
-      {5, gfx::RectF(28.0f, 65.333336f, 40.0f, 18.666664f),
+      {5, "", gfx::RectF(28.0f, 65.333336f, 40.0f, 18.666664f),
        AccessibilityTextDirection::kLeftToRight, expected_style_2},
-      {17, gfx::RectF(77.333336f, 64.0f, 160.0f, 20.0f),
+      {17, "", gfx::RectF(77.333336f, 64.0f, 160.0f, 20.0f),
        AccessibilityTextDirection::kLeftToRight, expected_style_2},
   });
 
@@ -826,18 +833,17 @@
       "Helvetica", 0,          AccessibilityTextRenderMode::kFill,
       16,          0xff000000, 0xff000000,
       false,       false};
-  auto expected_text_runs = std::to_array<AccessibilityTextRunInfo>({
-      {5, gfx::RectF(1.3333334f, 198.66667f, 46.666668f, 14.666672f),
-       AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
-      {7, gfx::RectF(50.666668f, 198.66667f, 47.999996f, 17.333328f),
-       AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
-      {7, gfx::RectF(106.66666f, 198.66667f, 73.333336f, 18.666672f),
-       AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
-      {2, gfx::RectF(181.33333f, 202.66667f, 16.0f, 14.66667f),
-       AccessibilityTextDirection::kNone, kExpectedStyle},
-      {2, gfx::RectF(198.66667f, 202.66667f, 21.333328f, 10.666672f),
-       AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
-  });
+  auto expected_text_runs = std::to_array<AccessibilityTextRunInfo>(
+      {{5, "", gfx::RectF(1.3333334f, 198.66667f, 46.666668f, 14.666672f),
+        AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
+       {7, "", gfx::RectF(50.666668f, 198.66667f, 47.999996f, 17.333328f),
+        AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
+       {7, "", gfx::RectF(106.66666f, 198.66667f, 73.333336f, 18.666672f),
+        AccessibilityTextDirection::kLeftToRight, kExpectedStyle},
+       {2, "", gfx::RectF(181.33333f, 202.66667f, 16.0f, 14.66667f),
+        AccessibilityTextDirection::kNone, kExpectedStyle},
+       {2, "", gfx::RectF(198.66667f, 202.66667f, 21.333328f, 10.666672f),
+        AccessibilityTextDirection::kLeftToRight, kExpectedStyle}});
 
   if (UsingTestFonts()) {
     expected_text_runs[2].bounds =
diff --git a/pdf/test/data/tags.in b/pdf/test/data/tags.in
new file mode 100644
index 0000000..fc1da33
--- /dev/null
+++ b/pdf/test/data/tags.in
@@ -0,0 +1,164 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /StructTreeRoot 7 0 R
+  /Lang (en-US)
+  /MarkInfo <<
+    /Type /MarkInfo
+    /Marked true
+  >>
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Contents 6 0 R
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Resources <<
+    /Font <<
+      /F1 4 0 R
+      /F2 5 0 R
+    >>
+  >>
+  /StructParents 0
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+{{object 6 0}} <<
+  {{streamlen}}
+>>
+stream
+/Art <</MCID 0 >>BDC
+BT
+/F1 12 Tf
+20 50 Td
+(Article) Tj
+ET
+EMC
+/BlockQuote <</MCID 1 >>BDC
+BT
+/F1 12 Tf
+20 150 Td
+(BlockQuote) Tj
+ET
+EMC
+/P <</MCID 2 >>BDC
+BT
+/F1 12 Tf
+20 250 Td
+(Paragraph) Tj
+ET
+EMC
+/H1 <</MCID 3 >>BDC
+BT
+/F2 16 Tf
+20 350 Td
+(Heading1) Tj
+ET
+EMC
+/H2 <</MCID 4 >>BDC
+BT
+/F2 14 Tf
+20 550 Td
+(Heading2) Tj
+ET
+EMC
+endstream
+endobj
+{{object 7 0}} <<
+  /Type /StructTreeRoot
+  /K 8 0 R
+  /ParentTree 9 0 R
+  /ParentTreeNextKey 1
+>>
+endobj
+{{object 8 0}} <<
+  /Type /StructElem
+  /S /Document
+  /Lang (en-US)
+  /P 7 0 R
+  /K [10 0 R 11 0 R 12 0 R 13 0 R 14 0 R]
+>>
+endobj
+{{object 9 0}} <<
+  /Type /ParentTree
+  /Nums [0 [10 0 R 11 0 R 12 0 R 13 0 R 14 0 R]]
+>>
+endobj
+{{object 10 0}} <<
+  /Type /StructElem
+  /S /Art
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 0
+  >>
+>>
+endobj
+{{object 11 0}} <<
+  /Type /StructElem
+  /S /BlockQuote
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 1
+  >>
+>>
+endobj
+{{object 12 0}} <<
+  /Type /StructElem
+  /S /P
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 2
+  >>
+>>
+endobj
+{{object 13 0}} <<
+  /Type /StructElem
+  /S /H1
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 3
+  >>
+>>
+endobj
+{{object 14 0}} <<
+  /Type /StructElem
+  /S /H2
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 4
+  >>
+>>
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/pdf/test/data/tags.pdf b/pdf/test/data/tags.pdf
new file mode 100644
index 0000000..799c1803
--- /dev/null
+++ b/pdf/test/data/tags.pdf
@@ -0,0 +1,185 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 2 0 R
+  /StructTreeRoot 7 0 R
+  /Lang (en-US)
+  /MarkInfo <<
+    /Type /MarkInfo
+    /Marked true
+  >>
+>>
+endobj
+2 0 obj <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+  /Type /Page
+  /Contents 6 0 R
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Resources <<
+    /Font <<
+      /F1 4 0 R
+      /F2 5 0 R
+    >>
+  >>
+  /StructParents 0
+>>
+endobj
+4 0 obj <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Times-Roman
+>>
+endobj
+5 0 obj <<
+  /Type /Font
+  /Subtype /Type1
+  /BaseFont /Helvetica
+>>
+endobj
+6 0 obj <<
+  /Length 329
+>>
+stream
+/Art <</MCID 0 >>BDC
+BT
+/F1 12 Tf
+20 50 Td
+(Article) Tj
+ET
+EMC
+/BlockQuote <</MCID 1 >>BDC
+BT
+/F1 12 Tf
+20 150 Td
+(BlockQuote) Tj
+ET
+EMC
+/P <</MCID 2 >>BDC
+BT
+/F1 12 Tf
+20 250 Td
+(Paragraph) Tj
+ET
+EMC
+/H1 <</MCID 3 >>BDC
+BT
+/F2 16 Tf
+20 350 Td
+(Heading1) Tj
+ET
+EMC
+/H2 <</MCID 4 >>BDC
+BT
+/F2 14 Tf
+20 550 Td
+(Heading2) Tj
+ET
+EMC
+endstream
+endobj
+7 0 obj <<
+  /Type /StructTreeRoot
+  /K 8 0 R
+  /ParentTree 9 0 R
+  /ParentTreeNextKey 1
+>>
+endobj
+8 0 obj <<
+  /Type /StructElem
+  /S /Document
+  /Lang (en-US)
+  /P 7 0 R
+  /K [10 0 R 11 0 R 12 0 R 13 0 R 14 0 R]
+>>
+endobj
+9 0 obj <<
+  /Type /ParentTree
+  /Nums [0 [10 0 R 11 0 R 12 0 R 13 0 R 14 0 R]]
+>>
+endobj
+10 0 obj <<
+  /Type /StructElem
+  /S /Art
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 0
+  >>
+>>
+endobj
+11 0 obj <<
+  /Type /StructElem
+  /S /BlockQuote
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 1
+  >>
+>>
+endobj
+12 0 obj <<
+  /Type /StructElem
+  /S /P
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 2
+  >>
+>>
+endobj
+13 0 obj <<
+  /Type /StructElem
+  /S /H1
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 3
+  >>
+>>
+endobj
+14 0 obj <<
+  /Type /StructElem
+  /S /H2
+  /P 8 0 R
+  /K <<
+    /Type /MCR
+    /Pg 3 0 R
+    /MCID 4
+  >>
+>>
+endobj
+xref
+0 15
+0000000000 65535 f 
+0000000015 00000 n 
+0000000165 00000 n 
+0000000228 00000 n 
+0000000415 00000 n 
+0000000493 00000 n 
+0000000569 00000 n 
+0000000950 00000 n 
+0000001049 00000 n 
+0000001174 00000 n 
+0000001264 00000 n 
+0000001381 00000 n 
+0000001505 00000 n 
+0000001620 00000 n 
+0000001736 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 15
+>>
+startxref
+1852
+%%EOF
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 8cd2fbb8..bd38e7f 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -59,6 +59,7 @@
       "//services/viz/public/cpp/gpu:tests",
       "//services/viz/public/cpp/hit_test:tests",
       "//services/webnn:tests",
+      "//services/webnn/public/cpp:tests",
       "//services/webnn/public/mojom:tests",
     ]
     if (is_ios) {
diff --git a/services/webnn/coreml/graph_impl_coreml.mm b/services/webnn/coreml/graph_impl_coreml.mm
index 97fb043..ebafc80 100644
--- a/services/webnn/coreml/graph_impl_coreml.mm
+++ b/services/webnn/coreml/graph_impl_coreml.mm
@@ -28,7 +28,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/thread_pool.h"
-#include "base/trace_event/trace_event.h"
 #include "base/types/expected_macros.h"
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
@@ -39,6 +38,7 @@
 #include "services/webnn/coreml/utils_coreml.h"
 #include "services/webnn/error.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom.h"
 #include "services/webnn/public/mojom/webnn_error.mojom.h"
 #include "services/webnn/queueable_resource_state_base.h"
@@ -192,9 +192,11 @@
       base::flat_map<std::string,
                      scoped_refptr<QueueableResourceState<BufferContent>>>
           named_output_buffer_states,
-      base::OnceClosure completion_closure) const {
+      base::OnceClosure completion_closure,
+      ScopedTrace scoped_trace) const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+    scoped_trace.AddStep("Set up prediction");
     base::ElapsedTimer model_predict_timer;
 
     NSString* feature_name;
@@ -298,6 +300,8 @@
     auto wrapped_completion_closure =
         base::BindPostTaskToCurrentDefault(std::move(completion_closure));
 
+    scoped_trace.AddStep("Trigger prediction");
+
     // Run the MLModel asynchronously.
     [ml_model_
         predictionFromFeatures:feature_provider
@@ -306,14 +310,17 @@
                  base::CallbackToBlock(base::BindOnce(
                      &GraphImplCoreml::ComputeResources::DidDispatch, this,
                      std::move(model_predict_timer), std::move(output_backings),
-                     std::move(wrapped_completion_closure)))];
+                     std::move(wrapped_completion_closure),
+                     std::move(scoped_trace)))];
   }
 
   void DidDispatch(base::ElapsedTimer model_predict_timer,
                    NSMutableDictionary* output_backing_buffers,
                    base::OnceClosure completion_closure,
+                   ScopedTrace scoped_trace,
                    id<MLFeatureProvider> output_features,
                    NSError* error) const {
+    scoped_trace.AddStep("Process prediction");
     DEPRECATED_UMA_HISTOGRAM_MEDIUM_TIMES("WebNN.CoreML.TimingMs."
                                           "ModelPredictWithDispatch",
                                           model_predict_timer.Elapsed());
@@ -567,7 +574,8 @@
     const base::flat_map<std::string_view, WebNNTensorImpl*>& named_inputs,
     const base::flat_map<std::string_view, WebNNTensorImpl*>& named_outputs) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  TRACE_EVENT0("gpu", "webnn::coreml::GraphImpl::DispatchImpl");
+
+  ScopedTrace scoped_trace("GraphImplCoreml::DispatchImpl");
 
   base::flat_map<std::string,
                  scoped_refptr<QueueableResourceState<BufferContent>>>
@@ -591,6 +599,7 @@
       named_output_buffer_states, std::back_inserter(exclusive_resources),
       [](const auto& name_and_state) { return name_and_state.second; });
 
+  scoped_trace.AddStep("Acquire resources");
   auto task = base::MakeRefCounted<ResourceTask>(
       std::move(shared_resources), std::move(exclusive_resources),
       base::BindOnce(
@@ -603,13 +612,14 @@
                  std::string,
                  scoped_refptr<QueueableResourceState<BufferContent>>>
                  named_output_buffer_states,
-             base::OnceClosure completion_closure) {
+             ScopedTrace scoped_trace, base::OnceClosure completion_closure) {
             compute_resources->DoDispatch(std::move(named_input_buffer_states),
                                           std::move(named_output_buffer_states),
-                                          std::move(completion_closure));
+                                          std::move(completion_closure),
+                                          std::move(scoped_trace));
           },
           compute_resources_, std::move(named_input_buffer_states),
-          std::move(named_output_buffer_states)));
+          std::move(named_output_buffer_states), std::move(scoped_trace)));
   task->Enqueue();
 }
 
diff --git a/services/webnn/coreml/tensor_impl_coreml.mm b/services/webnn/coreml/tensor_impl_coreml.mm
index 61814c1..026182d8 100644
--- a/services/webnn/coreml/tensor_impl_coreml.mm
+++ b/services/webnn/coreml/tensor_impl_coreml.mm
@@ -13,6 +13,7 @@
 #include "services/webnn/coreml/context_impl_coreml.h"
 #include "services/webnn/coreml/utils_coreml.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/queueable_resource_state.h"
 #include "services/webnn/resource_task.h"
 
@@ -138,27 +139,31 @@
     mojom::WebNNTensor::ReadTensorCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  ScopedTrace scoped_trace("TensorImplCoreml::ReadTensorImpl");
+
   // Lock the buffer contents as shared/read-only.
   std::vector<scoped_refptr<QueueableResourceStateBase>> shared_resources = {
       buffer_state_};
 
+  scoped_trace.AddStep("Wait for tensor");
   auto task = base::MakeRefCounted<ResourceTask>(
       std::move(shared_resources),
       /*exclusive_resources=*/
       std::vector<scoped_refptr<QueueableResourceStateBase>>(),
       base::BindOnce(
-          [](size_t bytes_to_read,
-             scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
+          [](scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
              ReadTensorCallback read_tensor_result_callback,
-             base::OnceClosure completion_closure) {
-            mojo_base::BigBuffer output_buffer(bytes_to_read);
+             ScopedTrace scoped_trace, base::OnceClosure completion_closure) {
+            scoped_trace.AddStep("Begin read");
 
             // Read from the underlying buffer contents, which are kept alive
             // until `completion_closure` is run.
             buffer_state->GetSharedLockedResource().Read(base::BindOnce(
                 [](base::OnceClosure completion_closure,
                    ReadTensorCallback read_tensor_result_callback,
+                   ScopedTrace scoped_trace,
                    mojo_base::BigBuffer output_buffer) {
+                  scoped_trace.AddStep("End read");
                   // Unlock the buffer contents.
                   std::move(completion_closure).Run();
 
@@ -167,34 +172,45 @@
                           std::move(output_buffer)));
                 },
                 std::move(completion_closure),
-                std::move(read_tensor_result_callback)));
+                std::move(read_tensor_result_callback),
+                std::move(scoped_trace)));
           },
-          /*bytes_to_read=*/PackedByteLength(), buffer_state_,
-          std::move(callback)));
+          buffer_state_, std::move(callback), std::move(scoped_trace)));
   task->Enqueue();
 }
 
 void TensorImplCoreml::WriteTensorImpl(mojo_base::BigBuffer src_buffer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  ScopedTrace scoped_trace("TensorImplCoreml::WriteTensorImpl");
+
   // Take an exclusive lock to the buffer contents while writing.
   std::vector<scoped_refptr<QueueableResourceStateBase>> exclusive_resources = {
       buffer_state_};
 
+  scoped_trace.AddStep("Wait for tensor");
   auto task = base::MakeRefCounted<ResourceTask>(
       /*shared_resources=*/
       std::vector<scoped_refptr<QueueableResourceStateBase>>(),
       std::move(exclusive_resources),
       base::BindOnce(
           [](scoped_refptr<QueueableResourceState<BufferContent>> buffer_state,
-             mojo_base::BigBuffer src_buffer,
+             mojo_base::BigBuffer src_buffer, ScopedTrace scoped_trace,
              base::OnceClosure completion_closure) {
+            scoped_trace.AddStep("Begin write");
             // Write to the underlying buffer contents, which are kept alive
             // until `completion_closure` is run.
             buffer_state->GetExclusivelyLockedResource()->Write(
-                src_buffer, std::move(completion_closure));
+                src_buffer,
+                base::BindOnce(
+                    [](base::OnceClosure completion_closure,
+                       ScopedTrace scoped_trace) {
+                      scoped_trace.AddStep("End write");
+                      std::move(completion_closure).Run();
+                    },
+                    std::move(completion_closure), std::move(scoped_trace)));
           },
-          buffer_state_, std::move(src_buffer)));
+          buffer_state_, std::move(src_buffer), std::move(scoped_trace)));
   task->Enqueue();
 }
 
diff --git a/services/webnn/public/cpp/BUILD.gn b/services/webnn/public/cpp/BUILD.gn
index 49cb62a..736b660 100644
--- a/services/webnn/public/cpp/BUILD.gn
+++ b/services/webnn/public/cpp/BUILD.gn
@@ -18,6 +18,8 @@
     "supported_tensors.h",
     "webnn_errors.cc",
     "webnn_errors.h",
+    "webnn_trace.cc",
+    "webnn_trace.h",
   ]
 
   deps = [
@@ -27,3 +29,15 @@
 
   defines = [ "IS_WEBNN_PUBLIC_CPP_IMPL" ]
 }
+
+source_set("tests") {
+  testonly = true
+
+  sources = [ "webnn_trace_unittest.cc" ]
+
+  deps = [
+    ":cpp",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/third_party/blink/renderer/modules/ml/ml_trace.cc b/services/webnn/public/cpp/webnn_trace.cc
similarity index 60%
rename from third_party/blink/renderer/modules/ml/ml_trace.cc
rename to services/webnn/public/cpp/webnn_trace.cc
index bf512a9..73ca78c 100644
--- a/third_party/blink/renderer/modules/ml/ml_trace.cc
+++ b/services/webnn/public/cpp/webnn_trace.cc
@@ -2,32 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_id_helper.h"
 
-namespace blink {
+namespace webnn {
 
 constexpr char kWebNNTraceCategory[] = "webnn";
 
-// Reset the |id_| so the moved `ScopedMLTrace` object won't end the trace
+// Reset the |id_| so the moved `ScopedTrace` object won't end the trace
 // prematurely on destruction.
-ScopedMLTrace::ScopedMLTrace(ScopedMLTrace&& other)
+ScopedTrace::ScopedTrace(ScopedTrace&& other)
     : name_(other.name_),
       id_(std::exchange(other.id_, std::nullopt)),
       step_(std::move(other.step_)) {}
 
-ScopedMLTrace::~ScopedMLTrace() {
+ScopedTrace::~ScopedTrace() {
   if (id_.has_value()) {
     TRACE_EVENT_NESTABLE_ASYNC_END0(kWebNNTraceCategory, name_,
                                     TRACE_ID_LOCAL(id_.value()));
   }
 }
 
-ScopedMLTrace& ScopedMLTrace::operator=(ScopedMLTrace&& other) {
+ScopedTrace& ScopedTrace::operator=(ScopedTrace&& other) {
   if (this != &other) {
     name_ = other.name_;
     id_ = std::exchange(other.id_, std::nullopt);
@@ -36,20 +36,19 @@
   return *this;
 }
 
-void ScopedMLTrace::AddStep(const char* step_name) {
+void ScopedTrace::AddStep(const char* step_name) {
   // Calling AddStep() after move is not allowed.
   CHECK(id_.has_value());
   step_.reset();
-  step_ = base::WrapUnique(new ScopedMLTrace(step_name, id_.value()));
+  step_ = base::WrapUnique(new ScopedTrace(step_name, id_.value()));
 }
 
-ScopedMLTrace::ScopedMLTrace(const char* name)
-    : ScopedMLTrace(name, base::trace_event::GetNextGlobalTraceId()) {}
+ScopedTrace::ScopedTrace(const char* name)
+    : ScopedTrace(name, base::trace_event::GetNextGlobalTraceId()) {}
 
-ScopedMLTrace::ScopedMLTrace(const char* name, uint64_t id)
-    : name_(name), id_(id) {
+ScopedTrace::ScopedTrace(const char* name, uint64_t id) : name_(name), id_(id) {
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kWebNNTraceCategory, name_,
                                     TRACE_ID_LOCAL(id_.value()));
 }
 
-}  // namespace blink
+}  // namespace webnn
diff --git a/services/webnn/public/cpp/webnn_trace.h b/services/webnn/public/cpp/webnn_trace.h
new file mode 100644
index 0000000..b62de55
--- /dev/null
+++ b/services/webnn/public/cpp/webnn_trace.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_PUBLIC_CPP_WEBNN_TRACE_H_
+#define SERVICES_WEBNN_PUBLIC_CPP_WEBNN_TRACE_H_
+
+#include <memory>
+#include <optional>
+
+#include "base/component_export.h"
+
+namespace webnn {
+
+// The trace starts when an object of this class is created, and ends when
+// the object goes out scope.
+// You should 'std::move' this object when binding callbacks. The trace ends
+// if the callback is destroyed (even if it's not run).
+//
+// Methods in this class are safe to be called from any thread.
+class COMPONENT_EXPORT(WEBNN_PUBLIC_CPP) ScopedTrace {
+ public:
+  // Create a ScopedTrace instance.
+  //
+  // Important note: Use literal strings only. See trace_event_common.h.
+  explicit ScopedTrace(const char* name);
+  ScopedTrace(ScopedTrace&& other);
+  ScopedTrace& operator=(ScopedTrace&& other);
+  ScopedTrace(const ScopedTrace&) = delete;
+  ScopedTrace& operator=(const ScopedTrace&) = delete;
+  ~ScopedTrace();
+
+  // Starts a nested sub-trace in the current trace. The next AddStep() call
+  // will mark the end of the previous sub-trace.
+  void AddStep(const char* step_name);
+
+ private:
+  ScopedTrace(const char* name, uint64_t id);
+
+  const char* name_;
+
+  // The trace ID.
+  //
+  // An 'std::nullopt' means the trace has been transferred to another
+  // 'ScopedTrace' object, and stops 'this''s destruction from ending the
+  // trace.
+  std::optional<uint64_t> id_;
+  std::unique_ptr<ScopedTrace> step_;
+};
+
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_PUBLIC_CPP_WEBNN_TRACE_H_
diff --git a/services/webnn/public/cpp/webnn_trace_unittest.cc b/services/webnn/public/cpp/webnn_trace_unittest.cc
new file mode 100644
index 0000000..0633567
--- /dev/null
+++ b/services/webnn/public/cpp/webnn_trace_unittest.cc
@@ -0,0 +1,286 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/public/cpp/webnn_trace.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/functional/bind.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/bind_post_task.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webnn {
+
+class ScopedTraceTest : public testing::Test {
+ public:
+  ScopedTraceTest() = default;
+
+  ~ScopedTraceTest() override = default;
+
+  void SetUp() override {
+    test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  }
+
+  void TearDown() override { base::trace_event::TraceLog::ResetForTesting(); }
+
+ protected:
+  void StartTracing(const std::string& filter) {
+    base::trace_event::TraceLog::GetInstance()->SetEnabled(
+        base::trace_event::TraceConfig(filter,
+                                       base::trace_event::RECORD_UNTIL_FULL));
+  }
+
+  static void TraceDataCb(
+      base::OnceClosure quit_closure,
+      base::trace_event::TraceResultBuffer::SimpleOutput* json_output,
+      const scoped_refptr<base::RefCountedString>& json_events_str,
+      bool has_more_events) {
+    base::trace_event::TraceResultBuffer trace_buffer;
+    trace_buffer.SetOutputCallback(json_output->GetCallback());
+    trace_buffer.Start();
+    trace_buffer.AddFragment(json_events_str->as_string());
+    trace_buffer.Finish();
+    if (!has_more_events) {
+      std::move(quit_closure).Run();
+    }
+  }
+
+  // End tracing, return tracing data in a map of event
+  // name->(begin_event_counts, end_event_counts)
+  std::map<std::string, std::pair<int, int>> EndTracing() {
+    std::map<std::string, std::pair<int, int>> event_counts;
+    base::trace_event::TraceResultBuffer::SimpleOutput json_data;
+    base::trace_event::TraceLog::GetInstance()->SetDisabled();
+    base::RunLoop run_loop;
+    base::trace_event::TraceLog::GetInstance()->Flush(base::BindRepeating(
+        &ScopedTraceTest::TraceDataCb, run_loop.QuitClosure(), &json_data));
+    run_loop.Run();
+
+    auto parsed_json =
+        base::JSONReader::ReadAndReturnValueWithError(json_data.json_output);
+    CHECK(parsed_json.has_value())
+        << "JSON parsing failed (" << parsed_json.error().message
+        << ") JSON data:" << std::endl
+        << json_data.json_output;
+
+    CHECK(parsed_json->is_list());
+    for (const base::Value& entry : parsed_json->GetList()) {
+      const auto& dict = entry.GetDict();
+      const std::string* name = dict.FindString("name");
+      CHECK(name);
+      const std::string* trace_type = dict.FindString("ph");
+      CHECK(trace_type);
+      // Count both the "BEGIN" and "END" traces.
+      if (*trace_type == "n") {
+        ((event_counts)[*name].first)++;
+        ((event_counts)[*name].second)++;
+      } else if (*trace_type != "E" && *trace_type != "e") {
+        ((event_counts)[*name].first)++;
+      } else {
+        ((event_counts)[*name].second)++;
+      }
+    }
+    return event_counts;
+  }
+
+  // The task runner we use for posting tasks.
+  base::test::TaskEnvironment task_environment_;
+  scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
+};
+
+TEST_F(ScopedTraceTest, SingleScopeWithoutStep) {
+  {
+    // Check the behavior without move. Both begin/end event should be seen.
+    StartTracing("webnn");
+    { ScopedTrace scoped_trace1("Method1"); }
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+  }
+
+  {
+    // Check the behavior with move assign. Both begin/end event should be seen.
+    StartTracing("webnn");
+    {
+      ScopedTrace scoped_trace1("Method1");
+      ScopedTrace scoped_trace2 = std::move(scoped_trace1);
+    }
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+  }
+
+  {
+    // Check the behavior with move ctor, similar as move assign.
+    StartTracing("webnn");
+    {
+      ScopedTrace scoped_trace1("Method1");
+      ScopedTrace scoped_trace2(std::move(scoped_trace1));
+    }
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+  }
+
+  {
+    // Move should not trigger an immediate end event.
+    StartTracing("webnn");
+    {
+      ScopedTrace scoped_trace1("Method1");
+      ScopedTrace scoped_trace2 = std::move(scoped_trace1);
+      auto event_counts = EndTracing();
+      auto [method_begins, method_ends] = event_counts.at("Method1");
+      EXPECT_EQ(1, method_begins);
+      EXPECT_EQ(0, method_ends);
+    }
+  }
+}
+
+// Both main trace and sub-trace should have pairing begin/end.
+TEST_F(ScopedTraceTest, SingleScopeWithStep) {
+  StartTracing("webnn");
+  {
+    ScopedTrace scoped_trace1("Method1");
+    scoped_trace1.AddStep("Step1");
+    ScopedTrace scoped_trace2 = std::move(scoped_trace1);
+  }
+  auto event_counts = EndTracing();
+
+  auto [method_begins, method_ends] = event_counts.at("Method1");
+  auto [step_begins, step_ends] = event_counts.at("Step1");
+  EXPECT_EQ(1, method_begins);
+  EXPECT_EQ(1, method_ends);
+  EXPECT_EQ(1, step_begins);
+  EXPECT_EQ(1, step_ends);
+}
+
+// Multiple steps should results in multiple begin/end pairs.
+TEST_F(ScopedTraceTest, MultipleAddSteps) {
+  StartTracing("webnn");
+  {
+    ScopedTrace scoped_trace1("Method1");
+    scoped_trace1.AddStep("Step1");
+    scoped_trace1.AddStep("Step2");
+    ScopedTrace scoped_trace2(std::move(scoped_trace1));
+    scoped_trace2.AddStep("Step3");
+  }
+  auto event_counts = EndTracing();
+
+  auto [method1_begins, method1_ends] = event_counts.at("Method1");
+  auto [step1_begins, step1_ends] = event_counts.at("Step1");
+  auto [step2_begins, step2_ends] = event_counts.at("Step2");
+  auto [step3_begins, step3_ends] = event_counts.at("Step3");
+  EXPECT_EQ(1, method1_begins);
+  EXPECT_EQ(1, method1_ends);
+  EXPECT_EQ(1, step1_begins);
+  EXPECT_EQ(1, step1_ends);
+  EXPECT_EQ(1, step2_begins);
+  EXPECT_EQ(1, step2_ends);
+  EXPECT_EQ(1, step3_begins);
+  EXPECT_EQ(1, step3_ends);
+}
+
+// Nesting top-level traces should have pairing begin/end.
+TEST_F(ScopedTraceTest, MultipleNestedTraces) {
+  StartTracing("webnn");
+  {
+    ScopedTrace scoped_trace1("Method1");
+    { ScopedTrace scoped_trace2("Method2"); }
+  }
+  auto event_counts = EndTracing();
+
+  auto [method1_begins, method1_ends] = event_counts.at("Method1");
+  auto [method2_begins, method2_ends] = event_counts.at("Method2");
+  EXPECT_EQ(1, method1_begins);
+  EXPECT_EQ(1, method1_ends);
+  EXPECT_EQ(1, method2_begins);
+  EXPECT_EQ(1, method2_ends);
+}
+
+// Trace handle should be passed correct across function boundaries.
+TEST_F(ScopedTraceTest, PassScopedTraceToFunc) {
+  {
+    // Pass to another function that does not add extra step.
+    StartTracing("webnn");
+    ScopedTrace scoped_trace1("Method1");
+    ([](ScopedTrace trace) {})(std::move(scoped_trace1));
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    method_ends = event_counts["Method1"].second;
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+  }
+
+  {
+    // Pass to another function call that adds extra step.
+    StartTracing("webnn");
+    ScopedTrace scoped_trace2("Method1");
+    ([](ScopedTrace trace) { trace.AddStep("Step1"); })(
+        std::move(scoped_trace2));
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    auto [step_begins, step_ends] = event_counts.at("Step1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+    EXPECT_EQ(1, step_begins);
+    EXPECT_EQ(1, step_ends);
+  }
+}
+
+TEST_F(ScopedTraceTest, WorksWithBindOnce) {
+  {
+    // Invoke BindOnce without adding extra step.
+    StartTracing("webnn");
+    ScopedTrace scoped_trace1("Method1");
+    test_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce([](ScopedTrace trace) {}, std::move(scoped_trace1)));
+    test_task_runner_->RunUntilIdle();
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+  }
+
+  {
+    // Invoke BindOnce and add extra step.
+    StartTracing("webnn");
+    ScopedTrace scoped_trace2("Method1");
+    test_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce([](ScopedTrace trace) { trace.AddStep("Step1"); },
+                       std::move(scoped_trace2)));
+    test_task_runner_->RunUntilIdle();
+    auto event_counts = EndTracing();
+
+    auto [method_begins, method_ends] = event_counts.at("Method1");
+    auto [step_begins, step_ends] = event_counts.at("Step1");
+    EXPECT_EQ(1, method_begins);
+    EXPECT_EQ(1, method_ends);
+    EXPECT_EQ(1, step_begins);
+    EXPECT_EQ(1, step_ends);
+  }
+}
+
+}  // namespace webnn
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 37dba55..a4b454a9 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -100,83 +100,6 @@
     "isolated_scripts": [
       {
         "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_python_tests",
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
-        },
-        "test": "blink_web_tests",
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "merge": {
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "chrome_sizes",
@@ -194,334 +117,6 @@
         },
         "test": "chrome_sizes",
         "test_id_prefix": "ninja://chrome/test:chrome_sizes/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "chrome_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_wpt_tests",
-        "test_id_prefix": "ninja://:chrome_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_py_tests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests_headless_shell",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_py_tests_headless_shell",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests_headless_shell/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_replay_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_perftests",
-        "test_id_prefix": "ninja://components:components_perftests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_shell_crash_test",
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "resultdb": {
-          "enable": true,
-          "result_format": "single"
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "flatbuffers_unittests",
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "grit_python_unittests",
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "args": [
-          "--test-type",
-          "testharness",
-          "reftest",
-          "crashtest",
-          "print-reftest",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/content_shell.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "headless_shell_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 18
-        },
-        "test": "headless_shell_wpt",
-        "test_id_prefix": "ninja://:headless_shell_wpt/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mac_signing_tests",
-        "test_id_prefix": "ninja://chrome/installer/mac:mac_signing_tests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_python_unittests",
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "idempotent": false,
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "telemetry_gpu_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--extra-browser-args=--enable-crashpad"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_perf_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "idempotent": false,
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test": "telemetry_perf_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/"
-      },
-      {
-        "args": [
-          "--jobs=1",
-          "--extra-browser-args=--disable-gpu"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_unittests",
-        "resultdb": {
-          "enable": true
-        },
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "idempotent": false,
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 8
-        },
-        "test": "telemetry_unittests",
-        "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-14",
-            "pool": "chrome.tests"
-          },
-          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_perftests",
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
       }
     ]
   },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 1a469e7..006082c 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -575,7 +575,7 @@
         ],
         'test_suites': {
           'gtest_tests': 'clang_tot_gtests',
-          'isolated_scripts': 'chromium_mac_rel_isolated_scripts_and_sizes',
+          'isolated_scripts': 'chrome_sizes_suite',
         },
         'additional_compile_targets': [
           'all',
diff --git a/third_party/blink/public/web/web_form_control_element.h b/third_party/blink/public/web/web_form_control_element.h
index 2e73e18..fe1fa020 100644
--- a/third_party/blink/public/web/web_form_control_element.h
+++ b/third_party/blink/public/web/web_form_control_element.h
@@ -147,6 +147,15 @@
   WebString NameForAutofill() const;
 
   WebFormElement Form() const;
+  // Returns the form that owns this element according to Autofill's definition
+  // of ownership, or a null WebFormElement if no form owns it. The form that
+  // owns this element is:
+  // - if this element is associated to a form, the furthest shadow-including
+  //   form ancestor of that form,
+  // - otherwise, the furthest shadow-including form ancestor of this element.
+  // For the definition of ownership in Autofill, see
+  // //components/autofill/content/renderer/README.md.
+  WebFormElement GetOwningFormForAutofill() const;
 
   // Returns the ax node id of the form control element in the accessibility
   // tree. The ax node id is consistent across renderer and browser processes.
diff --git a/third_party/blink/renderer/core/css/robin_hood_map-inl.h b/third_party/blink/renderer/core/css/robin_hood_map-inl.h
index 2859881c..c354f6d 100644
--- a/third_party/blink/renderer/core/css/robin_hood_map-inl.h
+++ b/third_party/blink/renderer/core/css/robin_hood_map-inl.h
@@ -65,6 +65,10 @@
 template <class Key, class Value>
 typename RobinHoodMap<Key, Value>::Bucket* RobinHoodMap<Key, Value>::Insert(
     const Key& key) {
+  unsigned hash = key.Hash();
+  pre_filter_ |= 1ULL << (hash & 63);
+  pre_filter_ |= 1ULL << ((hash >> 6) & 63);
+
   Bucket* bucket = InsertInternal({key, {}});
   if (bucket != nullptr) {
     // Normal, happy path.
@@ -91,6 +95,7 @@
       new_ht = new_ht.Grow();
     }
   }
+  new_ht.pre_filter_ = pre_filter_;
   return new_ht;
 }
 
diff --git a/third_party/blink/renderer/core/css/robin_hood_map.h b/third_party/blink/renderer/core/css/robin_hood_map.h
index d420912c..686424b 100644
--- a/third_party/blink/renderer/core/css/robin_hood_map.h
+++ b/third_party/blink/renderer/core/css/robin_hood_map.h
@@ -56,6 +56,8 @@
 //    Of course, if you lower kPossibleBucketsPerKey to e.g. 4, you'll
 //    only need a 5-collision, which is _much_ more likely.)
 //
+//  - A tiny Bloom filter to quickly filter out most (~80%+) negative queries.
+//
 // Possible future extensions:
 //
 //  - Arbitrary keys (currently supports only AtomicString as key).
@@ -101,7 +103,9 @@
   };
 
   // Constructs a map that can hold no elements; the only thing
-  // you can do with it is check IsNull() (which will be true).
+  // you can do with it is check IsNull() (which will be true)
+  // and Find() (which will return nullptr, since pre_filter_
+  // will be empty).
   RobinHoodMap() = default;
   explicit RobinHoodMap(unsigned size)
       : buckets_(new Bucket[size + kPossibleBucketsPerKey]),
@@ -110,6 +114,17 @@
   bool IsNull() const { return buckets_ == nullptr; }
 
   Bucket* Find(const Key& key) {
+    uint32_t hash = key.Hash();
+    bool h1 = (pre_filter_ >> (hash & 63)) & 1;
+    bool h2 = (pre_filter_ >> ((hash >> 6) & 63)) & 1;
+    if (!h1 || !h2) {
+      // NOTE: Since the filter will always be empty
+      // if buckets_ is nullptr, we don't need an extra
+      // test for buckets_ below (nor in the caller);
+      // we'll always hit this path.
+      return nullptr;
+    }
+
     Bucket* bucket = FindBucket(key);
     for (unsigned i = 0; i < kPossibleBucketsPerKey; ++i, ++bucket) {
       if (bucket->key == key) {
@@ -245,6 +260,17 @@
   // where the given key ended up and returns its bucket.
   Bucket* InsertWithRehashing(const Key& key);
 
+  // A tiny Bloom filter that is used as a prefilter for Find().
+  // This allows us to quickly return nullptr for queries that are not
+  // in the map (which is a fairly common case for us), without having to
+  // take the cache miss to actually look up in the map. (We'd get even
+  // better filter rates with three hashes instead of two, but it seems
+  // to be net-negative in performance.)
+  //
+  // Note that this filter uses the lower bits of the string hash,
+  // which are fairly independent from what FindBucketIndex() uses.
+  uint64_t pre_filter_ = 0;
+
   // The buckets, allocated in the usual way. Note that in addition to the
   // requested number of buckets (num_buckets_), we allocate first
   // (kPossibleBucketsPerKey - 1) extra buckets, so that we can overflow even
diff --git a/third_party/blink/renderer/core/css/rule_set.h b/third_party/blink/renderer/core/css/rule_set.h
index 8f68939..c75adbb 100644
--- a/third_party/blink/renderer/core/css/rule_set.h
+++ b/third_party/blink/renderer/core/css/rule_set.h
@@ -270,10 +270,6 @@
       const RuleSet& old_rule_set,
       RuleSet& new_rule_set);
   base::span<const RuleData> Find(const AtomicString& key) const {
-    if (buckets.IsNull()) {
-      return {};
-    }
-
     // Go through all the buckets and check for equality, brute force.
     // Note that we don't check for IsNull() to get an early abort
     // on empty buckets; the comparison of AtomicString is so cheap
diff --git a/third_party/blink/renderer/core/exported/web_form_control_element.cc b/third_party/blink/renderer/core/exported/web_form_control_element.cc
index c0abd753..874795a9 100644
--- a/third_party/blink/renderer/core/exported/web_form_control_element.cc
+++ b/third_party/blink/renderer/core/exported/web_form_control_element.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
+#include "third_party/blink/renderer/core/html/forms/listed_element.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/keyboard_codes.h"
@@ -304,6 +305,11 @@
   return WebFormElement(ConstUnwrap<HTMLFormControlElement>()->Form());
 }
 
+WebFormElement WebFormControlElement::GetOwningFormForAutofill() const {
+  return WebFormElement(
+      ConstUnwrap<HTMLFormControlElement>()->GetOwningFormForAutofill());
+}
+
 int32_t WebFormControlElement::GetAxId() const {
   return ConstUnwrap<HTMLFormControlElement>()->GetAxId();
 }
diff --git a/third_party/blink/renderer/core/exported/web_form_control_element_test.cc b/third_party/blink/renderer/core/exported/web_form_control_element_test.cc
index eeb98b4..89858c5 100644
--- a/third_party/blink/renderer/core/exported/web_form_control_element_test.cc
+++ b/third_party/blink/renderer/core/exported/web_form_control_element_test.cc
@@ -15,10 +15,12 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/event_type_names.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 
 namespace blink {
@@ -165,4 +167,275 @@
   EXPECT_EQ(element.Value().Ascii(), "value");
 }
 
+class WebFormControlElementGetOwningFormForAutofillTest
+    : public WebFormControlElementTest {
+ protected:
+  template <typename DocumentOrShadowRoot>
+  WebFormElement GetFormElementById(
+      const DocumentOrShadowRoot& document_or_shadow_root,
+      std::string_view id) {
+    return WebFormElement(DynamicTo<HTMLFormElement>(
+        document_or_shadow_root.getElementById(WebString::FromASCII(id))));
+  }  // namespace blink
+
+  template <typename DocumentOrShadowRoot>
+  WebFormControlElement GetFormControlElementById(
+      const DocumentOrShadowRoot& document_or_shadow_root,
+      std::string_view id) {
+    return WebFormControlElement(DynamicTo<HTMLFormControlElement>(
+        document_or_shadow_root.getElementById(WebString::FromASCII(id))));
+  }
+};
+
+// Tests that the owning form of a form control element in light DOM is its
+// associated form (i.e. the form explicitly set via form attribute or its
+// closest ancestor).
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInLightDom) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f>
+      <input id=t1>
+      <input id=t2>
+    </form>
+    <input id=t3>)");
+  WebFormElement f = GetFormElementById(document, "f");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(document, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(document, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(document, "t3");
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f_unowned);
+}
+
+// Tests that explicit association overrules DOM ancestry when determining the
+// owning form.
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInLightDomWithExplicitAssociation) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <div>
+      <form id=f1>
+        <input id=t1>
+        <input id=t2 form=f2>
+      </form>
+    </div>
+    <form id=f2>
+      <input id=t3>
+      <input id=t4 form=f1>
+      <input id=t5 form=f_unowned>
+    </form>
+    <input id=t6 form=f1>
+    <input id=t7 form=f2>
+    <input id=t8>)");
+  WebFormElement f1 = GetFormElementById(document, "f1");
+  WebFormElement f2 = GetFormElementById(document, "f2");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(document, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(document, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(document, "t3");
+  WebFormControlElement t4 = GetFormControlElementById(document, "t4");
+  WebFormControlElement t5 = GetFormControlElementById(document, "t5");
+  WebFormControlElement t6 = GetFormControlElementById(document, "t6");
+  WebFormControlElement t7 = GetFormControlElementById(document, "t7");
+  WebFormControlElement t8 = GetFormControlElementById(document, "t8");
+
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f2);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f2);
+  EXPECT_EQ(t4.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t5.GetOwningFormForAutofill(), f_unowned);
+  EXPECT_EQ(t6.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t7.GetOwningFormForAutofill(), f2);
+  EXPECT_EQ(t8.GetOwningFormForAutofill(), f_unowned);
+}
+
+// Tests that input elements in shadow DOM whose closest ancestor is in the
+// light DOM are extracted correctly.
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInShadowDomWithoutFormInShadowDom) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f1>
+      <div id=host1>
+        <template shadowrootmode="open">
+          <div>
+            <input id=t1>
+          </div>
+        </template>
+        <input id=t2>
+      </div>
+    </form>
+    <div id=host2>
+      <template shadowrootmode="open">
+        <input id=t3>
+      </template>
+    </div>)");
+  const ShadowRoot& shadow_root1 = *GetElementById("host1")->GetShadowRoot();
+  const ShadowRoot& shadow_root2 = *GetElementById("host2")->GetShadowRoot();
+  WebFormElement f1 = GetFormElementById(document, "f1");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(shadow_root1, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(document, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(shadow_root2, "t3");
+
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f_unowned);
+}
+
+// Tests that the owning form of a form control element is the furthest
+// shadow-including ancestor form element (in absence of explicit associations).
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInShadowDomWithFormInShadowDom) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f1>
+      <div id=host1>
+        <template shadowrootmode=open>
+          <div>
+            <form id=f2>
+              <input id=t1>
+            </form>
+          </div>
+          <input id=t2>
+        </template>
+      </div>
+    </form>
+    <div id=host2>
+      <template shadowrootmode=open>
+        <form id=f3>
+          <input id=t3>
+        </form>
+      </template>
+    </div>)");
+  const ShadowRoot& shadow_root1 = *GetElementById("host1")->GetShadowRoot();
+  const ShadowRoot& shadow_root2 = *GetElementById("host2")->GetShadowRoot();
+  WebFormElement f1 = GetFormElementById(document, "f1");
+  WebFormElement f3 = GetFormElementById(shadow_root2, "f3");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(shadow_root1, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(shadow_root1, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(shadow_root2, "t3");
+
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f3);
+}
+
+// Tests that the owning form is returned correctly even if there are
+// multiple levels of Shadow DOM.
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInShadowDomWithFormInShadowDomWithMultipleLevels) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f1>
+      <div id=host1>
+        <template shadowrootmode=open>
+          <form id=f2>
+            <input id=t1>
+          </form>
+          <div id=host2>
+            <template shadowrootmode=open>
+              <form id=f3>
+                <input id=t2>
+              </form>
+              <input id=t3>
+            </template>
+            <input id=t4>
+          </div>
+          <input id=t5>
+        </template>
+      </div>
+    </form>)");
+
+  const ShadowRoot& shadow_root1 = *GetElementById("host1")->GetShadowRoot();
+  const ShadowRoot& shadow_root2 =
+      *shadow_root1.getElementById(AtomicString("host2"))->GetShadowRoot();
+  WebFormElement f1 = GetFormElementById(document, "f1");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(shadow_root1, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(shadow_root2, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(shadow_root2, "t3");
+  WebFormControlElement t4 = GetFormControlElementById(shadow_root1, "t4");
+  WebFormControlElement t5 = GetFormControlElementById(shadow_root1, "t5");
+
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t4.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t5.GetOwningFormForAutofill(), f1);
+}
+
+// Tests that the owning form is computed correctly for form control elements
+// inside the shadow DOM that have explicit form attributes.
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInShadowDomWithFormInShadowDomAndExplicitAssociation) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f1>
+      <div id=host1>
+        <template shadowrootmode=open>
+          <form id=f2>
+            <input id=t1>
+          </form>
+          <input id=t2>
+          <form id=f3>
+            <input id=t3 form=f2>
+          </form>
+          <input id=t4 form=f2>
+          <input id=t5 form=f3>
+          <input id=t6 form=f1>
+        </template>
+      </div>
+    </form>
+    <div id=host2>
+      <template shadowrootmode=open>
+        <form id=f4>
+          <input id=t7>
+        </form>
+      </template>
+    </div>)");
+  const ShadowRoot& shadow_root1 = *GetElementById("host1")->GetShadowRoot();
+  const ShadowRoot& shadow_root2 = *GetElementById("host2")->GetShadowRoot();
+  WebFormElement f1 = GetFormElementById(document, "f1");
+  WebFormElement f4 = GetFormElementById(shadow_root2, "f4");
+  WebFormElement f_unowned = WebFormElement();
+  WebFormControlElement t1 = GetFormControlElementById(shadow_root1, "t1");
+  WebFormControlElement t2 = GetFormControlElementById(shadow_root1, "t2");
+  WebFormControlElement t3 = GetFormControlElementById(shadow_root1, "t3");
+  WebFormControlElement t4 = GetFormControlElementById(shadow_root1, "t4");
+  WebFormControlElement t5 = GetFormControlElementById(shadow_root1, "t5");
+  WebFormControlElement t6 = GetFormControlElementById(shadow_root1, "t6");
+  WebFormControlElement t7 = GetFormControlElementById(shadow_root2, "t7");
+
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t2.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t3.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t4.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t5.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t6.GetOwningFormForAutofill(), f1);
+  EXPECT_EQ(t7.GetOwningFormForAutofill(), f4);
+}
+
+TEST_F(WebFormControlElementGetOwningFormForAutofillTest,
+       GetOwningFormInLightDomWithSlots) {
+  const Document& document = GetDocument();
+  document.body()->setHTMLUnsafe(R"(
+    <form id=f>
+      <div>
+        <template shadowrootmode=open>
+          <form id=f_unowned>
+            <slot></slot>
+          </form>
+        </template>
+        <input id=t1>
+      </div>
+    </form>)");
+  WebFormElement f = GetFormElementById(document, "f");
+  WebFormControlElement t1 = GetFormControlElementById(document, "t1");
+  EXPECT_EQ(t1.GetOwningFormForAutofill(), f);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index 1cd39176c..ba35212 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -229,7 +229,8 @@
 
   if (!provider && use_shared_bitmap_provider) {
     provider = CanvasResourceProvider::CreateSharedBitmapProvider(
-        Size(), sk_color_type, alpha_type, sk_color_space, kShouldInitialize,
+        Size(), sk_color_type, alpha_type,
+        SkColorSpaceToGfxColorSpace(sk_color_space), kShouldInitialize,
         SharedGpuContext::SharedImageInterfaceProvider(), this);
   }
   if (!provider) {
@@ -267,7 +268,8 @@
     // If we can use the gpu and low latency is enabled, we will try to use a
     // SwapChain if possible.
     provider = CanvasResourceProvider::CreateSwapChainProvider(
-        Size(), sk_color_type, alpha_type, sk_color_space, kShouldInitialize,
+        Size(), sk_color_type, alpha_type,
+        SkColorSpaceToGfxColorSpace(sk_color_space), kShouldInitialize,
         SharedGpuContext::ContextProviderWrapper(), this);
     // If SwapChain failed or it was not possible, we will try a SharedImage
     // with a set of flags trying to add Usage Display and Usage Scanout and
@@ -323,7 +325,8 @@
 
   if (!provider && use_shared_bitmap_provider) {
     provider = CanvasResourceProvider::CreateSharedBitmapProvider(
-        Size(), sk_color_type, alpha_type, sk_color_space, kShouldInitialize,
+        Size(), sk_color_type, alpha_type,
+        SkColorSpaceToGfxColorSpace(sk_color_space), kShouldInitialize,
         SharedGpuContext::SharedImageInterfaceProvider(), this);
   }
   if (!provider) {
diff --git a/third_party/blink/renderer/core/html/forms/listed_element.cc b/third_party/blink/renderer/core/html/forms/listed_element.cc
index 2679324..aba4216a 100644
--- a/third_party/blink/renderer/core/html/forms/listed_element.cc
+++ b/third_party/blink/renderer/core/html/forms/listed_element.cc
@@ -29,17 +29,20 @@
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/focus_params.h"
 #include "third_party/blink/renderer/core/dom/id_target_observer.h"
+#include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/dom/node_traversal.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/html/custom/element_internals.h"
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
+#include "third_party/blink/renderer/core/html/forms/html_button_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/core/html/forms/validity_state.h"
 #include "third_party/blink/renderer/core/html/html_object_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
@@ -49,8 +52,6 @@
 #include "third_party/blink/renderer/core/page/validation_message_client.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/text/bidi_paragraph.h"
-#include "third_party/blink/renderer/core/html/forms/html_button_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -715,6 +716,28 @@
   }
 }
 
+HTMLFormElement* ListedElement::GetOwningFormForAutofill() const {
+  // The owning form is the furthest ancestor form element, if there is one.
+  HTMLFormElement* owner = nullptr;
+  // Look for ancestors of the associated form of this element inside the same
+  // tree.
+  for (Node* ancestor = Form(); ancestor; ancestor = ancestor->parentNode()) {
+    if (auto* form = DynamicTo<HTMLFormElement>(ancestor)) {
+      owner = form;
+    }
+  }
+
+  // If this element is inside Shadow DOM, also consider ancestors of this
+  // element.
+  for (Node* ancestor = ToHTMLElement().OwnerShadowHost(); ancestor;
+       ancestor = ancestor->ParentOrShadowHostNode()) {
+    if (auto* form = DynamicTo<HTMLFormElement>(ancestor)) {
+      owner = form;
+    }
+  }
+  return owner;
+}
+
 void ListedElement::SetFormAttributeTargetObserver(
     FormAttributeTargetObserver* new_observer) {
   if (form_attribute_target_observer_)
diff --git a/third_party/blink/renderer/core/html/forms/listed_element.h b/third_party/blink/renderer/core/html/forms/listed_element.h
index 9f405e9..860a68d 100644
--- a/third_party/blink/renderer/core/html/forms/listed_element.h
+++ b/third_party/blink/renderer/core/html/forms/listed_element.h
@@ -170,6 +170,15 @@
   void NotifyFormStateChanged();
   // This should be called in Element::FinishParsingChildren() override.
   void TakeStateAndRestore();
+  // Returns the form that owns this element according to Autofill's definition
+  // of ownership, or nullptr if no form owns it. The form that owns this
+  // element is:
+  // - if this element is associated to a form, the furthest shadow-including
+  //   form ancestor of that form,
+  // - otherwise, the furthest shadow-including form ancestor of this element.
+  // For the definition of ownership in Autofill, see
+  // //components/autofill/content/renderer/README.md.
+  HTMLFormElement* GetOwningFormForAutofill() const;
 
   void Trace(Visitor*) const override;
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index 3acb3bf..db2904f 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -3639,8 +3639,22 @@
       name = css_animation->animationName();
     }
 
+    auto property_pass_filter = [](const PropertyHandle& property) {
+      return property.IsCSSProperty();
+    };
+
+    EffectStack& effect_stack = element_animations->GetEffectStack();
+    HashSet<PropertyHandle> affected_properties =
+        effect_stack.AffectedProperties(
+            KeyframeEffect::Priority::kDefaultPriority);
     ActiveInterpolationsMap active_interpolations =
-        effect->InterpolationsForCommitStyles();
+        EffectStack::ActiveInterpolations(
+            &effect_stack,
+            /*new_animations=*/nullptr,
+            /*suppressed_animations=*/nullptr,
+            KeyframeEffect::Priority::kDefaultPriority, property_pass_filter,
+            effect);
+
     PropertyHandleSet animation_properties = effect->Model()->Properties();
     MutableCSSPropertyValueSet* property_values =
         MakeGarbageCollected<MutableCSSPropertyValueSet>(
diff --git a/third_party/blink/renderer/core/layout/inline/fragment_items.cc b/third_party/blink/renderer/core/layout/inline/fragment_items.cc
index bcfa987..8e26fc7 100644
--- a/third_party/blink/renderer/core/layout/inline/fragment_items.cc
+++ b/third_party/blink/renderer/core/layout/inline/fragment_items.cc
@@ -109,6 +109,12 @@
         DCHECK_EQ(item.DeltaToNextForSameLayoutObject(), 0u);
         item.SetFragmentId(line_fragment_id++);
         continue;
+      } else if (item.IsEllipsis() &&
+                 item.GetLayoutObject() == fragment.GetLayoutObject()) {
+        DCHECK(
+            RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled());
+        // Line-clamp ellipsis
+        continue;
       } else if (!found_inflow_content) {
         // Resumed floats may take up all the space in the containing block
         // fragment, leaving no room for actual content inside the inline
diff --git a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
index 99f287e..adc5c2f 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
@@ -341,14 +341,17 @@
   LineClampData line_clamp_data = space.GetLineClampData();
   if (line_clamp_data.IsLineClampContext()) {
     if (!line_info->IsBlockInInline() && line_clamp_data.IsAtClampPoint()) {
-      return LineClampState::kEllipsize;
+      if (RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled()) {
+        return LineClampState::kLineClampEllipsis;
+      }
+      return LineClampState::kTextOverflowEllipsis;
     }
     if (line_clamp_data.ShouldHideForPaint()) {
       return LineClampState::kHide;
     }
   } else if (!line_info->IsBlockInInline() && line_info->HasOverflow() &&
              node_.GetLayoutBlockFlow()->ShouldTruncateOverflowingText()) {
-    return LineClampState::kEllipsize;
+    return LineClampState::kTextOverflowEllipsis;
   }
 
   return LineClampState::kShow;
@@ -416,7 +419,7 @@
   //  - If we've reached the line-clamp limit.
   const LineClampState line_clamp_state =
       GetLineClampState(line_info, line_box_metrics.LineHeight());
-  if (line_clamp_state == LineClampState::kEllipsize) [[unlikely]] {
+  if (line_clamp_state == LineClampState::kTextOverflowEllipsis) [[unlikely]] {
     DCHECK(!line_info->IsBlockInInline());
     LineTruncator truncator(*line_info);
     auto* input =
@@ -550,9 +553,10 @@
       space.ShouldTextBoxTrimFragmentainerStart() ||
       space.ShouldTextBoxTrimFragmentainerEnd() ||
       space.ShouldTextBoxTrimInsideWhenLineClamp()) [[unlikely]] {
-    bool is_truncated = line_clamp_state == LineClampState::kEllipsize ||
-                        space.GetLineClampData().state ==
-                            LineClampData::kMeasureLinesUntilBfcOffset;
+    LineClampData line_clamp_data = space.GetLineClampData();
+    bool is_truncated =
+        line_clamp_data.IsAtClampPoint() ||
+        line_clamp_data.state == LineClampData::kMeasureLinesUntilBfcOffset;
     ApplyTextBoxTrim(*line_info, is_truncated);
   }
 
@@ -1012,6 +1016,26 @@
   return true;
 }
 
+LayoutUnit InlineLayoutAlgorithm::SetupLineClampEllipsis() {
+  DCHECK(RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled());
+  const Font& font = node_.Style().GetFont();
+  const SimpleFontData* font_data = font.PrimaryFont();
+  DCHECK(font_data);
+  String ellipsis_text =
+      font_data && font_data->GlyphForCharacter(kHorizontalEllipsisCharacter)
+          ? String(base::span_from_ref(kHorizontalEllipsisCharacter))
+          : String(u"...");
+  HarfBuzzShaper shaper(ellipsis_text);
+  const ShapeResult* shape_result = shaper.Shape(&font, Node().BaseDirection());
+  DCHECK(shape_result);
+
+  FontHeight text_metrics = font_data->GetFontMetrics().GetFontHeight(
+      Node().Style().GetFontBaseline());
+
+  line_clamp_ellipsis_.emplace(ellipsis_text, shape_result, text_metrics);
+  return shape_result->SnappedWidth();
+}
+
 const LayoutResult* InlineLayoutAlgorithm::Layout() {
   const auto& constraint_space = GetConstraintSpace();
   ExclusionSpace initial_exclusion_space(constraint_space.GetExclusionSpace());
@@ -1157,7 +1181,22 @@
                                leading_floats, break_token,
                                column_spanner_path_, &GetExclusionSpace());
       line_break_strategy.SetupLineBreaker(context_, line_breaker);
+      if (RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled() &&
+          constraint_space.GetLineClampData().IsAtClampPoint()) {
+        LayoutUnit ellipsis_width = SetupLineClampEllipsis();
+        line_breaker.SetLineClampEllipsisWidth(ellipsis_width);
+      }
+
       line_breaker.NextLine(&line_info);
+
+      // The line-clamp ellipsis is not created as an InlineItemResult by the
+      // line breaker, but is instead appended afterwards in the
+      // LogicalLineBuilder. Therefore, we need to make sure to not add it in
+      // empty lines or in block-in-inlines.
+      if (line_clamp_ellipsis_.has_value() &&
+          (line_info.IsEmptyLine() || line_info.IsBlockInInline())) {
+        line_clamp_ellipsis_.reset();
+      }
     }
 
     if (Node().IsInitialLetterBox()) [[unlikely]] {
diff --git a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.h b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.h
index 2c75953..ddb0f43f 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.h
@@ -68,6 +68,18 @@
                           InlineItemResult*,
                           LogicalLineItems* line_box);
 
+  struct LineClampEllipsis {
+    STACK_ALLOCATED();
+
+   public:
+    String text;
+    const ShapeResult* shape_result;
+    FontHeight text_metrics;
+  };
+  const std::optional<LineClampEllipsis>& GetLineClampEllipsis() {
+    return line_clamp_ellipsis_;
+  }
+
  private:
   friend class LineWidthsTest;
 
@@ -103,9 +115,12 @@
       const FontHeight& line_box_metrics,
       std::optional<FontHeight> annotation_font_height);
 
+  LayoutUnit SetupLineClampEllipsis();
+
   enum class LineClampState {
     kShow,
-    kEllipsize,
+    kLineClampEllipsis,
+    kTextOverflowEllipsis,
     kHide,
   };
   LineClampState GetLineClampState(const LineInfo*,
@@ -119,6 +134,8 @@
   MarginStrut end_margin_strut_;
   std::optional<int> lines_until_clamp_;
 
+  std::optional<LineClampEllipsis> line_clamp_ellipsis_;
+
   FontBaseline baseline_type_ = FontBaseline::kAlphabeticBaseline;
 
   // True if in quirks or limited-quirks mode, which require line-height quirks.
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.cc b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
index 16b52e4a..1291702 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -412,9 +412,19 @@
 void LineBreaker::UpdateAvailableWidth() {
   LayoutUnit available_width;
   if (override_available_width_) [[unlikely]] {
-    available_width = override_available_width_;
+    // If we have an overridden width (e.g. because of text-wrap), the
+    // line-clamp ellipsis should only cut into it when the overridden available
+    // width plus the ellipsis width overflow the available inline size.
+    if (line_clamp_ellipsis_width_) {
+      available_width = std::min(
+          line_opportunity_.AvailableInlineSize() - line_clamp_ellipsis_width_,
+          override_available_width_);
+    } else {
+      available_width = override_available_width_;
+    }
   } else {
-    available_width = line_opportunity_.AvailableInlineSize();
+    available_width =
+        line_opportunity_.AvailableInlineSize() - line_clamp_ellipsis_width_;
   }
   // Make sure it's at least the initial size, which is usually 0 but not so
   // when `box-decoration-break: clone`.
@@ -1065,8 +1075,9 @@
   // Negative margins can make the position negative, but the inline size is
   // always positive or 0.
   LayoutUnit available_width = AvailableWidth();
-  line_info->SetWidth(available_width,
-                      position_ + cloned_box_decorations_end_size_);
+  line_info->SetWidth(available_width + line_clamp_ellipsis_width_,
+                      position_ + cloned_box_decorations_end_size_ +
+                          line_clamp_ellipsis_width_);
   line_info->SetBfcOffset(
       {line_opportunity_.line_left_offset, line_opportunity_.bfc_block_offset});
   if (mode_ == LineBreakerMode::kContent) {
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.h b/third_party/blink/renderer/core/layout/inline/line_breaker.h
index c4de5bf..8f993af 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.h
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.h
@@ -83,6 +83,12 @@
   // Specify to break at the `offset` rather than the available width.
   void SetBreakAt(const LineBreakPoint& offset);
 
+  void SetLineClampEllipsisWidth(LayoutUnit width) {
+    DCHECK(RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled());
+    line_clamp_ellipsis_width_ = width;
+    UpdateAvailableWidth();
+  }
+
   // Computing |LineBreakerMode::kMinContent| with |MaxSizeCache| caches
   // information that can help computing |kMaxContent|. It is recommended to set
   // this when computing both |kMinContent| and |kMaxContent|.
@@ -504,6 +510,8 @@
   // This has a valid object if is_svg_text_.
   std::unique_ptr<ResolvedTextLayoutAttributesIterator> svg_resolved_iterator_;
 
+  LayoutUnit line_clamp_ellipsis_width_;
+
   // This member is available after calling SetInputRange().
   const LineBreaker* parent_breaker_ = nullptr;
 };
diff --git a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
index 8d05265..43592f61 100644
--- a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
+++ b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
@@ -74,6 +74,29 @@
 
   box_states_->OnEndPlaceItems(constraint_space_, line_box, baseline_type_);
 
+  if (main_line_helper) {
+    if (auto& ellipsis_data = main_line_helper->GetLineClampEllipsis()) {
+      DCHECK(RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled());
+      const ShapeResultView* shape_result_view =
+          ShapeResultView::Create(ellipsis_data->shape_result);
+      FontHeight text_metrics = ellipsis_data->text_metrics;
+
+      line_box->AddChild(*node_.GetLayoutBlockFlow(),
+                         StyleVariant::kStandardEllipsis, shape_result_view,
+                         ellipsis_data->text,
+                         LogicalRect(LayoutUnit(), -text_metrics.ascent,
+                                     shape_result_view->SnappedWidth(),
+                                     text_metrics.LineHeight()),
+                         // TODO(abotella): The ellipsis' bidi level is pending
+                         // discussion at
+                         // https://github.com/w3c/csswg-drafts/issues/10844.
+                         // Meanwhile we use the paragraph's embedding level for
+                         // compatibility with the previous behavior of
+                         // -webkit-line-clamp.
+                         static_cast<UBiDiLevel>(line_info->BaseDirection()));
+    }
+  }
+
   if (node_.IsBidiEnabled()) [[unlikely]] {
     box_states_->PrepareForReorder(line_box);
     BidiReorder(line_info->BaseDirection(), line_box,
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 8519393..4542138 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -2597,9 +2597,18 @@
     case StyleVariant::kStandardEllipsis:
       // The ellipsis is styled according to the line style.
       // https://www.w3.org/TR/css-overflow-3/#ellipsing-details
-      DCHECK(IsInline());
-      if (const LayoutObject* block = ContainingBlock()) {
-        return block->StyleRef();
+      // For the line-clamp ellipsis, we can end up with a FragmentItem whose
+      // LayoutObject is the containing LayoutBlockFlow, because there is no
+      // inline layout object that it belongs to. In that case, we must also use
+      // the line style, which is this LayoutObject's style.
+      DCHECK(
+          IsInline() ||
+          (RuntimeEnabledFeatures::CSSLineClampLineBreakingEllipsisEnabled() &&
+           IsLayoutBlockFlow() && ChildrenInline()));
+      if (!IsLayoutBlockFlow()) {
+        if (const LayoutObject* block = ContainingBlock()) {
+          return block->StyleRef();
+        }
       }
       return StyleRef();
     case StyleVariant::kFirstLineEllipsis:
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 9ef6c9e..359a0d1 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -568,7 +568,8 @@
     base::WeakPtr<CanvasResourceDispatcher> dispatcher_weakptr =
         GetOrCreateResourceDispatcher()->GetWeakPtr();
     provider = CanvasResourceProvider::CreateSharedBitmapProvider(
-        Size(), sk_color_type, alpha_type, sk_color_space,
+        Size(), sk_color_type, alpha_type,
+        SkColorSpaceToGfxColorSpace(sk_color_space),
         CanvasResourceProvider::ShouldInitialize::kCallClear,
         SharedGpuContext::SharedImageInterfaceProvider(), this);
   }
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc
index cad0912..67eae56 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -106,7 +106,7 @@
   if (auto* form_control = DynamicTo<HTMLFormControlElement>(node)) {
     data.form_control_type = form_control->FormControlType();
     data.field_renderer_id = form_control->GetDomNodeId();
-    if (auto* form = form_control->Form()) {
+    if (auto* form = form_control->GetOwningFormForAutofill()) {
       data.form_renderer_id = form->GetDomNodeId();
     } else {
       data.form_renderer_id = 0;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.idl b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.idl
index 259d8821..c27faa38 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.idl
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.idl
@@ -33,12 +33,12 @@
     [NoAllocDirectCall] void resetTransform();
 
     // compositing
-    attribute unrestricted double globalAlpha; // (default 1.0)
+    [NoAllocDirectCall=Setter] attribute unrestricted double globalAlpha; // (default 1.0)
     [HighEntropy] attribute DOMString globalCompositeOperation; // (default source-over)
     [MeasureAs=Canvas2DFilter, SetterCallWith=ScriptState] attribute (DOMString or CanvasFilter)? filter; // (default 'none')
 
     // image smoothing
-    attribute boolean imageSmoothingEnabled; // (default True)
+    [NoAllocDirectCall=Setter] attribute boolean imageSmoothingEnabled; // (default True)
     [MeasureAs=Canvas2DImageSmoothingQuality2] attribute ImageSmoothingQuality imageSmoothingQuality; // (default "low")
 
     // colors and styles (see also the CanvasDrawingStyles interface)
@@ -50,9 +50,9 @@
     [RaisesException] CanvasPattern? createPattern(CanvasImageSource image, [LegacyNullToEmptyString] DOMString repetitionType);
 
     // shadows
-    [HighEntropy] attribute unrestricted double shadowOffsetX;
-    [HighEntropy] attribute unrestricted double shadowOffsetY;
-    [HighEntropy] attribute unrestricted double shadowBlur;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowOffsetX;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowOffsetY;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowBlur;
     [HighEntropy] attribute DOMString shadowColor;
 
     // CanvasRect interface
@@ -109,12 +109,12 @@
     [NoAllocDirectCall=Setter] attribute unrestricted double lineWidth; // (default 1)
     attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
     attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
-    attribute unrestricted double miterLimit; // (default 10)
+    [NoAllocDirectCall=Setter] attribute unrestricted double miterLimit; // (default 10)
 
     // dashed lines
     void setLineDash(sequence<unrestricted double> dash);
     sequence<unrestricted double> getLineDash();
-    attribute unrestricted double lineDashOffset;
+    [NoAllocDirectCall=Setter] attribute unrestricted double lineDashOffset;
 
     // text
     [HighEntropy] attribute DOMString font; // (default 10px sans-serif)
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
index 2c3044b..4a2e4f8 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.idl
@@ -28,12 +28,12 @@
 
 
     // compositing
-    attribute unrestricted double globalAlpha; // (default 1.0)
+    [NoAllocDirectCall=Setter] attribute unrestricted double globalAlpha; // (default 1.0)
     [HighEntropy] attribute DOMString globalCompositeOperation; // (default source-over)
     [MeasureAs=Canvas2DFilter, SetterCallWith=ScriptState] attribute (DOMString or CanvasFilter)? filter; // (default 'none')
 
     // image smoothing
-    attribute boolean imageSmoothingEnabled; // (default True)
+    [NoAllocDirectCall=Setter] attribute boolean imageSmoothingEnabled; // (default True)
     [RuntimeEnabled=CanvasImageSmoothing, MeasureAs=Canvas2DImageSmoothingQuality2] attribute ImageSmoothingQuality imageSmoothingQuality; // (default "low")
 
     // colors and styles (see also the CanvasDrawingStyles interface)
@@ -45,9 +45,9 @@
     CanvasGradient createConicGradient(double startAngle, double cx, double cy);
 
     // shadows
-    [HighEntropy] attribute unrestricted double shadowOffsetX;
-    [HighEntropy] attribute unrestricted double shadowOffsetY;
-    [HighEntropy] attribute unrestricted double shadowBlur;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowOffsetX;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowOffsetY;
+    [HighEntropy, NoAllocDirectCall=Setter] attribute unrestricted double shadowBlur;
     [HighEntropy] attribute DOMString shadowColor;
 
     // rects
@@ -84,14 +84,14 @@
                                                                                                       CanvasImageSource image);
     // FIXME: factor out to CanvasDrawingStyles
     // line caps/joins
-    attribute unrestricted double lineWidth; // (default 1)
+    [NoAllocDirectCall=Setter] attribute unrestricted double lineWidth; // (default 1)
     attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
     attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
-    attribute unrestricted double miterLimit; // (default 10)
+    [NoAllocDirectCall=Setter] attribute unrestricted double miterLimit; // (default 10)
 
     // dashed lines
     void setLineDash(sequence<unrestricted double> dash);
     sequence<unrestricted double> getLineDash();
-    attribute unrestricted double lineDashOffset;
+    [NoAllocDirectCall=Setter] attribute unrestricted double lineDashOffset;
 };
 PaintRenderingContext2D includes CanvasPath;
diff --git a/third_party/blink/renderer/modules/ml/BUILD.gn b/third_party/blink/renderer/modules/ml/BUILD.gn
index 9cf2304d5..c0b8a2f 100644
--- a/third_party/blink/renderer/modules/ml/BUILD.gn
+++ b/third_party/blink/renderer/modules/ml/BUILD.gn
@@ -11,8 +11,6 @@
     "ml.h",
     "ml_context.cc",
     "ml_context.h",
-    "ml_trace.cc",
-    "ml_trace.h",
     "navigator_ml.cc",
     "navigator_ml.h",
     "webnn/allow_shared_buffer_source_util.h",
@@ -45,7 +43,6 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "ml_trace_unittest.cc",
     "webnn/ml_graph_builder_test_utils.cc",
     "webnn/ml_graph_builder_test_utils.h",
     "webnn/ml_graph_test.cc",
diff --git a/third_party/blink/renderer/modules/ml/ml.cc b/third_party/blink/renderer/modules/ml/ml.cc
index 78b3f165..044323e 100644
--- a/third_party/blink/renderer/modules/ml/ml.cc
+++ b/third_party/blink/renderer/modules/ml/ml.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/ml/ml.h"
 
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_context_options.h"
@@ -63,7 +64,7 @@
 ScriptPromise<MLContext> ML::createContext(ScriptState* script_state,
                                            MLContextOptions* options,
                                            ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("ML::createContext");
+  webnn::ScopedTrace scoped_trace("ML::createContext");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -86,7 +87,7 @@
           ConvertBlinkPowerPreferenceToMojo(options->powerPreference())),
       WTF::BindOnce(
           [](ML* ml, ScriptPromiseResolver<MLContext>* resolver,
-             MLContextOptions* options,
+             MLContextOptions* options, webnn::ScopedTrace scoped_trace,
              webnn::mojom::blink::CreateContextResultPtr result) {
             ml->pending_resolvers_.erase(resolver);
 
@@ -109,7 +110,7 @@
                 std::move(result->get_success())));
           },
           WrapPersistent(this), WrapPersistent(resolver),
-          WrapPersistent(options)));
+          WrapPersistent(options), std::move(scoped_trace)));
 
   return promise;
 }
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc
index 9781833..ef70a0c 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.cc
+++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -14,6 +14,7 @@
 #include "services/webnn/public/cpp/operand_descriptor.h"
 #include "services/webnn/public/cpp/supported_data_types.h"
 #include "services/webnn/public/cpp/webnn_errors.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/features.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_graph_builder.mojom-blink.h"
@@ -51,7 +52,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_where_support_limits.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_error.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h"
@@ -966,7 +966,7 @@
     ScriptState* script_state,
     const MLTensorDescriptor* descriptor,
     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::createTensor");
+  webnn::ScopedTrace scoped_trace("MLContext::createTensor");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -1038,7 +1038,7 @@
                             MLTensor* dst_tensor,
                             AllowSharedBufferSource* src_data,
                             ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::writeTensor");
+  webnn::ScopedTrace scoped_trace("MLContext::writeTensor");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -1074,7 +1074,7 @@
     ScriptState* script_state,
     MLTensor* src_tensor,
     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::readTensor");
+  webnn::ScopedTrace scoped_trace("MLContext::readTensor");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -1102,7 +1102,7 @@
     MLTensor* src_tensor,
     AllowSharedBufferSource* dst_data,
     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::readTensor");
+  webnn::ScopedTrace scoped_trace("MLContext::readTensor");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -1127,7 +1127,7 @@
                          const MLNamedTensors& inputs,
                          const MLNamedTensors& outputs,
                          ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLContext::dispatch");
+  webnn::ScopedTrace scoped_trace("MLContext::dispatch");
   if (!script_state->ContextIsValid()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid script state");
@@ -1145,7 +1145,7 @@
 }
 
 void MLContext::DidCreateWebNNTensor(
-    ScopedMLTrace scoped_trace,
+    webnn::ScopedTrace scoped_trace,
     ScriptPromiseResolver<blink::MLTensor>* resolver,
     webnn::OperandDescriptor validated_descriptor,
     webnn::MLTensorUsage usage,
diff --git a/third_party/blink/renderer/modules/ml/ml_context.h b/third_party/blink/renderer/modules/ml/ml_context.h
index 3eacb0fb..9ae502d 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.h
+++ b/third_party/blink/renderer/modules/ml/ml_context.h
@@ -12,6 +12,7 @@
 #include "services/webnn/public/cpp/context_properties.h"
 #include "services/webnn/public/cpp/ml_tensor_usage.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_context.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom-blink-forward.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
@@ -24,7 +25,6 @@
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h"
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
 #include "third_party/blink/renderer/modules/ml/webnn/allow_shared_buffer_source_util.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -108,7 +108,7 @@
   // Close the `context_remote_` pipe because the context has been lost.
   void OnLost(uint32_t custom_reason, const std::string& description);
 
-  void DidCreateWebNNTensor(ScopedMLTrace scoped_trace,
+  void DidCreateWebNNTensor(webnn::ScopedTrace scoped_trace,
                             ScriptPromiseResolver<blink::MLTensor>* resolver,
                             webnn::OperandDescriptor validated_descriptor,
                             webnn::MLTensorUsage usage,
diff --git a/third_party/blink/renderer/modules/ml/ml_trace.h b/third_party/blink/renderer/modules/ml/ml_trace.h
deleted file mode 100644
index 6fb140e..0000000
--- a/third_party/blink/renderer/modules/ml/ml_trace.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_TRACE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_TRACE_H_
-
-#include <memory>
-#include <optional>
-
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-// The trace starts when an object of this class is created, and ends when
-// the object goes out scope.
-// You should 'std::move' this object when binding callbacks. The trace ends
-// if the callback is destroyed (even if it's not run).
-//
-// Methods in this class is safe to be called from any threads.
-class MODULES_EXPORT ScopedMLTrace {
- public:
-  // Create a ScopedAsyncTrace instance.
-  //
-  // Important note: Use literal strings only. See trace_event_common.h.
-  explicit ScopedMLTrace(const char* name);
-  ScopedMLTrace(ScopedMLTrace&& other);
-  ScopedMLTrace& operator=(ScopedMLTrace&& other);
-  ScopedMLTrace(const ScopedMLTrace&) = delete;
-  ScopedMLTrace& operator=(const ScopedMLTrace&) = delete;
-  ~ScopedMLTrace();
-
-  // Starts a nested sub-trace in the current trace. The next AddStep() call
-  // will mark the end of the previous sub-trace.
-  void AddStep(const char* step_name);
-
- private:
-  ScopedMLTrace(const char* name, uint64_t id);
-
-  const char* name_;
-
-  // The trace ID.
-  //
-  // An 'std::nullopt' means the trace has been transferred to another
-  // 'ScopedMLTrace' object, and stops 'this''s destruction from ending the
-  // trace.
-  std::optional<uint64_t> id_;
-  std::unique_ptr<ScopedMLTrace> step_;
-};
-
-}  // namespace blink
-
-namespace WTF {
-
-template <>
-struct CrossThreadCopier<blink::ScopedMLTrace>
-    : public WTF::CrossThreadCopierByValuePassThrough<blink::ScopedMLTrace> {};
-
-}  // namespace WTF
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_ML_TRACE_H_
diff --git a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc b/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
deleted file mode 100644
index b25e2189..0000000
--- a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/json/json_reader.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/bind_post_task.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/trace_event/trace_buffer.h"
-#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_log.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/testing/task_environment.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-class ScopedMLTraceTest : public testing::Test {
- public:
-  ScopedMLTraceTest() = default;
-
-  ~ScopedMLTraceTest() override = default;
-
-  void SetUp() override {
-    test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
-  }
-
-  void TearDown() override { base::trace_event::TraceLog::ResetForTesting(); }
-
- protected:
-  void StartTracing(const std::string& filter) {
-    base::trace_event::TraceLog::GetInstance()->SetEnabled(
-        base::trace_event::TraceConfig(filter,
-                                       base::trace_event::RECORD_UNTIL_FULL));
-  }
-
-  static void TraceDataCb(
-      base::OnceClosure quit_closure,
-      base::trace_event::TraceResultBuffer::SimpleOutput* json_output,
-      const scoped_refptr<base::RefCountedString>& json_events_str,
-      bool has_more_events) {
-    base::trace_event::TraceResultBuffer trace_buffer;
-    trace_buffer.SetOutputCallback(json_output->GetCallback());
-    trace_buffer.Start();
-    trace_buffer.AddFragment(json_events_str->as_string());
-    trace_buffer.Finish();
-    if (!has_more_events) {
-      std::move(quit_closure).Run();
-    }
-  }
-
-  // End tracing, return tracing data in a map of event
-  // name->(begin_event_counts, end_event_counts)
-  std::map<std::string, std::pair<int, int>> EndTracing() {
-    std::map<std::string, std::pair<int, int>> event_counts;
-    base::trace_event::TraceResultBuffer::SimpleOutput json_data;
-    base::trace_event::TraceLog::GetInstance()->SetDisabled();
-    base::RunLoop run_loop;
-    base::trace_event::TraceLog::GetInstance()->Flush(base::BindRepeating(
-        &ScopedMLTraceTest::TraceDataCb, run_loop.QuitClosure(), &json_data));
-    run_loop.Run();
-
-    auto parsed_json =
-        base::JSONReader::ReadAndReturnValueWithError(json_data.json_output);
-    CHECK(parsed_json.has_value())
-        << "JSON parsing failed (" << parsed_json.error().message
-        << ") JSON data:" << std::endl
-        << json_data.json_output;
-
-    CHECK(parsed_json->is_list());
-    for (const base::Value& entry : parsed_json->GetList()) {
-      const auto& dict = entry.GetDict();
-      const std::string* name = dict.FindString("name");
-      CHECK(name);
-      const std::string* trace_type = dict.FindString("ph");
-      CHECK(trace_type);
-      // Count both the "BEGIN" and "END" traces.
-      if (*trace_type == "n") {
-        ((event_counts)[*name].first)++;
-        ((event_counts)[*name].second)++;
-      } else if (*trace_type != "E" && *trace_type != "e") {
-        ((event_counts)[*name].first)++;
-      } else {
-        ((event_counts)[*name].second)++;
-      }
-    }
-    return event_counts;
-  }
-
-  // The task runner we use for posting tasks.
-  test::TaskEnvironment task_environment_;
-  scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
-};
-
-TEST_F(ScopedMLTraceTest, SingleScopeWithoutStep) {
-  {
-    // Check the behavior without move. Both begin/end event should be seen.
-    StartTracing("webnn");
-    { ScopedMLTrace scoped_trace1("Method1"); }
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Check the behavior with move assign. Both begin/end event should be seen.
-    StartTracing("webnn");
-    {
-      ScopedMLTrace scoped_trace1("Method1");
-      ScopedMLTrace scoped_trace2 = std::move(scoped_trace1);
-    }
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Check the behavior with move ctor, similar as move assign.
-    StartTracing("webnn");
-    {
-      ScopedMLTrace scoped_trace1("Method1");
-      ScopedMLTrace scoped_trace2(std::move(scoped_trace1));
-    }
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Move should not trigger an immediate end event.
-    StartTracing("webnn");
-    {
-      ScopedMLTrace scoped_trace1("Method1");
-      ScopedMLTrace scoped_trace2 = std::move(scoped_trace1);
-      auto event_counts = EndTracing();
-      auto [method_begins, method_ends] = event_counts.at("Method1");
-      EXPECT_EQ(1, method_begins);
-      EXPECT_EQ(0, method_ends);
-    }
-  }
-}
-
-// Both main trace and sub-trace should have pairing begin/end.
-TEST_F(ScopedMLTraceTest, SingleScopeWithStep) {
-  StartTracing("webnn");
-  {
-    ScopedMLTrace scoped_trace1("Method1");
-    scoped_trace1.AddStep("Step1");
-    ScopedMLTrace scoped_trace2 = std::move(scoped_trace1);
-  }
-  auto event_counts = EndTracing();
-
-  auto [method_begins, method_ends] = event_counts.at("Method1");
-  auto [step_begins, step_ends] = event_counts.at("Step1");
-  EXPECT_EQ(1, method_begins);
-  EXPECT_EQ(1, method_ends);
-  EXPECT_EQ(1, step_begins);
-  EXPECT_EQ(1, step_ends);
-}
-
-// Multiple steps should results in multiple begin/end pairs.
-TEST_F(ScopedMLTraceTest, MultipleAddSteps) {
-  StartTracing("webnn");
-  {
-    ScopedMLTrace scoped_trace1("Method1");
-    scoped_trace1.AddStep("Step1");
-    scoped_trace1.AddStep("Step2");
-    ScopedMLTrace scoped_trace2(std::move(scoped_trace1));
-    scoped_trace2.AddStep("Step3");
-  }
-  auto event_counts = EndTracing();
-
-  auto [method1_begins, method1_ends] = event_counts.at("Method1");
-  auto [step1_begins, step1_ends] = event_counts.at("Step1");
-  auto [step2_begins, step2_ends] = event_counts.at("Step2");
-  auto [step3_begins, step3_ends] = event_counts.at("Step3");
-  EXPECT_EQ(1, method1_begins);
-  EXPECT_EQ(1, method1_ends);
-  EXPECT_EQ(1, step1_begins);
-  EXPECT_EQ(1, step1_ends);
-  EXPECT_EQ(1, step2_begins);
-  EXPECT_EQ(1, step2_ends);
-  EXPECT_EQ(1, step3_begins);
-  EXPECT_EQ(1, step3_ends);
-}
-
-// Nesting top-level traces should have pairing begin/end.
-TEST_F(ScopedMLTraceTest, MultipleNestedTraces) {
-  StartTracing("webnn");
-  {
-    ScopedMLTrace scoped_trace1("Method1");
-    { ScopedMLTrace scoped_trace2("Method2"); }
-  }
-  auto event_counts = EndTracing();
-
-  auto [method1_begins, method1_ends] = event_counts.at("Method1");
-  auto [method2_begins, method2_ends] = event_counts.at("Method2");
-  EXPECT_EQ(1, method1_begins);
-  EXPECT_EQ(1, method1_ends);
-  EXPECT_EQ(1, method2_begins);
-  EXPECT_EQ(1, method2_ends);
-}
-
-// Trace handle should be passed correct across function boundaries.
-TEST_F(ScopedMLTraceTest, PassScopedTraceToFunc) {
-  {
-    // Pass to another function that does not add extra step.
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace1("Method1");
-    ([](ScopedMLTrace trace) {})(std::move(scoped_trace1));
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    method_ends = event_counts["Method1"].second;
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Pass to another function call that adds extra step.
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace2("Method1");
-    ([](ScopedMLTrace trace) { trace.AddStep("Step1"); })(
-        std::move(scoped_trace2));
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    auto [step_begins, step_ends] = event_counts.at("Step1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-    EXPECT_EQ(1, step_begins);
-    EXPECT_EQ(1, step_ends);
-  }
-}
-
-// Trace handle should be passed correctly by posting tasks.
-TEST_F(ScopedMLTraceTest, WorksWithPostCrossThreadTask) {
-  {
-    // Post to another thread that does not add extra step.
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace1("Method1");
-    PostCrossThreadTask(*test_task_runner_, FROM_HERE,
-                        CrossThreadBindOnce([](ScopedMLTrace trace) {},
-                                            std::move(scoped_trace1)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Post to another thread that adds extra step.
-    base::trace_event::TraceLog::ResetForTesting();
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace2("Method1");
-    PostCrossThreadTask(
-        *test_task_runner_, FROM_HERE,
-        CrossThreadBindOnce([](ScopedMLTrace trace) { trace.AddStep("Step1"); },
-                            std::move(scoped_trace2)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    auto [step_begins, step_ends] = event_counts.at("Step1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-    EXPECT_EQ(1, step_begins);
-    EXPECT_EQ(1, step_ends);
-  }
-
-  {
-    // Add step first, and post to another thread without adding step.
-    base::trace_event::TraceLog::ResetForTesting();
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace3("Method1");
-    scoped_trace3.AddStep("Step1");
-    PostCrossThreadTask(*test_task_runner_, FROM_HERE,
-                        CrossThreadBindOnce([](ScopedMLTrace trace) {},
-                                            std::move(scoped_trace3)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    auto [step_begins, step_ends] = event_counts.at("Step1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-    EXPECT_EQ(1, step_begins);
-    EXPECT_EQ(1, step_ends);
-  }
-
-  {
-    // Add step first, and post to another thread that adds step.
-    base::trace_event::TraceLog::ResetForTesting();
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace4("Method1");
-    scoped_trace4.AddStep("Step1");
-    PostCrossThreadTask(
-        *test_task_runner_, FROM_HERE,
-        CrossThreadBindOnce([](ScopedMLTrace trace) { trace.AddStep("Step2"); },
-                            std::move(scoped_trace4)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    auto [step_begins, step_ends] = event_counts.at("Step1");
-    auto [step_in_task_begins, step_in_task_ends] = event_counts["Step2"];
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-    EXPECT_EQ(1, step_begins);
-    EXPECT_EQ(1, step_ends);
-    EXPECT_EQ(1, step_in_task_begins);
-    EXPECT_EQ(1, step_in_task_ends);
-  }
-}
-
-TEST_F(ScopedMLTraceTest, WorksWithBindOnce) {
-  {
-    // Invoke BindOnce without adding extra step.
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace1("Method1");
-    test_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce([](ScopedMLTrace trace) {}, std::move(scoped_trace1)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-  }
-
-  {
-    // Invoke BindOnce and add extra step.
-    StartTracing("webnn");
-    ScopedMLTrace scoped_trace2("Method1");
-    test_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce([](ScopedMLTrace trace) { trace.AddStep("Step1"); },
-                       std::move(scoped_trace2)));
-    test_task_runner_->RunUntilIdle();
-    auto event_counts = EndTracing();
-
-    auto [method_begins, method_ends] = event_counts.at("Method1");
-    auto [step_begins, step_ends] = event_counts.at("Step1");
-    EXPECT_EQ(1, method_begins);
-    EXPECT_EQ(1, method_ends);
-    EXPECT_EQ(1, step_begins);
-    EXPECT_EQ(1, step_ends);
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph.cc
index 2bc414e..a1d29d0e 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph.cc
@@ -153,7 +153,7 @@
   return output_constraints_;
 }
 
-void MLGraph::Dispatch(ScopedMLTrace scoped_trace,
+void MLGraph::Dispatch(webnn::ScopedTrace scoped_trace,
                        const MLNamedTensors& inputs,
                        const MLNamedTensors& outputs,
                        ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph.h
index ec62f70..5b8c84e6 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph.h
@@ -7,10 +7,10 @@
 
 #include "base/types/pass_key.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_graph.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_operand_descriptor.h"
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
@@ -67,7 +67,7 @@
   // This method validates the input and output MLNamedTensors against the
   // graph's input and output resources info and then executes the compiled
   // platform graph.
-  void Dispatch(ScopedMLTrace scoped_trace,
+  void Dispatch(webnn::ScopedTrace scoped_trace,
                 const MLNamedTensors& inputs,
                 const MLNamedTensors& outputs,
                 ExceptionState& exception_state);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index 540d4160..d282f218 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -18,6 +18,7 @@
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
 #include "services/webnn/public/cpp/webnn_errors.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/features.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_graph.mojom-blink.h"
@@ -1672,7 +1673,7 @@
                                     const MLOperandDescriptor* desc,
                                     AllowSharedBufferSource* buffer,
                                     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLGraphBuilder::constant");
+  webnn::ScopedTrace scoped_trace("MLGraphBuilder::constant");
   CHECK(buffer);
 
   THROW_AND_RETURN_IF_ERROR(ValidateGraphBuilderState(), nullptr);
@@ -3248,7 +3249,7 @@
     ScriptState* script_state,
     const MLNamedOperands& named_outputs,
     ExceptionState& exception_state) {
-  ScopedMLTrace scoped_trace("MLGraphBuilder::build");
+  webnn::ScopedTrace scoped_trace("MLGraphBuilder::build");
   base::expected<void, String> validation_result = ValidateGraphBuilderState();
   if (!validation_result.has_value()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
index 7f40c704..58a43be 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.cc
@@ -104,7 +104,7 @@
 }
 
 ScriptPromise<DOMArrayBuffer> MLTensor::ReadTensorImpl(
-    ScopedMLTrace scoped_trace,
+    webnn::ScopedTrace scoped_trace,
     ScriptState* script_state,
     ExceptionState& exception_state) {
   // Remote context gets automatically unbound when the execution context
@@ -129,7 +129,7 @@
 }
 
 ScriptPromise<IDLUndefined> MLTensor::ReadTensorImpl(
-    ScopedMLTrace scoped_trace,
+    webnn::ScopedTrace scoped_trace,
     ScriptState* script_state,
     AllowSharedBufferSource* dst_data,
     ExceptionState& exception_state) {
@@ -160,7 +160,7 @@
 }
 
 void MLTensor::OnDidReadTensor(
-    ScopedMLTrace scoped_trace,
+    webnn::ScopedTrace scoped_trace,
     ScriptPromiseResolver<DOMArrayBuffer>* resolver,
     base::ElapsedTimer read_tensor_timer,
     webnn::mojom::blink::ReadTensorResultPtr result) {
@@ -182,7 +182,7 @@
 }
 
 void MLTensor::OnDidReadTensorByob(
-    ScopedMLTrace scoped_trace,
+    webnn::ScopedTrace scoped_trace,
     ScriptPromiseResolver<IDLUndefined>* resolver,
     AllowSharedBufferSource* dst_data,
     base::ElapsedTimer read_tensor_timer,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
index 71eff37..82debb7 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_tensor.h
@@ -10,11 +10,11 @@
 #include "base/types/pass_key.h"
 #include "services/webnn/public/cpp/ml_tensor_usage.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom-blink.h"
 #include "services/webnn/public/mojom/webnn_tensor.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_operand_data_type.h"
-#include "third_party/blink/renderer/modules/ml/ml_trace.h"
 #include "third_party/blink/renderer/modules/ml/webnn/allow_shared_buffer_source_util.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -80,11 +80,11 @@
 
   // Read data from the MLTensor. The resolver should be resolved with a copy of
   // the tensor data. Otherwise, the resolver should be rejected accordingly.
-  ScriptPromise<DOMArrayBuffer> ReadTensorImpl(ScopedMLTrace scoped_trace,
+  ScriptPromise<DOMArrayBuffer> ReadTensorImpl(webnn::ScopedTrace scoped_trace,
                                                ScriptState* script_state,
                                                ExceptionState& exception_state);
 
-  ScriptPromise<IDLUndefined> ReadTensorImpl(ScopedMLTrace scoped_trace,
+  ScriptPromise<IDLUndefined> ReadTensorImpl(webnn::ScopedTrace scoped_trace,
                                              ScriptState* script_state,
                                              AllowSharedBufferSource* dst_data,
                                              ExceptionState& exception_state);
@@ -97,11 +97,11 @@
  private:
   // The callback of reading from `WebNNTensor` by calling hardware accelerated
   // OS machine learning APIs.
-  void OnDidReadTensor(ScopedMLTrace scoped_trace,
+  void OnDidReadTensor(webnn::ScopedTrace scoped_trace,
                        ScriptPromiseResolver<DOMArrayBuffer>* resolver,
                        base::ElapsedTimer read_tensor_timer,
                        webnn::mojom::blink::ReadTensorResultPtr result);
-  void OnDidReadTensorByob(ScopedMLTrace scoped_trace,
+  void OnDidReadTensorByob(webnn::ScopedTrace scoped_trace,
                            ScriptPromiseResolver<IDLUndefined>* resolver,
                            AllowSharedBufferSource* dst_data,
                            base::ElapsedTimer read_tensor_timer,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
index ff33724..d89aba85 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher_test.cc
@@ -124,7 +124,7 @@
     dispatcher_ = std::make_unique<MockCanvasResourceDispatcher>();
     resource_provider_ = CanvasResourceProvider::CreateSharedBitmapProvider(
         gfx::Size(kWidth, kHeight), kN32_SkColorType, kPremul_SkAlphaType,
-        SkColorSpace::MakeSRGB(),
+        gfx::ColorSpace::CreateSRGB(),
         CanvasResourceProvider::ShouldInitialize::kCallClear,
         test_web_shared_image_interface_provider_.get());
   }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index acc82f1..24fb8f05 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1076,7 +1076,7 @@
     gfx::Size size,
     SkColorType sk_color_type,
     SkAlphaType alpha_type,
-    sk_sp<SkColorSpace> sk_color_space,
+    const gfx::ColorSpace& color_space,
     ShouldInitialize should_initialize,
     WebGraphicsSharedImageInterfaceProvider* shared_image_interface_provider,
     CanvasResourceHost* resource_host) {
@@ -1091,8 +1091,7 @@
   }
 
   auto provider = std::make_unique<CanvasResourceProviderSharedBitmap>(
-      size, sk_color_type, alpha_type,
-      SkColorSpaceToGfxColorSpace(std::move(sk_color_space)),
+      size, sk_color_type, alpha_type, color_space,
       shared_image_interface_provider, resource_host);
   if (provider->IsValid()) {
     if (should_initialize ==
@@ -1280,7 +1279,7 @@
     gfx::Size size,
     SkColorType sk_color_type,
     SkAlphaType alpha_type,
-    sk_sp<SkColorSpace> sk_color_space,
+    const gfx::ColorSpace& color_space,
     ShouldInitialize should_initialize,
     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
     CanvasResourceHost* resource_host) {
@@ -1304,9 +1303,8 @@
   }
 
   auto provider = std::make_unique<CanvasResourceProviderSwapChain>(
-      size, sk_color_type, alpha_type,
-      SkColorSpaceToGfxColorSpace(std::move(sk_color_space)),
-      context_provider_wrapper, resource_host);
+      size, sk_color_type, alpha_type, color_space, context_provider_wrapper,
+      resource_host);
   if (provider->IsValid()) {
     if (should_initialize ==
         CanvasResourceProvider::ShouldInitialize::kCallClear)
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
index 477ca82..db9bac93 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -120,7 +120,7 @@
       gfx::Size size,
       SkColorType sk_color_type,
       SkAlphaType alpha_type,
-      sk_sp<SkColorSpace> sk_color_space,
+      const gfx::ColorSpace& color_space,
       ShouldInitialize initialize_provider,
       WebGraphicsSharedImageInterfaceProvider* shared_image_interface_provider,
       CanvasResourceHost* resource_host = nullptr);
@@ -156,7 +156,7 @@
       gfx::Size size,
       SkColorType sk_color_type,
       SkAlphaType alpha_type,
-      sk_sp<SkColorSpace> sk_color_space,
+      const gfx::ColorSpace& color_space,
       ShouldInitialize initialize_provider,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>,
       CanvasResourceHost* resource_host = nullptr);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index 078c28b..a339a5b 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -602,7 +602,7 @@
 
   EXPECT_FALSE(CanvasResourceProvider::CreateSharedBitmapProvider(
       gfx::Size(10, 10), kN32_SkColorType, kPremul_SkAlphaType,
-      SkColorSpace::MakeSRGB(),
+      gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       test_web_shared_image_interface_provider.get()));
 }
@@ -619,7 +619,8 @@
           TestWebGraphicsSharedImageInterfaceProvider::Create();
 
   auto provider = CanvasResourceProvider::CreateSharedBitmapProvider(
-      kSize, kInfo.colorType(), kInfo.alphaType(), kInfo.refColorSpace(),
+      kSize, kInfo.colorType(), kInfo.alphaType(),
+      gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       test_web_shared_image_interface_provider.get());
 
@@ -757,19 +758,19 @@
 TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SwapChain) {
   auto provider = CanvasResourceProvider::CreateSwapChainProvider(
       gfx::Size(kMaxTextureSize - 1, kMaxTextureSize), kN32_SkColorType,
-      kPremul_SkAlphaType, SkColorSpace::MakeSRGB(),
+      kPremul_SkAlphaType, gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       context_provider_wrapper_);
   EXPECT_TRUE(provider->SupportsDirectCompositing());
   provider = CanvasResourceProvider::CreateSwapChainProvider(
       gfx::Size(kMaxTextureSize, kMaxTextureSize), kN32_SkColorType,
-      kPremul_SkAlphaType, SkColorSpace::MakeSRGB(),
+      kPremul_SkAlphaType, gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       context_provider_wrapper_);
   EXPECT_TRUE(provider->SupportsDirectCompositing());
   provider = CanvasResourceProvider::CreateSwapChainProvider(
       gfx::Size(kMaxTextureSize + 1, kMaxTextureSize), kN32_SkColorType,
-      kPremul_SkAlphaType, SkColorSpace::MakeSRGB(),
+      kPremul_SkAlphaType, gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       context_provider_wrapper_);
 
@@ -801,7 +802,8 @@
       SkImageInfo::MakeN32Premul(10, 10, SkColorSpace::MakeSRGB());
 
   auto provider = CanvasResourceProvider::CreateSwapChainProvider(
-      kSize, kInfo.colorType(), kInfo.alphaType(), kInfo.refColorSpace(),
+      kSize, kInfo.colorType(), kInfo.alphaType(),
+      gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       context_provider_wrapper_);
 
@@ -823,7 +825,8 @@
       10, 10, kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear());
 
   auto provider = CanvasResourceProvider::CreateSwapChainProvider(
-      kSize, kInfo.colorType(), kInfo.alphaType(), kInfo.refColorSpace(),
+      kSize, kInfo.colorType(), kInfo.alphaType(),
+      gfx::ColorSpace::CreateSRGBLinear(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       context_provider_wrapper_);
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 456177f3..cc6480d 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -463,7 +463,7 @@
   *out_resource = viz::TransferableResource::MakeSoftwareSharedImage(
       registered.shared_image, registered.sync_token, size_,
       viz::SinglePlaneFormat::kBGRA_8888,
-      viz::TransferableResource::ResourceSource::kImageLayerBridge);
+      viz::TransferableResource::ResourceSource::kDrawingBuffer);
   out_resource->color_space = back_color_buffer_->shared_image->color_space();
   out_resource->hdr_metadata = hdr_metadata_;
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index 21daf102..716b2957 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -227,7 +227,7 @@
     // bitmaps to the GPU process.
     viz::SharedImageFormat format = viz::SinglePlaneFormat::kBGRA_8888;
     RegisteredBitmap registered = CreateOrRecycleBitmap(size, format);
-    if (!registered.bitmap) {
+    if (!registered.shared_image) {
       return false;
     }
 
@@ -240,15 +240,9 @@
     if (!sk_image->readPixels(dst_info, pixels, dst_info.minRowBytes(), 0, 0))
       return false;
 
-    if (registered.shared_image) {
-      *out_resource = viz::TransferableResource::MakeSoftwareSharedImage(
-          registered.shared_image, registered.sync_token, size, format,
-          viz::TransferableResource::ResourceSource::kImageLayerBridge);
-    } else {
-      *out_resource = viz::TransferableResource::MakeSoftwareSharedBitmap(
-          registered.bitmap->id(), gpu::SyncToken(), size, format,
-          viz::TransferableResource::ResourceSource::kImageLayerBridge);
-    }
+    *out_resource = viz::TransferableResource::MakeSoftwareSharedImage(
+        registered.shared_image, registered.sync_token, size, format,
+        viz::TransferableResource::ResourceSource::kImageLayerBridge);
     out_resource->origin = image_->IsOriginTopLeft()
                                ? kTopLeft_GrSurfaceOrigin
                                : kBottomLeft_GrSurfaceOrigin;
@@ -272,7 +266,7 @@
   DCHECK(sii_provider);
   auto it = std::remove_if(recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
                            [&size](const RegisteredBitmap& registered) {
-                             return registered.bitmap->size() != size ||
+                             return registered.shared_image->size() != size ||
                                     !registered.sii_provider;
                            });
 
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder_test.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder_test.cc
index ad6d6a65..22dcbb2 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder_test.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder_test.cc
@@ -95,7 +95,7 @@
   dispatcher_->SetPlaceholderCanvasDispatcher(placeholder_id_);
   resource_provider_ = CanvasResourceProvider::CreateSharedBitmapProvider(
       gfx::Size(kWidth, kHeight), kN32_SkColorType, kPremul_SkAlphaType,
-      SkColorSpace::MakeSRGB(),
+      gfx::ColorSpace::CreateSRGB(),
       CanvasResourceProvider::ShouldInitialize::kCallClear,
       test_web_shared_image_interface_provider_.get());
 }
diff --git a/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
index a52d744..62aa6a9 100644
--- a/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
+++ b/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
@@ -60,7 +60,7 @@
     if (!provider) {
       provider = CanvasResourceProvider::CreateSharedBitmapProvider(
           Size(), kN32_SkColorType, kPremul_SkAlphaType,
-          SkColorSpace::MakeSRGB(), kShouldInitialize,
+          gfx::ColorSpace::CreateSRGB(), kShouldInitialize,
           SharedGpuContext::SharedImageInterfaceProvider(), this);
     }
     if (!provider) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0d0ac60..a24a244 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1088,6 +1088,10 @@
       status: "experimental",
     },
     {
+      name: "CSSLineClampLineBreakingEllipsis",
+      depends_on: ["CSSLineClamp"],
+    },
+    {
       // https://github.com/w3c/csswg-drafts/issues/10435
       name: "CSSLineClampWebkitBoxBlockification",
       status: "stable",
@@ -1106,6 +1110,7 @@
     },
     {
       name: "CSSMixins",
+      status: "test",
     },
     {
       name: "CSSNestedPseudoElements",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 17704f5..8c7f06f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2682,6 +2682,7 @@
 crbug.com/383880384 [ Win ] external/wpt/css/css-properties-values-api/registered-property-change-style-002.html [ Failure Pass ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/389545685 [ Mac14 ] external/wpt/css/css-position/sticky/position-sticky-fractional-offset.html [ Failure ]
 crbug.com/388922812 external/wpt/svg/animations/reftests/discard-check-remove.svg [ Failure ]
 crbug.com/388922812 external/wpt/svg/animations/reftests/discard-rect-as-child.svg [ Failure ]
 crbug.com/388922812 external/wpt/svg/animations/reftests/discard-rect-as-href.svg [ Failure ]
@@ -8391,11 +8392,37 @@
 
 # line-clamp
 crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-abspos-001.tentative.html [ Failure ]
-crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-abspos-001.tentative.html [ Pass ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html [ Failure ]
+crbug.com/40336192 external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html [ Failure ]
+# css-line-clamp-line-breaking-ellipsis
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html [ Pass ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-009.tentative.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-024.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-035.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-036.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-text/white-space/text-wrap-balance-005.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/external/wpt/css/css-text/white-space/text-wrap-balance-line-clamp-001.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/fast/overflow/line-clamp.html [ Failure ]
+crbug.com/40336192 virtual/css-line-clamp-line-breaking-ellipsis/paint/invalidation/text-line-clamp-truncation.html [ Failure ]
 # disable-css-line-clamp
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-abspos-001.tentative.html [ Pass ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-040.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-047.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-050.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-001.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-004.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-005.tentative.html [ Failure ]
@@ -8485,6 +8512,15 @@
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-008.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-009.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-with-floats-010.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-002.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-003.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-004.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-005.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-006.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html [ Failure ]
 
 # backdrop-filter-mirror-edge
 crbug.com/904592 external/wpt/css/filter-effects/backdrop-filter-svg-blur.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestLists/content_shell.filter b/third_party/blink/web_tests/TestLists/content_shell.filter
index 352b7c3..23da2531 100644
--- a/third_party/blink/web_tests/TestLists/content_shell.filter
+++ b/third_party/blink/web_tests/TestLists/content_shell.filter
@@ -34,7 +34,6 @@
 virtual/old-text-size-adjust-with-os-font-scale/wpt_internal/*
 virtual/generic-sensor-extra-classes/wpt_internal/*
 virtual/unload-allowed/wpt_internal/*
-virtual/css-mixins/wpt_internal/*
 virtual/single-import-map/wpt_internal/*
 
 # Blocklisted tests fail unexpectedly on headless shell for at least one
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 075668ad..4add0d8 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -4627,15 +4627,6 @@
     ]
   },
   {
-    "prefix": "css-mixins",
-    "platforms": ["Linux"],
-    "bases": ["wpt_internal/css/css-mixins"],
-    "exclusive_tests": "ALL",
-    "args": ["--enable-blink-features=CSSMixins"],
-    "owners": ["sesse@chromium.org"],
-    "expires": "Jan 1, 2025"
-  },
-  {
     "prefix": "css-relative-currentcolor-disabled",
     "platforms": ["Linux"],
     "bases": [
@@ -4788,6 +4779,47 @@
       "--force-fieldtrials=WebRTC-Video-H26xPacketBuffer/Enabled/"
     ],
     "expires": "August 31, 2025"
+  },
+  {
+    "prefix": "css-line-clamp-line-breaking-ellipsis",
+    "platforms": [
+      "Linux"
+    ],
+    "bases": [
+      "external/wpt/css/css-overflow/line-clamp/",
+      "external/wpt/compat/webkit-box-clamp-bottom-border.html",
+      "external/wpt/compat/webkit-box-clamp-visibility-change.html",
+      "external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-001.tentative.html",
+      "external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-002.tentative.html",
+      "external/wpt/css/css-flexbox/alignment/flex-align-baseline-line-clamp-003.tentative.html",
+      "external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-001.tentative.html",
+      "external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-002.tentative.html",
+      "external/wpt/css/css-grid/alignment/grid-align-baseline-line-clamp-003.tentative.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-first-001.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-first-002.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-first-003.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-last-001.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-last-002.html",
+      "external/wpt/css/css-inline/baseline-source/baseline-source-last-003.html",
+      "external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-001.html",
+      "external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-002.html",
+      "external/wpt/css/css-text/white-space/text-wrap-balance-005.html",
+      "external/wpt/css/css-text/white-space/text-wrap-balance-line-clamp-001.html",
+      "fast/deprecated-flexbox/dynamically-change-line-clamp.html",
+      "fast/deprecated-flexbox/line-clamp-crash.html",
+      "fast/deprecated-flexbox/line-clamp-removed-dynamically.html",
+      "fast/overflow/line-clamp-and-columns.html",
+      "fast/overflow/line-clamp-ellipsis-in-free-space.html",
+      "fast/overflow/line-clamp-hides-trailing-anchor.html",
+      "fast/overflow/line-clamp.html",
+      "paint/invalidation/text-line-clamp-truncation.html"
+    ],
+    "args": [
+      "--enable-blink-features=CSSLineClamp,CSSLineClampLineBreakingEllipsis"
+    ],
+    "owners": [
+      "abotella@igalia.com"
+    ]
   }
 
 ]
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 86505413..94765f8 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
@@ -417203,6 +417203,12 @@
        []
       ]
      },
+     "interfaces": {
+      "SVGPathSegment-expected.txt": [
+       "5ef6abd62bb20066c23d36acfd732c188655ad49",
+       []
+      ]
+     },
      "property": {
       "d-none-expected.svg": [
        "60195b1777f3ed2fd800380d02ba488e24ed5af5",
@@ -417845,7 +417851,7 @@
        []
       ],
       "SVGGeometryElement.getTotalLength-01-expected.txt": [
-       "b00415a2f6780870939955e08b01cc1ecdc5e9aa",
+       "aa53daa3be12789adac2855cf58ee312c0a4e7ca",
        []
       ],
       "SVGGeometryElement.isPointInFill-01-expected.txt": [
@@ -438102,39 +438108,479 @@
       }
      ]
     ],
-    "transaction-abort-generator-revert.html": [
-     "bbe0338c3acdc8791e308d8411c986048096f36c",
+    "transaction-abort-generator-revert.any.js": [
+     "0c6ffa52d276e426db0f2771fafe79d35b087ce8",
      [
-      null,
-      {}
+      "IndexedDB/transaction-abort-generator-revert.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts an object store's key generator state"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-generator-revert.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts an object store's key generator state"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-generator-revert.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts an object store's key generator state"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-generator-revert.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts an object store's key generator state"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
      ]
     ],
-    "transaction-abort-index-metadata-revert.html": [
-     "54a873d8758c6a906c1899ee0c15e990a8798444",
+    "transaction-abort-index-metadata-revert.any.js": [
+     "9b429795c48f381127d467ee3fc46b9e5870188e",
      [
-      null,
-      {}
+      "IndexedDB/transaction-abort-index-metadata-revert.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts index metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-index-metadata-revert.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts index metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-index-metadata-revert.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts index metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-index-metadata-revert.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts index metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
      ]
     ],
-    "transaction-abort-multiple-metadata-revert.html": [
-     "18abd0588c4197e22976644a706f1df4731aad5d",
+    "transaction-abort-multiple-metadata-revert.any.js": [
+     "9161af8e2baad31dd51a58ae8d22d08bb94ef344",
      [
-      null,
-      {}
+      "IndexedDB/transaction-abort-multiple-metadata-revert.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts multiple operations on the same metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-multiple-metadata-revert.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts multiple operations on the same metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-multiple-metadata-revert.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts multiple operations on the same metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-multiple-metadata-revert.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts multiple operations on the same metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
      ]
     ],
-    "transaction-abort-object-store-metadata-revert.html": [
-     "c31537bc5cda382fdf87608f55af434129e2710a",
+    "transaction-abort-object-store-metadata-revert.any.js": [
+     "d5f14b54de48030cdd129c300b2db3435418be6c",
      [
-      null,
-      {}
+      "IndexedDB/transaction-abort-object-store-metadata-revert.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts object store metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-object-store-metadata-revert.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts object store metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-object-store-metadata-revert.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts object store metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-object-store-metadata-revert.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: aborting transactions reverts object store metadata"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
      ]
     ],
-    "transaction-abort-request-error.html": [
-     "fa828286f4d7c4f9cb0d2a8a7ac561082dbfc4f4",
+    "transaction-abort-request-error.any.js": [
+     "a7ddd02f1d2ad88d810db36bb82d0e29cf6be336",
      [
-      null,
-      {}
+      "IndexedDB/transaction-abort-request-error.any.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test error events fired at requests from aborted transaction"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-request-error.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test error events fired at requests from aborted transaction"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-request-error.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test error events fired at requests from aborted transaction"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "IndexedDB/transaction-abort-request-error.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "title",
+         "IndexedDB: Test error events fired at requests from aborted transaction"
+        ],
+        [
+         "global",
+         "window,worker"
+        ],
+        [
+         "script",
+         "resources/support-promises.js"
+        ],
+        [
+         "script",
+         "resources/support.js"
+        ]
+       ]
+      }
      ]
     ],
     "transaction-create_in_versionchange.htm": [
@@ -704456,6 +704902,13 @@
         null,
         {}
        ]
+      ],
+      "SVGPathSegment.svg": [
+       "a4f67363dc3b179fa8bd46ec1692a7d8eff9e701",
+       [
+        null,
+        {}
+       ]
       ]
      },
      "property": {
@@ -705285,7 +705738,7 @@
        ]
       ],
       "SVGGeometryElement.getTotalLength-01.svg": [
-       "412afe7b730a9fadddf6b7c27e2688c5ebffd7f0",
+       "e429a55af4fc38df0344e68756d0a1f4ce97e15f",
        [
         null,
         {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html
new file mode 100644
index 0000000..1818f3d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-001.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: the line-clamp ellipsis is placed after a break opportunity</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-001-ref.html">
+<meta name="assert" content="The block overflow ellipsis must be placed after the last soft wrap opportunity that still allows the ellipsis to fit on the line.">
+<style>
+.clamp {
+  line-clamp: 2;
+  width: 63.1ch;
+  border: 1px solid black;
+  font-family: monospace;
+}
+</style>
+<div class="clamp">
+  This time, Mark, who had always been the center of attention in
+  <!-- End of first line -->
+  any social gathering, walked into the room uncharacteristically
+  <!-- Break point for the second line if the ellipsis was not there. -->
+  quietly, barely speaking as he settled into a chair.
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-002.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-002.html
new file mode 100644
index 0000000..5859fb2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-002.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis styling</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-002-ref.html">
+<meta name="assert" content="The block overflow ellipsis acts as an anonymous inline which is a child of the root inline box, and it should be styled as such.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+  font-weight: bold;
+  font-style: italic;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  Line 3<br>
+  Line 4
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-003.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-003.tentative.html
new file mode 100644
index 0000000..5911022
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-003.tentative.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis styling</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-003-ref.html">
+<meta name="assert" content="The block overflow ellipsis is styled according to the containing root inline box, not the line-clamp container.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+}
+.inner {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  Line 1
+  <div class="inner">
+    Line 2 <br>
+    Line 3
+  </div>
+  Line 4
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-004.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-004.html
new file mode 100644
index 0000000..7eadab1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-004.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis styling</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-004-ref.html">
+<meta name="assert" content="The block overflow ellipsis is styled according to the containing root inline box, even if it is contained within a span with different styling. The span's borders don't continue through the ellipsis.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+}
+span {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+  border: 2px solid blue;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  <span>
+    Line 3<br>
+    Line 4
+  </span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-005.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-005.html
new file mode 100644
index 0000000..84786d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-005.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis styling</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-005-ref.html">
+<meta name="assert" content="The block overflow ellipsis is styled according to the containing root inline box, even if it is contained within a span with different styling. If the span ends at the end of the line, it has a right margin before the ellipsis.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+}
+span {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+  border: 2px solid blue;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  <span>Line 3</span><br>
+  Line 4
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-006.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-006.html
new file mode 100644
index 0000000..bb88427
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-006.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis styling</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-005-ref.html">
+<meta name="assert" content="The block overflow ellipsis is styled according to the containing root inline box, even if it is contained within a span with different styling. If the span has box-decoration-break: clone, it will have a right margin.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+}
+span {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+  border: 2px solid blue;
+  box-decoration-break: clone;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  <span>Line 3</span><br>
+  Line 4
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html
new file mode 100644
index 0000000..86c701b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-007.tentative.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis and ::first-line</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-007-ref.html">
+<meta name="assert" content="The block overflow ellipsis must not be included in the ::first-line pseudoelement of the line-clamp container.">
+<style>
+.clamp {
+  line-clamp: 1;
+  color: teal;
+}
+.clamp::first-line {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html
new file mode 100644
index 0000000..e844d2d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-008.tentative.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis and ::first-line</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-007-ref.html">
+<meta name="assert" content="The block overflow ellipsis must not be included in the ::first-line pseudoelement of a parent of the line-clamp container.">
+<style>
+.clamp {
+  line-clamp: 1;
+  color: teal;
+}
+.container::first-line {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="container">
+  <div class="clamp">
+    Line 1<br>
+    Line 2
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html
new file mode 100644
index 0000000..7517f5d1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/block-ellipsis-009.tentative.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: block-ellipsis and ::first-line</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#block-ellipsis">
+<link rel="match" href="reference/block-ellipsis-009-ref.html">
+<meta name="assert" content="The block overflow ellipsis must not be included in the ::first-line pseudoelement of a child of the line-clamp container.">
+<style>
+.clamp {
+  line-clamp: 3;
+  color: teal;
+}
+.inner::first-line {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2
+  <div class="inner">
+    Line 3<br>
+    Line 4
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-001-ref.html
new file mode 100644
index 0000000..2343643
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-001-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  width: 63.1ch;
+  border: 1px solid black;
+  font-family: monospace;
+}
+</style>
+<div class="clamp">
+  This time, Mark, who had always been the center of attention in
+  <!-- End of first line -->
+  any social gathering, walked into the room…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-002-ref.html
new file mode 100644
index 0000000..7ba1ae430
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-002-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+  font-weight: bold;
+  font-style: italic;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  Line 3…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-003-ref.html
new file mode 100644
index 0000000..b490d79
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-003-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+}
+.inner {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  Line 1
+  <div class="inner">
+    Line 2 <br>
+    Line 3…
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-004-ref.html
new file mode 100644
index 0000000..acb8d0e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-004-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+}
+span {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+  border: 2px solid blue;
+  border-right: 0;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  <span>Line 3</span>…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-005-ref.html
new file mode 100644
index 0000000..92dbdda6f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-005-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+}
+span {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+  border: 2px solid blue;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2<br>
+  <span>Line 3</span>…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-007-ref.html
new file mode 100644
index 0000000..d9a39c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-007-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+}
+.first-line {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  <span class="first-line">Line 1</span>…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-009-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-009-ref.html
new file mode 100644
index 0000000..949ba2f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/block-ellipsis-009-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  color: teal;
+}
+.inner-first-line {
+  color: purple;
+  font-weight: bold;
+  font-style: italic;
+  font-size: 1.5em;
+}
+</style>
+<div class="clamp">
+  Line 1<br>
+  Line 2
+  <div>
+    <span class="inner-first-line">Line 3</span>…
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-051-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-051-ref.html
new file mode 100644
index 0000000..8951ff9a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-051-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+  .clamp {
+    width: 10em;
+    border: 2px solid black;
+    text-align: right;
+  }
+</style>
+<div class="clamp">
+  Line 1 <br>
+  Line 2…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-052-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-052-ref.html
new file mode 100644
index 0000000..1f89d6c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-052-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+  .clamp {
+    width: 10em;
+    border: 2px solid black;
+    text-align: center;
+  }
+</style>
+<div class="clamp">
+  Line 1 <br>
+  Line 2…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-053-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-053-ref.html
new file mode 100644
index 0000000..42b42c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/webkit-line-clamp-053-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+  .clamp {
+    width: 8ch;
+    border: 2px solid black;
+    text-align: justify;
+    text-align-last: justify;
+    font-family: monospace;
+  }
+</style>
+<div class="clamp">
+  XXX XXX XX XX…
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html
new file mode 100644
index 0000000..2667da9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-051.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: right-aligned -webkit-line-clamp ellipsis</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#propdef--webkit-line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-051-ref.html">
+<meta name="assert" content="If the -webkit-line-clamp ellipsis would be placed in a right-aligned line, the alignment happens after placing the ellipsis, which means the ellipsis ends at the right edge of the line.">
+<style>
+  .clamp {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+
+    width: 10em;
+    border: 2px solid black;
+    text-align: right;
+  }
+</style>
+<div class="clamp">
+  Line 1 <br>
+  Line 2 <br>
+  Line 3
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html
new file mode 100644
index 0000000..cd4c26d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-052.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: center-aligned -webkit-line-clamp ellipsis</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#propdef--webkit-line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-052-ref.html">
+<meta name="assert" content="If the -webkit-line-clamp ellipsis would be placed in an aligned line, the alignment happens after placing the ellipsis.">
+<style>
+  .clamp {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+
+    width: 10em;
+    border: 2px solid black;
+    text-align: center;
+  }
+</style>
+<div class="clamp">
+  Line 1 <br>
+  Line 2 <br>
+  Line 3
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html
new file mode 100644
index 0000000..404188b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/webkit-line-clamp-053.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: justified -webkit-line-clamp ellipsis</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#propdef--webkit-line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-053-ref.html">
+<meta name="assert" content="If the -webkit-line-clamp ellipsis would be placed in a justified line, the justification happens after placing the ellipsis.">
+<style>
+  .clamp {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+
+    width: 8ch;
+    border: 2px solid black;
+    text-align: justify;
+
+    font-family: monospace;
+  }
+</style>
+<div class="clamp">
+  XXX XXX XX XX XXXXX
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment-expected.txt b/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment-expected.txt
new file mode 100644
index 0000000..5ef6abd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+[FAIL] SVGPathSegment interface exists
+  assert_not_equals: got disallowed value undefined
+[FAIL] Test path.getPathData() straight lines
+  path.getPathData is not a function
+[FAIL] Test path.getPathData() cubic
+  path.getPathData is not a function
+[FAIL] Test path.getPathData({normalize: true}) straight lines
+  path.getPathData is not a function
+[FAIL] Test path.getPathData({normalize: true}) cubic
+  path.getPathData is not a function
+[FAIL] Test path.getPathData({normalize: true}) quadratic
+  path.getPathData is not a function
+[FAIL] Test path.getPathData({normalize: true}) elliptical arc
+  path.getPathData is not a function
+[FAIL] Test path.setPathData()lines
+  path.getPathData is not a function
+[FAIL] Test path.setPathData()empty
+  path.getPathData is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment.svg b/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment.svg
new file mode 100644
index 0000000..a4f6736
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/path/interfaces/SVGPathSegment.svg
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:h="http://www.w3.org/1999/xhtml">
+  <metadata>
+    <h:link rel="help" href="https://svgwg.org/specs/paths/#InterfaceSVGPathSegment"/>
+  </metadata>
+  <h:script src="/resources/testharness.js"/>
+  <h:script src="/resources/testharnessreport.js"/>
+
+  <path id="track" d="m 10 20 h 30"/>S
+
+  <script><![CDATA[
+  test(function() {
+    let track = document.getElementById('track');
+    assert_equals(Object.getPrototypeOf(track), SVGPathElement.prototype);
+    assert_not_equals(track.getPathData, undefined);
+    assert_not_equals(track.setPathData, undefined);
+    assert_not_equals(track.getPathSegmentAtLength, undefined);
+  }, "SVGPathSegment interface exists");
+
+  function checkObjects(actual, expected, epsilon) {
+    if (Array.isArray(expected)) {
+      if (actual.length != expected.length) {
+        return false;
+      }
+      for (let i = 0; i < expected.length; i++) {
+        if (!checkObjects(actual[i], expected[i], epsilon) ) {
+          return false;
+        }
+      }
+      return true;
+    }
+    if (typeof expected == "object") {
+      for (let key in expected) {
+        if (!checkObjects(actual[key], expected[key], epsilon)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    if (typeof expected == "number") {
+      if (epsilon === undefined) {
+        epsilon = 0;
+      }
+      return Math.abs(actual - expected) <= epsilon;
+    }
+    return actual == expected;
+  }
+
+  function ToString(value) {
+    let output = "";
+    if (Array.isArray(value)) {
+      let arrayAsString = [];
+      for (let i = 0; i < value.length; i++) {
+        arrayAsString.push(ToString(value[i]));
+      }
+      return arrayAsString.join(' ');
+    }
+    if (typeof value == "object") {
+      let objectAsArray = [];
+      for (let key in value) {
+        objectAsArray.push(ToString(value[key]));
+      }
+      return objectAsArray.join(' ');
+    }
+    if (typeof value == "number") {
+      return "" + +value.toFixed(3);
+    }
+    return  value;
+  }
+
+  var checkPathData = function(actual, expected, epsilon) {
+    assert_true(checkObjects(actual, expected, epsilon), "actual:" + ToString(actual) + " expected:" + ToString(expected));
+  };
+
+  let getPathDataTests = [
+    {
+      description: "straight lines",
+      input: "M 0 0 H 100 V 100 H 0 Z",
+      output: [
+        { type: "M", values: [0, 0] },
+        { type: "H", values: [100] },
+        { type: "V", values: [100] },
+        { type: "H", values: [0] },
+        { type: "Z", values: [] }
+      ]
+    },
+    {
+      description: "cubic",
+      input: "M 413 140 C 413 140 438 40 302 44",
+      output: [
+        { type: "M", values: [413, 140] },
+        { type: "C", values: [413, 140, 438, 40, 302, 44] }
+      ]
+    }
+  ];
+
+  getPathDataTests.forEach(t => {
+    test(_ => {
+      let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
+
+      path.setAttribute("d", t.input);
+      let pathData = path.getPathData();
+
+      checkPathData(pathData, t.output);
+    }, "Test path.getPathData() " + t.description)
+  });
+
+
+  let getNormalizedPathDataTests = [
+    {
+      description: "straight lines",
+      input: "M 0 0 H 100 V 100 H 0 Z",
+      output: [
+        { type: "M", values: [0, 0] },
+        { type: "L", values: [100, 0] },
+        { type: "L", values: [100, 100] },
+        { type: "L", values: [0, 100] },
+        { type: "Z", values: [] }
+      ]
+    },
+    {
+      description: "cubic",
+      input: "M 0 0 C 30,90 25,10 50,10 S 70,90 90,90",
+      output: [
+        { type: "M", values: [0, 0] },
+        { type: "C", values: [30, 90, 25, 10, 50, 10] },
+        { type: "C", values: [75, 10, 70, 90, 90, 90] },
+      ]
+    },
+    {
+      description: "quadratic",
+      input: "M 0 0 Q 30 30 30 60 t 30 0 30 0 30 0 30 0 30 0",
+      output: [
+        { type: "M", values: [0, 0] },
+        { type: "C", values: [20, 20, 30, 40, 30, 60] },
+        { type: "C", values: [30, 80, 40, 80, 60, 60] },
+        { type: "C", values: [80, 40, 90, 40, 90, 60] },
+        { type: "C", values: [90, 80, 100, 80, 120, 60] },
+        { type: "C", values: [140, 40, 150, 40, 150, 60] },
+        { type: "C", values: [150, 80, 160, 80, 180, 60] },
+      ]
+    },
+    {
+      description: "elliptical arc",
+      input: "M 6 10 A 10 10 10 0 0 15 10",
+      output: [
+        { type: "M", values: [6, 10] },
+        { type: "C", values: [8.83, 11.426, 12.169, 11.426, 15, 10] },
+      ],
+      epsilon: 0.01,
+    },
+  ];
+
+  getNormalizedPathDataTests.forEach(t => {
+    test(_ => {
+      let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
+
+      path.setAttribute("d", t.input);
+      let pathData = path.getPathData({normalize: true});
+
+      checkPathData(pathData, t.output, t.epsilon);
+    }, "Test path.getPathData({normalize: true}) " + t.description)
+  });
+
+  let setPathDataTests = [
+    {
+      description: "lines",
+      input: [
+        { type: "M", values: [0, 0] },
+        { type: "L", values: [10, 10] },
+        { type: "Z", values: [] }
+      ],
+      output: "M 0 0 L 10 10 Z"
+    },
+    {
+      description: "empty",
+      input: [],
+      output: ""
+    },
+  ];
+
+  setPathDataTests.forEach(t => {
+    test(_ => {
+      let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
+
+      path.setAttribute("d", t.output);
+      let segments = path.getPathData();
+      path.removeAttribute("d");
+      path.setPathData(segments);
+
+      assert_equals(path.getAttribute("d"), t.output);
+    }, "Test path.setPathData()" + t.description);
+  });
+
+  ]]></script>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01-expected.txt b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01-expected.txt
index b00415a2..aa53daa 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01-expected.txt
@@ -1,4 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] SVGGeometryElement.prototype.getTotalLength(), getTotalLength - rect
   Failed to execute 'getTotalLength' on 'SVGGeometryElement': This element is non-rendered element.
+[FAIL] SVGGeometryElement.prototype.getTotalLength(), getTotalLength - path modified with setPathData
+  path.getPathData is not a function
 Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01.svg b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01.svg
index 412afe7..e429a55a 100644
--- a/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01.svg
+++ b/third_party/blink/web_tests/external/wpt/svg/types/scripted/SVGGeometryElement.getTotalLength-01.svg
@@ -3,7 +3,7 @@
   <h:link rel="help" href="https://svgwg.org/svg2-draft/types.html#__svg__SVGGeometryElement__getTotalLength"/>
   <h:script src="/resources/testharness.js"/>
   <h:script src="/resources/testharnessreport.js"/>
-  <script>
+  <script><![CDATA[
 test(function() {
     let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
     path.setAttribute('d', 'M0,0L100,0L100,100');
@@ -69,5 +69,26 @@
       document.documentElement.removeChild(g);
     }
 }, document.title+', getTotalLength - rect in document with display none');
-  </script>
+
+test(function() {
+    let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+    document.documentElement.appendChild(path);
+    path.setAttribute("d", "M50,100l0,0l0,-50l100,0l86.3325,122.665z");
+    try {
+
+      assert_equals(path.getTotalLength(), 500);
+
+      let pathData = path.getPathData();
+      for (var i = 0; i < 2; i++) {
+        pathData = pathData.slice(0, -1);
+      }
+      path.setPathData(pathData);
+
+      assert_equals(path.getTotalLength(), 150);
+
+    } finally {
+      document.documentElement.removeChild(path);
+    }
+}, document.title+', getTotalLength - path modified with setPathData');
+  ]]></script>
 </svg>
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles-expected.txt
index 9e2c294..e1d143ab 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles-expected.txt
@@ -35,3 +35,8 @@
 First inherited entry contains transitions from "#element": TRUE
 Second inherited entry is empty (.parent does not have any transitions): TRUE
 
+Animations for pseudo ::before when its origin element does not have any animations
+There is only 1 animation: TRUE
+The name of the animation is --color: TRUE
+The color property is animated: TRUE
+
diff --git a/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles.js b/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles.js
index 67050ee..e664fbf 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles.js
+++ b/third_party/blink/web_tests/inspector-protocol/css/css-get-animated-styles.js
@@ -35,6 +35,12 @@
   background-color: black;
 }
 
+#element-for-pseudo::before {
+  content: '';
+  background-color: white;
+  animation: 1s --color infinite;
+}
+
 @keyframes --color {
   from {
     color: red;
@@ -61,6 +67,7 @@
 <div class='grand-parent'>
   <div class='parent'>
     <div id='element'>Text</div>
+    <div id='element-for-pseudo'></div>
   </div>
 </div>
 `,
@@ -188,6 +195,24 @@
       'Second inherited entry is empty (.parent does not have any transitions)',
       inheritedForPseudo[1].transitionsStyle === undefined);
 
+  testRunner.log('\nAnimations for pseudo ::before when its origin element does not have any animations');
+  const nodeForPseudo = nodeTracker.nodes().find(
+    node => DOMHelper.attributes(node).get('id') === 'element-for-pseudo');
+  const beforeNodeIdForPseudo = getPseudoElement(nodeForPseudo, 'before').nodeId;
+  const {
+    result: {
+      animationStyles: animationStylesForPseudoWithoutParentAnimations,
+    }
+  } = await dp.CSS.getAnimatedStylesForNode({nodeId: beforeNodeIdForPseudo});
+  logCondition(
+    'There is only 1 animation', animationStylesForPseudoWithoutParentAnimations.length === 1);
+  logCondition(
+      'The name of the animation is --color',
+      animationStylesForPseudoWithoutParentAnimations[0].name === '--color');
+  logCondition(
+      'The color property is animated',
+      animationStylesForPseudoWithoutParentAnimations[0].style.cssProperties[0].name === 'color');
+
   testRunner.completeTest();
   function logCondition(text, condition) {
     testRunner.log(`${text}: ${condition ? 'TRUE' : 'FALSE'}`)
diff --git a/third_party/blink/web_tests/virtual/css-line-clamp-line-breaking-ellipsis/README.md b/third_party/blink/web_tests/virtual/css-line-clamp-line-breaking-ellipsis/README.md
new file mode 100644
index 0000000..0f8fdf5
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/css-line-clamp-line-breaking-ellipsis/README.md
@@ -0,0 +1,5 @@
+Tests with the CSSLineClampLineBreakingEllipsis feature.
+
+This feature makes the (-webkit-)line-clamp ellipsis be taken into account when
+line breaking, as well as making it be taken into account for bidi reordering
+and text alignment/justification.
diff --git a/third_party/blink/web_tests/virtual/css-mixins/wpt_internal/css/css-mixins/README.txt b/third_party/blink/web_tests/virtual/css-mixins/wpt_internal/css/css-mixins/README.txt
deleted file mode 100644
index 848d212..0000000
--- a/third_party/blink/web_tests/virtual/css-mixins/wpt_internal/css/css-mixins/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Virtual test suite for CSS Mixins.
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index a3f5426..91db0dd 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit a3f542676a2b8ff19db3e41192e7c867f16ed8bb
+Subproject commit 91db0dddd20500f927076d7309ab54d3b3909344
diff --git a/third_party/dawn b/third_party/dawn
index 777987d..46d1e23 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 777987d6d109a1632a0a413eca952cf6902e09fb
+Subproject commit 46d1e23d9ee5fdf648359b7b3e3f9caa5eafac68
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 6cbd7a8..a912cd2 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 6cbd7a824340c50ef1aa5cdddf94e14114ade41f
+Subproject commit a912cd245b093ea57a187ca66665ca98090a82fd
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index e796212..40f57f8 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit e79621229ef59e11bc5859d82a765892b2a5979c
+Subproject commit 40f57f86c54cd8b5c06878c0a7301bce9d4b0dbf
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium
index 55678ef..5e5dde5 100644
--- a/third_party/eigen3/README.chromium
+++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@
 Name: Eigen
 Short Name: eigen3
 URL: https://gitlab.com/libeigen/eigen
-Version: 77a073aaa821300fc129ef24b3b052be2e670a3e
-Date: 2024-12-09
+Version: 7f2377859377da6f22152015c28b12c04752af77
+Date: 2025-01-08
 License: MPL-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/eigen3/src b/third_party/eigen3/src
index 24e0c2a1..7bb23b1 160000
--- a/third_party/eigen3/src
+++ b/third_party/eigen3/src
@@ -1 +1 @@
-Subproject commit 24e0c2a125d2b37b35719124d1f758777c150ca8
+Subproject commit 7bb23b1e360e22a395eef75061565fc079ae6a85
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 8e6e4b4..1a218b4 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-3-37-g1400b20ae
-Revision: 1400b20ae8683315f53f00b6c3707fc64faeaa7b
+Version: VER-2-13-3-46-gf21999675
+Revision: f219996754c4df75b758983e18cabb401e5b93a1
 CPEPrefix: cpe:/a:freetype:freetype:2.13.3
 License: FTL
 License File: src/docs/FTL.TXT
diff --git a/third_party/freetype/src b/third_party/freetype/src
index 1400b20..f219996 160000
--- a/third_party/freetype/src
+++ b/third_party/freetype/src
@@ -1 +1 @@
-Subproject commit 1400b20ae8683315f53f00b6c3707fc64faeaa7b
+Subproject commit f219996754c4df75b758983e18cabb401e5b93a1
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index b9f74ba9..597b2e8 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit b9f74ba96d2f3a088e6a38fc1f3331e1aa62b637
+Subproject commit 597b2e8c42ef95d1996a3d3713cddac269c68b50
diff --git a/third_party/perfetto b/third_party/perfetto
index e324242..c6ea87b5 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit e324242074e2e64a65e90a2933afd3ca4413554f
+Subproject commit c6ea87b5b19e6b2798f290b000bb3609c9018c81
diff --git a/third_party/pthreadpool/README.chromium b/third_party/pthreadpool/README.chromium
index 22abdb4..ceb04ac0 100644
--- a/third_party/pthreadpool/README.chromium
+++ b/third_party/pthreadpool/README.chromium
@@ -1,8 +1,8 @@
 Name: pthreadpool
 Short Name: pthreadpool
-URL: https://github.com/Maratyszcza/pthreadpool
-Version: 560c60d342a76076f0557a3946924c6478470044
-Date: 2024-09-09
+URL: https://github.com/google/pthreadpool
+Version: 847fb990fada8bdbd184f5897424cc1969ec8f91
+Date: 2025-01-08
 License: BSD-2-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/pthreadpool/src b/third_party/pthreadpool/src
index 560c60d..b4fb4eb 160000
--- a/third_party/pthreadpool/src
+++ b/third_party/pthreadpool/src
@@ -1 +1 @@
-Subproject commit 560c60d342a76076f0557a3946924c6478470044
+Subproject commit b4fb4eb1668c7d976cdaa941b135a02462adb460
diff --git a/third_party/ruy/README.chromium b/third_party/ruy/README.chromium
index 9cc92a55..6266e92 100644
--- a/third_party/ruy/README.chromium
+++ b/third_party/ruy/README.chromium
@@ -1,8 +1,8 @@
 Name: The ruy matrix multiplication library
 Short Name: ruy
 URL: https://github.com/google/ruy
-Version: 9889171210b81138fd15fb57dd06e98fe6d37b3c
-Date: 2024-11-20
+Version: 83fd40d730feb0804fafbc2d8814bcc19a17b2e5
+Date: 2025-01-08
 License: Apache-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/ruy/src b/third_party/ruy/src
index 95484c3..83fd40d 160000
--- a/third_party/ruy/src
+++ b/third_party/ruy/src
@@ -1 +1 @@
-Subproject commit 95484c3e02206f73309c08ee5ee23d2304ca092b
+Subproject commit 83fd40d730feb0804fafbc2d8814bcc19a17b2e5
diff --git a/third_party/skia b/third_party/skia
index 3531a78..539c311 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 3531a78f28898e41d4180d2094e3ecf2e55bea0e
+Subproject commit 539c311a3a7fa76bf50a9c83822815abdb825a18
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src
index 31c154a..9064fe8 160000
--- a/third_party/spirv-tools/src
+++ b/third_party/spirv-tools/src
@@ -1 +1 @@
-Subproject commit 31c154a2a68a2efad82d372b957b42c6b51c1585
+Subproject commit 9064fe8637daf9f694c8a2e035a34da94022f2be
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium
index 29fd8db..a898c8df 100644
--- a/third_party/tflite/README.chromium
+++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@
 Name: TensorFlow Lite
 Short Name: tflite
 URL: https://github.com/tensorflow/tensorflow
-Version: 73e1e9f4d021a1819a3e2a28889b75de1174bdbe
-Date: 2024-12-09
+Version: b7bed6cb1d5eeebd81324b60d8bd624b9124ef5b
+Date: 2025-01-08
 License: Apache-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/tflite/src b/third_party/tflite/src
index b25df27..b7bed6c 160000
--- a/third_party/tflite/src
+++ b/third_party/tflite/src
@@ -1 +1 @@
-Subproject commit b25df276c8e912c22f57263ffcae6ca8f4c64342
+Subproject commit b7bed6cb1d5eeebd81324b60d8bd624b9124ef5b
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 8540477..8d2a13c 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 8540477b5d951bf001cb55fd57dae8dac8974000
+Subproject commit 8d2a13cc437488e3dafc128371e0fb78cd1a216b
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index 10f90cc..ea05bf7 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit 10f90cce65ba16710a0a2900749008aa0767749e
+Subproject commit ea05bf71f2948d64f7d36651ffcad59216401095
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 3dd1fec..3d039b4 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 3dd1feca3b4bf0c6223a6a732d5b7db79a6cf95b
+Subproject commit 3d039b4adaba9163659becb0af593a9a9a6f8069
diff --git a/third_party/webrtc b/third_party/webrtc
index f94bddf..d8135eb 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit f94bddf72cefe1abd30b54474d774ff08dfd181e
+Subproject commit d8135eb75b7ed9544c6b41732c8fd5640514d565
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn
index 86c7de3e..603d542 100644
--- a/third_party/xnnpack/BUILD.gn
+++ b/third_party/xnnpack/BUILD.gn
@@ -323,9 +323,6 @@
     ":qs8-packw_avx2-avxvnni-f16c-fma",
     ":qs8-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni",
     ":qs8-packw_x64",
-    ":qs8-qc4w-packw_avx2-avxvnni-f16c-fma",
-    ":qs8-qc4w-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni",
-    ":qs8-qc4w-packw_x64",
     ":qs8-qc8w-dwconv_avx-no-avx2-no-f16c-no-fma",
     ":qs8-qc8w-dwconv_f16c-fma-avx2",
     ":qs8-qc8w-dwconv_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl",
@@ -461,9 +458,6 @@
     ":qu8-vmulc_sse4.1-no-sse4.2",
     ":qu8-vmulc_x64",
     ":reference_x64",
-    ":s32-f32-vcvt_avx512f",
-    ":s32-f32-vcvt_f16c-fma-avx2",
-    ":s32-f32-vcvt_x64",
     ":s8-ibilinear_sse2-no-sse3",
     ":s8-ibilinear_sse4.1-no-sse4.2",
     ":s8-ibilinear_x64",
@@ -505,8 +499,6 @@
     ":x32-transposec_x64",
     ":x32-unpool_sse2-no-sse3",
     ":x32-unpool_x64",
-    ":x32-zip_sse2-no-sse3",
-    ":x32-zip_x64",
     ":x64-transposec_avx-no-avx2-no-f16c-no-fma",
     ":x64-transposec_sse2-no-sse3",
     ":x64-transposec_x64",
@@ -520,8 +512,6 @@
     ":x8-transposec_f16c-fma-avx2",
     ":x8-transposec_sse2-no-sse3",
     ":x8-transposec_x64",
-    ":x8-zip_sse2-no-sse3",
-    ":x8-zip_x64",
     ":xx-copy_x64",
     ":xx-fill_sse2-no-sse3",
     ":xx-fill_x64",
@@ -793,9 +783,6 @@
     ":qs8-packw_avx2-avxvnni-f16c-fma_standalone",
     ":qs8-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni_standalone",
     ":qs8-packw_x64_standalone",
-    ":qs8-qc4w-packw_avx2-avxvnni-f16c-fma_standalone",
-    ":qs8-qc4w-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni_standalone",
-    ":qs8-qc4w-packw_x64_standalone",
     ":qs8-qc8w-dwconv_avx-no-avx2-no-f16c-no-fma_standalone",
     ":qs8-qc8w-dwconv_f16c-fma-avx2_standalone",
     ":qs8-qc8w-dwconv_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl_standalone",
@@ -931,9 +918,6 @@
     ":qu8-vmulc_sse4.1-no-sse4.2_standalone",
     ":qu8-vmulc_x64_standalone",
     ":reference_x64_standalone",
-    ":s32-f32-vcvt_avx512f_standalone",
-    ":s32-f32-vcvt_f16c-fma-avx2_standalone",
-    ":s32-f32-vcvt_x64_standalone",
     ":s8-ibilinear_sse2-no-sse3_standalone",
     ":s8-ibilinear_sse4.1-no-sse4.2_standalone",
     ":s8-ibilinear_x64_standalone",
@@ -975,8 +959,6 @@
     ":x32-transposec_x64_standalone",
     ":x32-unpool_sse2-no-sse3_standalone",
     ":x32-unpool_x64_standalone",
-    ":x32-zip_sse2-no-sse3_standalone",
-    ":x32-zip_x64_standalone",
     ":x64-transposec_avx-no-avx2-no-f16c-no-fma_standalone",
     ":x64-transposec_sse2-no-sse3_standalone",
     ":x64-transposec_x64_standalone",
@@ -990,8 +972,6 @@
     ":x8-transposec_f16c-fma-avx2_standalone",
     ":x8-transposec_sse2-no-sse3_standalone",
     ":x8-transposec_x64_standalone",
-    ":x8-zip_sse2-no-sse3_standalone",
-    ":x8-zip_x64_standalone",
     ":xx-copy_x64_standalone",
     ":xx-fill_sse2-no-sse3_standalone",
     ":xx-fill_x64_standalone",
@@ -1120,7 +1100,6 @@
     ":qs8-f16-vcvt_arch=armv8.2-a+fp16",
     ":qs8-f32-vcvt_arm64",
     ":qs8-packw_arm64",
-    ":qs8-qc4w-packw_arm64",
     ":qs8-qc8w-dwconv_arm64",
     ":qs8-qc8w-gemm_arch=armv8.2-a+dotprod",
     ":qs8-qc8w-gemm_arch=armv8.2-a+fp16+dotprod",
@@ -1156,7 +1135,6 @@
     ":qu8-vmul_arm64",
     ":qu8-vmulc_arm64",
     ":reference_arm64",
-    ":s32-f32-vcvt_arm64",
     ":s8-ibilinear_arm64",
     ":s8-maxpool_arm64",
     ":s8-vclamp_arm64",
@@ -1173,13 +1151,11 @@
     ":x32-packw_arm64",
     ":x32-transposec_arm64",
     ":x32-unpool_arm64",
-    ":x32-zip_arm64",
     ":x64-transposec_arm64",
     ":x8-lut_arm64",
     ":x8-packq_arm64",
     ":x8-packw_arm64",
     ":x8-transposec_arm64",
-    ":x8-zip_arm64",
     ":xx-copy_arm64",
     ":xx-fill_arm64",
     ":xx-pad_arm64",
@@ -1306,7 +1282,6 @@
     ":qs8-f16-vcvt_arch=armv8.2-a+fp16_standalone",
     ":qs8-f32-vcvt_arm64_standalone",
     ":qs8-packw_arm64_standalone",
-    ":qs8-qc4w-packw_arm64_standalone",
     ":qs8-qc8w-dwconv_arm64_standalone",
     ":qs8-qc8w-gemm_arch=armv8.2-a+dotprod_standalone",
     ":qs8-qc8w-gemm_arch=armv8.2-a+fp16+dotprod_standalone",
@@ -1342,7 +1317,6 @@
     ":qu8-vmul_arm64_standalone",
     ":qu8-vmulc_arm64_standalone",
     ":reference_arm64_standalone",
-    ":s32-f32-vcvt_arm64_standalone",
     ":s8-ibilinear_arm64_standalone",
     ":s8-maxpool_arm64_standalone",
     ":s8-vclamp_arm64_standalone",
@@ -1359,13 +1333,11 @@
     ":x32-packw_arm64_standalone",
     ":x32-transposec_arm64_standalone",
     ":x32-unpool_arm64_standalone",
-    ":x32-zip_arm64_standalone",
     ":x64-transposec_arm64_standalone",
     ":x8-lut_arm64_standalone",
     ":x8-packq_arm64_standalone",
     ":x8-packw_arm64_standalone",
     ":x8-transposec_arm64_standalone",
-    ":x8-zip_arm64_standalone",
     ":xx-copy_arm64_standalone",
     ":xx-fill_arm64_standalone",
     ":xx-pad_arm64_standalone",
@@ -1496,7 +1468,6 @@
       "src/src/configs/x8-lut-config.c",
       "src/src/configs/xx-fill-config.c",
       "src/src/configs/xx-pad-config.c",
-      "src/src/configs/zip-config.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -1546,7 +1517,6 @@
       "src/src/configs/x8-lut-config.c",
       "src/src/configs/xx-fill-config.c",
       "src/src/configs/xx-pad-config.c",
-      "src/src/configs/zip-config.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12917,7 +12887,6 @@
       "src/src/operators/average-pooling-nhwc.c",
       "src/src/operators/batch-matrix-multiply-nc.c",
       "src/src/operators/binary-elementwise-nd.c",
-      "src/src/operators/channel-shuffle-nc.c",
       "src/src/operators/constant-pad-nd.c",
       "src/src/operators/convolution-nchw.c",
       "src/src/operators/convolution-nhwc.c",
@@ -12962,7 +12931,6 @@
       "src/src/operators/average-pooling-nhwc.c",
       "src/src/operators/batch-matrix-multiply-nc.c",
       "src/src/operators/binary-elementwise-nd.c",
-      "src/src/operators/channel-shuffle-nc.c",
       "src/src/operators/constant-pad-nd.c",
       "src/src/operators/convolution-nchw.c",
       "src/src/operators/convolution-nhwc.c",
@@ -16862,6 +16830,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-avx256vnni-prfm.c",
+      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-avx256vnni-prfm.c",
       "src/src/qs8-packw/gen/qs8-packw-x8c8-gemm-goi-avx256vnni-prfm.c",
     ]
 
@@ -16896,6 +16865,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-avx256vnni-prfm.c",
+      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-avx256vnni-prfm.c",
       "src/src/qs8-packw/gen/qs8-packw-x8c8-gemm-goi-avx256vnni-prfm.c",
     ]
 
@@ -16923,7 +16893,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-scalar.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -16947,188 +16916,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("qs8-qc4w-packw_avx2-avxvnni-f16c-fma") {
-    cflags = [
-      "-mavx2",
-      "-mavxvnni",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avxvnni-prfm.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("qs8-qc4w-packw_avx2-avxvnni-f16c-fma_standalone") {
-    cflags = [
-      "-mavx2",
-      "-mavxvnni",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avxvnni-prfm.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set(
-      "qs8-qc4w-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni") {
-    cflags = [
-      "-mavx512bw",
-      "-mavx512cd",
-      "-mavx512dq",
-      "-mavx512f",
-      "-mavx512vl",
-      "-mavx512vnni",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-avx256vnni-prfm.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avx256vnni-prfm.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set(
-      "qs8-qc4w-packw_f16c-fma-avx512f-avx512cd-avx512bw-avx512dq-avx512vl-avx512vnni_standalone") {
-    cflags = [
-      "-mavx512bw",
-      "-mavx512cd",
-      "-mavx512dq",
-      "-mavx512f",
-      "-mavx512vl",
-      "-mavx512vnni",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-avx256vnni-prfm.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avx256vnni-prfm.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("qs8-qc4w-packw_x64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("qs8-qc4w-packw_x64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-scalar.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -24970,161 +24757,6 @@
     }
   }
 
-  source_set("s32-f32-vcvt_avx512f") {
-    cflags = [ "-mavx512f" ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-avx512f.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("s32-f32-vcvt_avx512f_standalone") {
-    cflags = [ "-mavx512f" ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-avx512f.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("s32-f32-vcvt_f16c-fma-avx2") {
-    cflags = [
-      "-mavx2",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-avx2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("s32-f32-vcvt_f16c-fma-avx2_standalone") {
-    cflags = [
-      "-mavx2",
-      "-mf16c",
-      "-mfma",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-avx2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("s32-f32-vcvt_x64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("s32-f32-vcvt_x64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("s8-ibilinear_sse2-no-sse3") {
     cflags = [
       "-mno-sse3",
@@ -27398,122 +27030,6 @@
     }
   }
 
-  source_set("x32-zip_sse2-no-sse3") {
-    cflags = [
-      "-mno-sse3",
-      "-msse2",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-sse2.c",
-      "src/src/x32-zip/x32-zip-x3-sse2.c",
-      "src/src/x32-zip/x32-zip-x4-sse2.c",
-      "src/src/x32-zip/x32-zip-xm-sse2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x32-zip_sse2-no-sse3_standalone") {
-    cflags = [
-      "-mno-sse3",
-      "-msse2",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-sse2.c",
-      "src/src/x32-zip/x32-zip-x3-sse2.c",
-      "src/src/x32-zip/x32-zip-x4-sse2.c",
-      "src/src/x32-zip/x32-zip-xm-sse2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("x32-zip_x64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-scalar.c",
-      "src/src/x32-zip/x32-zip-x3-scalar.c",
-      "src/src/x32-zip/x32-zip-x4-scalar.c",
-      "src/src/x32-zip/x32-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x32-zip_x64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-scalar.c",
-      "src/src/x32-zip/x32-zip-x3-scalar.c",
-      "src/src/x32-zip/x32-zip-x4-scalar.c",
-      "src/src/x32-zip/x32-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("x64-transposec_avx-no-avx2-no-f16c-no-fma") {
     cflags = [
       "-mavx",
@@ -28242,122 +27758,6 @@
     }
   }
 
-  source_set("x8-zip_sse2-no-sse3") {
-    cflags = [
-      "-mno-sse3",
-      "-msse2",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-sse2.c",
-      "src/src/x8-zip/x8-zip-x3-sse2.c",
-      "src/src/x8-zip/x8-zip-x4-sse2.c",
-      "src/src/x8-zip/x8-zip-xm-sse2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x8-zip_sse2-no-sse3_standalone") {
-    cflags = [
-      "-mno-sse3",
-      "-msse2",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-sse2.c",
-      "src/src/x8-zip/x8-zip-x3-sse2.c",
-      "src/src/x8-zip/x8-zip-x4-sse2.c",
-      "src/src/x8-zip/x8-zip-xm-sse2.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("x8-zip_x64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-scalar.c",
-      "src/src/x8-zip/x8-zip-x3-scalar.c",
-      "src/src/x8-zip/x8-zip-x4-scalar.c",
-      "src/src/x8-zip/x8-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x8-zip_x64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-scalar.c",
-      "src/src/x8-zip/x8-zip-x3-scalar.c",
-      "src/src/x8-zip/x8-zip-x4-scalar.c",
-      "src/src/x8-zip/x8-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("xx-copy_x64") {
     cflags = []
 
@@ -28698,7 +28098,6 @@
       "src/src/configs/x8-lut-config.c",
       "src/src/configs/xx-fill-config.c",
       "src/src/configs/xx-pad-config.c",
-      "src/src/configs/zip-config.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -28748,7 +28147,6 @@
       "src/src/configs/x8-lut-config.c",
       "src/src/configs/xx-fill-config.c",
       "src/src/configs/xx-pad-config.c",
-      "src/src/configs/zip-config.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -33279,7 +32677,6 @@
       "src/src/operators/average-pooling-nhwc.c",
       "src/src/operators/batch-matrix-multiply-nc.c",
       "src/src/operators/binary-elementwise-nd.c",
-      "src/src/operators/channel-shuffle-nc.c",
       "src/src/operators/constant-pad-nd.c",
       "src/src/operators/convolution-nchw.c",
       "src/src/operators/convolution-nhwc.c",
@@ -33324,7 +32721,6 @@
       "src/src/operators/average-pooling-nhwc.c",
       "src/src/operators/batch-matrix-multiply-nc.c",
       "src/src/operators/binary-elementwise-nd.c",
-      "src/src/operators/channel-shuffle-nc.c",
       "src/src/operators/constant-pad-nd.c",
       "src/src/operators/convolution-nchw.c",
       "src/src/operators/convolution-nhwc.c",
@@ -35320,7 +34716,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-scalar.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35344,58 +34739,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
-  source_set("qs8-qc4w-packw_arm64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("qs8-qc4w-packw_arm64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-scalar.c",
-      "src/src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-scalar.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -37391,57 +36734,6 @@
     }
   }
 
-  source_set("s32-f32-vcvt_arm64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-neon.c",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("s32-f32-vcvt_arm64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-neon.c",
-      "src/src/s32-f32-vcvt/gen/s32-f32-vcvt-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("s8-ibilinear_arm64") {
     cflags = []
 
@@ -38340,69 +37632,6 @@
     }
   }
 
-  source_set("x32-zip_arm64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-neon.c",
-      "src/src/x32-zip/x32-zip-x2-scalar.c",
-      "src/src/x32-zip/x32-zip-x3-neon.c",
-      "src/src/x32-zip/x32-zip-x3-scalar.c",
-      "src/src/x32-zip/x32-zip-x4-neon.c",
-      "src/src/x32-zip/x32-zip-x4-scalar.c",
-      "src/src/x32-zip/x32-zip-xm-neon.c",
-      "src/src/x32-zip/x32-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x32-zip_arm64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x32-zip/x32-zip-x2-neon.c",
-      "src/src/x32-zip/x32-zip-x2-scalar.c",
-      "src/src/x32-zip/x32-zip-x3-neon.c",
-      "src/src/x32-zip/x32-zip-x3-scalar.c",
-      "src/src/x32-zip/x32-zip-x4-neon.c",
-      "src/src/x32-zip/x32-zip-x4-scalar.c",
-      "src/src/x32-zip/x32-zip-xm-neon.c",
-      "src/src/x32-zip/x32-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("x64-transposec_arm64") {
     cflags = []
 
@@ -38664,69 +37893,6 @@
     }
   }
 
-  source_set("x8-zip_arm64") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-neon.c",
-      "src/src/x8-zip/x8-zip-x2-scalar.c",
-      "src/src/x8-zip/x8-zip-x3-neon.c",
-      "src/src/x8-zip/x8-zip-x3-scalar.c",
-      "src/src/x8-zip/x8-zip-x4-neon.c",
-      "src/src/x8-zip/x8-zip-x4-scalar.c",
-      "src/src/x8-zip/x8-zip-xm-neon.c",
-      "src/src/x8-zip/x8-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-  }
-
-  # This is a target that cannot depend on //base.
-  source_set("x8-zip_arm64_standalone") {
-    cflags = []
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/x8-zip/x8-zip-x2-neon.c",
-      "src/src/x8-zip/x8-zip-x2-scalar.c",
-      "src/src/x8-zip/x8-zip-x3-neon.c",
-      "src/src/x8-zip/x8-zip-x3-scalar.c",
-      "src/src/x8-zip/x8-zip-x4-neon.c",
-      "src/src/x8-zip/x8-zip-x4-scalar.c",
-      "src/src/x8-zip/x8-zip-xm-neon.c",
-      "src/src/x8-zip/x8-zip-xm-scalar.c",
-    ]
-
-    configs -= [ "//build/config/compiler:chromium_code" ]
-    configs += [ "//build/config/compiler:no_chromium_code" ]
-    configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ]
-
-    deps = [
-      "//third_party/cpuinfo",
-      "//third_party/fp16",
-      "//third_party/fxdiv",
-      "//third_party/pthreadpool:pthreadpool_standalone",
-    ]
-
-    public_configs = [ ":xnnpack_config" ]
-
-    if (!(is_android && use_order_profiling)) {
-      assert_no_deps = [ "//base" ]
-    }
-  }
-
   source_set("xx-copy_arm64") {
     cflags = []
 
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium
index fad85df..f06460ae 100644
--- a/third_party/xnnpack/README.chromium
+++ b/third_party/xnnpack/README.chromium
@@ -1,8 +1,8 @@
 Name: XNNPACK
 Short Name: xnnpack
 URL: https://github.com/google/xnnpack
-Version: acb51c63d59d36b663e959b89a93f0e085e80ac0
-Date: 2024-12-09
+Version: 0824e2965f6edc2297e55c8dff5a8ac4cb12aaad
+Date: 2025-01-08
 License: BSD-3-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/xnnpack/build_identifier.c b/third_party/xnnpack/build_identifier.c
index 97b79af6..83eeab8 100644
--- a/third_party/xnnpack/build_identifier.c
+++ b/third_party/xnnpack/build_identifier.c
@@ -604,15 +604,10 @@
 // - src/qs8-f32-vcvt/gen/qs8-f32-vcvt-sse41-u16.c
 // - src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-avx256vnni-prfm.c
 // - src/qs8-packw/gen/qs8-packw-x16c8-gemm-goi-scalar.c
-// - src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-scalar.c
+// - src/qs8-packw/gen/qs8-packw-x64c4-gemm-goi-avx256vnni-prfm.c
 // - src/qs8-packw/gen/qs8-packw-x8c8-gemm-goi-avx256vnni-prfm.c
 // - src/qs8-packw/gen/qs8-packw-x8c8-gemm-goi-avxvnni-prfm.c
 // - src/qs8-packw/gen/qs8-packw-x8c8-gemm-goi-avxvnni.c
-// - src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-avx256vnni-prfm.c
-// - src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x16c8-gemm-goi-scalar.c
-// - src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avx256vnni-prfm.c
-// - src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-avxvnni-prfm.c
-// - src/qs8-qc4w-packw/gen/qs8-qc4w-packw-x8c8-gemm-goi-scalar.c
 // - src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-avx-mul16-add16.c
 // - src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-avx2-mul32.c
 // - src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c
@@ -832,9 +827,6 @@
 // - src/qu8-vmulc/gen/qu8-vmulc-minmax-fp32-sse2-mul16-ld64-u8.c
 // - src/qu8-vmulc/gen/qu8-vmulc-minmax-fp32-sse41-mul16-ld64-u16.c
 // - src/reference/packing.cc
-// - src/s32-f32-vcvt/gen/s32-f32-vcvt-avx2.c
-// - src/s32-f32-vcvt/gen/s32-f32-vcvt-avx512f.c
-// - src/s32-f32-vcvt/gen/s32-f32-vcvt-scalar.c
 // - src/s8-ibilinear/gen/s8-ibilinear-scalar-c1.c
 // - src/s8-ibilinear/gen/s8-ibilinear-sse2-c8.c
 // - src/s8-ibilinear/gen/s8-ibilinear-sse41-c16.c
@@ -888,14 +880,6 @@
 // - src/x32-transposec/x32-transposec-4x4-sse.c
 // - src/x32-unpool/x32-unpool-scalar.c
 // - src/x32-unpool/x32-unpool-sse2.c
-// - src/x32-zip/x32-zip-x2-scalar.c
-// - src/x32-zip/x32-zip-x2-sse2.c
-// - src/x32-zip/x32-zip-x3-scalar.c
-// - src/x32-zip/x32-zip-x3-sse2.c
-// - src/x32-zip/x32-zip-x4-scalar.c
-// - src/x32-zip/x32-zip-x4-sse2.c
-// - src/x32-zip/x32-zip-xm-scalar.c
-// - src/x32-zip/x32-zip-xm-sse2.c
 // - src/x64-transposec/gen/x64-transposec-2x2-multi-mov-sse2.c
 // - src/x64-transposec/gen/x64-transposec-4x2-scalar-int.c
 // - src/x64-transposec/gen/x64-transposec-4x4-reuse-multi-avx.c
@@ -912,14 +896,6 @@
 // - src/x8-transposec/gen/x8-transposec-16x16-reuse-mov-sse2.c
 // - src/x8-transposec/gen/x8-transposec-2x4-scalar-int.c
 // - src/x8-transposec/gen/x8-transposec-32x32-reuse-switch-avx2.c
-// - src/x8-zip/x8-zip-x2-scalar.c
-// - src/x8-zip/x8-zip-x2-sse2.c
-// - src/x8-zip/x8-zip-x3-scalar.c
-// - src/x8-zip/x8-zip-x3-sse2.c
-// - src/x8-zip/x8-zip-x4-scalar.c
-// - src/x8-zip/x8-zip-x4-sse2.c
-// - src/x8-zip/x8-zip-xm-scalar.c
-// - src/x8-zip/x8-zip-xm-sse2.c
 // - src/xx-copy/xx-copy-scalar-memcpy.c
 // - src/xx-fill/xx-fill-scalar-u16.c
 // - src/xx-fill/xx-fill-sse2-u64.c
@@ -933,10 +909,10 @@
 #include <string.h>
 
 static const uint8_t xnn_build_identifier[] = {
-  134,  14, 156, 130,  30, 132,  68,  25,
-   79, 183, 144, 102,   1, 152, 248, 226,
-  248,  39,  21,   0,  87,  30,  69, 153,
-   81,  20,  12, 245,  44,  98, 182, 103
+    1,  80, 140, 209,  11,  70,  27,  98,
+   18, 206, 157,  40,  28, 164,  23,  45,
+  130, 131,  18,   8, 147,  49,  85,  43,
+   83,  53, 152, 105, 176, 155, 245, 108
 };
 
 size_t xnn_experimental_get_build_identifier_size() {
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src
index 7440eee..0824e29 160000
--- a/third_party/xnnpack/src
+++ b/third_party/xnnpack/src
@@ -1 +1 @@
-Subproject commit 7440eee88f66c4b81d4e7d31f6ae07af66e059ea
+Subproject commit 0824e2965f6edc2297e55c8dff5a8ac4cb12aaad
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 46998cc..b146c16 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -47536,6 +47536,8 @@
       label="For displaying the supervised user sign-in IPH."/>
   <suffix name="TabAudioMuting" label="For TabAudioMuting feature."/>
   <suffix name="TabGroupsDragAndDrop" label="For drop-to-merge in tab group."/>
+  <suffix name="TabGroupShareNotificationBubbleOnStrip"
+      label="For tab group share notification bubble on tablet tab strip."/>
   <suffix name="TabGroupsQuicklyComparePages"
       label="For long press links to create tab groups."/>
   <suffix name="TabGroupsRemoteGroup" label="For a synced tab group."/>
@@ -47547,7 +47549,8 @@
   <suffix name="TabGroupsSurfaceOnHide"
       label="For tab group surface after hiding a tab group while on the GTS."/>
   <suffix name="TabGroupsTapToSeeAnotherTab" label="For tab strip."/>
-  <suffix name="TabGroupSyncOnStrip" label="For tab group sync on tab strip."/>
+  <suffix name="TabGroupSyncOnStrip"
+      label="For tab group sync on tablet tab strip."/>
   <suffix name="TabGroupsYourTabsTogether"
       label="For tab switcher with tab groups."/>
   <suffix name="TabOrganizationSuccess"
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 3ecfb3a6..1574638 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -7370,7 +7370,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Search.{Provider}Provider.QueryTime" units="ms"
-    expires_after="2025-06-08">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>jopalmer@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -7396,7 +7396,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Session.InputReadyLatency" units="ms"
-    expires_after="2025-07-06">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>jopalmer@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -7410,7 +7410,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Session.Outcome" enum="PickerSessionOutcome"
-    expires_after="2025-06-08">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -7420,7 +7420,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Session.PresentationLatency.SearchField" units="ms"
-    expires_after="2025-05-11">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>jopalmer@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -7434,7 +7434,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Session.PresentationLatency.SearchResults"
-    units="ms" expires_after="2025-06-08">
+    units="ms" expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>jopalmer@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -7448,7 +7448,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.Session.SearchLatency" units="ms"
-    expires_after="2025-06-08">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>jopalmer@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -7462,7 +7462,7 @@
 </histogram>
 
 <histogram name="Ash.Picker.TimeToFirstGifFrame" units="ms"
-    expires_after="2024-12-31">
+    expires_after="2025-12-31">
   <owner>shend@chromium.org</owner>
   <owner>michellegc@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index 4a38a070..a569cf7 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -552,6 +552,8 @@
   <variant name="IPH_TabAudioMuting" summary="muting tab audio"/>
   <variant name="IPH_TabGroupsDragAndDrop"
       summary="educating user to drop one tab on another tab to create group"/>
+  <variant name="IPH_TabGroupSharedNotificationBubbleOnStrip"
+      summary="For tab group share notification bubble on tablet tab strip."/>
   <variant name="IPH_TabGroupsQuicklyComparePages"
       summary="(obsolete) long pressing a link to open in a tab group"/>
   <variant name="IPH_TabGroupsRemoteGroup"
@@ -567,7 +569,7 @@
   <variant name="IPH_TabGroupsTapToSeeAnotherTab"
       summary="(obsolete) tab strip"/>
   <variant name="IPH_TabGroupSyncOnStrip"
-      summary="For tab group sync on tab strip."/>
+      summary="For tab group sync on tablet tab strip."/>
   <variant name="IPH_TabGroupsYourTabsTogether"
       summary="tab switcher cards with multiple tab thumbnails"/>
   <variant name="IPH_TabOrganizationSuccess"
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 4501f54..274653e 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -2227,7 +2227,7 @@
 </histogram>
 
 <histogram name="Net.HttpJob.ProxyTypeFailed" enum="ProxyScheme"
-    expires_after="2025-02-10">
+    expires_after="2025-04-10">
   <owner>rch@chromium.org</owner>
   <owner>djmitche@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -2241,7 +2241,7 @@
 </histogram>
 
 <histogram name="Net.HttpJob.ProxyTypeSuccess" enum="ProxyScheme"
-    expires_after="2025-02-10">
+    expires_after="2025-04-10">
   <owner>rch@chromium.org</owner>
   <owner>djmitche@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a2b3165..e3c0b567 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v49.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "d99ae0124dbfa94f91dd685422c7cb0ffd4052e0",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/e324242074e2e64a65e90a2933afd3ca4413554f/trace_processor_shell"
+            "hash": "dcc509ec51017ea9e1cf5f40916cb520ddc70611",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/c6ea87b5b19e6b2798f290b000bb3609c9018c81/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 4c53fa7..75ffc37 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -39,6 +39,7 @@
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/layer_delegate.h"
 #include "ui/compositor/layer_observer.h"
+#include "ui/compositor/layer_type.h"
 #include "ui/compositor/paint_context.h"
 #include "ui/gfx/animation/animation.h"
 #include "ui/gfx/canvas.h"
@@ -219,6 +220,11 @@
       backdrop_filter_quality_(1.0f),
       trilinear_filtering_request_(0) {
   CreateCcLayer();
+
+  // For LAYER_SOLID_COLOR, the background color dictates content opaqueness.
+  if (type_ == LAYER_SOLID_COLOR) {
+    fills_bounds_opaquely_ = cc_layer_->background_color().isOpaque();
+  }
 }
 
 Layer::~Layer() {
@@ -1221,6 +1227,7 @@
     return;
 
   solid_color_layer_ = new_layer;
+  fills_bounds_opaquely_ = cc_layer_->background_color().isOpaque();
 
   transfer_resource_ = viz::TransferableResource();
   if (transfer_release_callback_) {
@@ -1688,6 +1695,10 @@
 void Layer::SetColorFromAnimation(SkColor4f color,
                                   PropertyChangeReason reason) {
   DCHECK_EQ(type_, LAYER_SOLID_COLOR);
+
+  // For LAYER_SOLID_COLOR, the background color dictates content opaqueness.
+  // And `SetContentOpaque()` is called in
+  // `SolidColorLayer::SetBackgroundColor()`.
   cc_layer_->SetBackgroundColor(color);
   cc_layer_->SetSafeOpaqueBackgroundColor(color);
   SetFillsBoundsOpaquelyWithReason(color.isOpaque(), reason);
@@ -1814,11 +1825,20 @@
     cc_layer_ = content_layer_.get();
   }
   cc_layer_->SetTransformOrigin(gfx::Point3F());
-  cc_layer_->SetContentsOpaque(true);
-  cc_layer_->SetSafeOpaqueBackgroundColor(SkColors::kWhite);
   cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN);
   cc_layer_->SetHitTestable(IsHitTestableForCC());
   cc_layer_->SetElementId(cc::ElementId(cc_layer_->id()));
+  cc_layer_->SetBackgroundColor(SkColors::kTransparent);
+  cc_layer_->SetSafeOpaqueBackgroundColor(
+      type_ == LAYER_SOLID_COLOR ? SkColors::kBlack : SkColors::kWhite);
+
+  // For LAYER_SOLID_COLOR, the background color dictates content opaqueness.
+  // And `SetContentOpaque()` is called in
+  // `cc::SolidColorLayer::SetBackgroundColor()`.
+  if (type_ != LAYER_SOLID_COLOR) {
+    cc_layer_->SetContentsOpaque(true);
+  }
+
   RecomputePosition();
 }
 
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index a9ba231..729a8f2 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -765,7 +765,7 @@
   // does not affect the layer's descendants.
   bool accept_events_ = true;
 
-  // See SetFillsBoundsOpaquely(). Defaults to true.
+  // See SetFillsBoundsOpaquely().
   bool fills_bounds_opaquely_;
 
   bool fills_bounds_completely_;
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 0976aaf..6bf2754 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -47,6 +47,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/layer_animation_element.h"
@@ -54,6 +55,7 @@
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/layer_delegate.h"
+#include "ui/compositor/layer_type.h"
 #include "ui/compositor/paint_context.h"
 #include "ui/compositor/paint_recorder.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -1090,6 +1092,55 @@
   std::unique_ptr<NullLayerDelegate> default_layer_delegate_;
 };
 
+TEST_F(LayerWithNullDelegateTest, LayerContentOpaqueness) {
+  std::unique_ptr<Layer> layer = CreateLayer(LAYER_TEXTURED);
+
+  EXPECT_EQ(layer->cc_layer_for_testing()->background_color(),
+            SkColors::kTransparent);
+  EXPECT_EQ(layer->cc_layer_for_testing()->SafeOpaqueBackgroundColor(),
+            SkColors::kWhite);
+  EXPECT_TRUE(layer->fills_bounds_opaquely());
+  EXPECT_TRUE(layer->cc_layer_for_testing()->contents_opaque());
+
+  layer->SetFillsBoundsOpaquely(false);
+  EXPECT_EQ(layer->cc_layer_for_testing()->background_color(),
+            SkColors::kTransparent);
+  EXPECT_EQ(layer->cc_layer_for_testing()->SafeOpaqueBackgroundColor(),
+            SkColors::kTransparent);
+  EXPECT_FALSE(layer->fills_bounds_opaquely());
+  EXPECT_FALSE(layer->cc_layer_for_testing()->contents_opaque());
+
+  // For LAYER_SOLID_COLOR, the background color dictates content opaqueness.
+  layer = CreateLayer(LAYER_SOLID_COLOR);
+
+  // The default background color is transparent.
+  EXPECT_EQ(layer->cc_layer_for_testing()->background_color(),
+            SkColors::kTransparent);
+  EXPECT_EQ(layer->cc_layer_for_testing()->SafeOpaqueBackgroundColor(),
+            SkColors::kTransparent);
+  EXPECT_FALSE(layer->fills_bounds_opaquely());
+  EXPECT_FALSE(layer->cc_layer_for_testing()->contents_opaque());
+
+  // Set an opaque color.
+  layer->SetColor(SK_ColorRED);
+  EXPECT_EQ(layer->cc_layer_for_testing()->background_color(), SkColors::kRed);
+  EXPECT_EQ(layer->cc_layer_for_testing()->SafeOpaqueBackgroundColor(),
+            SkColors::kRed);
+  EXPECT_TRUE(layer->fills_bounds_opaquely());
+  EXPECT_TRUE(layer->cc_layer_for_testing()->contents_opaque());
+
+  // Set color with alpha.
+  const SkColor4f color_with_alpha =
+      SkColor4f::FromColor(SkColorSetARGB(100, 255, 0, 0));
+  layer->SetColor(color_with_alpha.toSkColor());
+  EXPECT_EQ(layer->cc_layer_for_testing()->background_color(),
+            color_with_alpha);
+  EXPECT_EQ(layer->cc_layer_for_testing()->SafeOpaqueBackgroundColor(),
+            color_with_alpha);
+  EXPECT_FALSE(layer->fills_bounds_opaquely());
+  EXPECT_FALSE(layer->cc_layer_for_testing()->contents_opaque());
+}
+
 TEST_F(LayerWithNullDelegateTest, SwitchLayerPreservesCCLayerState) {
   std::unique_ptr<Layer> l1 = CreateLayer(LAYER_SOLID_COLOR);
   l1->SetFillsBoundsOpaquely(true);
@@ -1099,6 +1150,7 @@
   constexpr gfx::RoundedCornersF kCornerRadii(1, 2, 3, 4);
   l1->SetRoundedCornerRadius(kCornerRadii);
   l1->SetIsFastRoundedCorner(true);
+  l1->SetColor(SK_ColorBLACK);
   constexpr viz::SubtreeCaptureId kSubtreeCaptureId(base::Token(0u, 22u));
   l1->SetSubtreeCaptureId(kSubtreeCaptureId);
   gfx::LinearGradient gradient_mask(45);
@@ -1108,6 +1160,7 @@
   EXPECT_EQ(gfx::Point3F(), l1->cc_layer_for_testing()->transform_origin());
   EXPECT_TRUE(l1->cc_layer_for_testing()->draws_content());
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
+  EXPECT_EQ(l1->cc_layer_for_testing()->background_color(), SkColors::kBlack);
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
   EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
@@ -1135,6 +1188,7 @@
   EXPECT_EQ(gfx::Point3F(), l1->cc_layer_for_testing()->transform_origin());
   EXPECT_TRUE(l1->cc_layer_for_testing()->draws_content());
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
+  EXPECT_EQ(l1->cc_layer_for_testing()->background_color(), SkColors::kBlack);
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
   EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());