diff --git a/.gitignore b/.gitignore
index 6d29c75..46957252 100644
--- a/.gitignore
+++ b/.gitignore
@@ -334,6 +334,7 @@
 
 # Buckup files that are generated by //tools/metrics/histograms/pretty_print.py in presubmit.
 /*.before.pretty-print.xml
+/tools/metrics/structured/sync/structured.old.xml
 
 # Extensions: Generated DNR e.g. /_metadata/generated_indexed_rulesets/_ruleset1
 **/_metadata/generated_indexed_rulesets/
diff --git a/.gitmodules b/.gitmodules
index 55266c1..5f0e7c8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -542,6 +542,10 @@
 [submodule "third_party/search_engines_data/resources"]
 	path = third_party/search_engines_data/resources
 	url = https://chromium.googlesource.com/external/search_engines_data
+[submodule "third_party/search_engines_data/resources_internal"]
+	path = third_party/search_engines_data/resources_internal
+	url = https://chrome-internal.googlesource.com/external/search_engines_data_internal
+	gclient-condition = checkout_src_internal
 [submodule "third_party/skia"]
 	path = third_party/skia
 	url = https://skia.googlesource.com/skia
diff --git a/DEPS b/DEPS
index 4dcbab7..5d1da502 100644
--- a/DEPS
+++ b/DEPS
@@ -295,19 +295,19 @@
   # 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': 'ceb7c2b2a31d272f5dae507665b9a1f891f8676d',
+  'src_internal_revision': '4611c0803480dede3396370ade3f85c313348f8a',
   # 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': '60646997b471616ef833e5af7b395019a2cbb026',
+  'skia_revision': '13a299964c9f66e7af63defde83b9c03055fa304',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '5ab97a63041bd352dc145b8311e6fcb7814ab690',
+  'v8_revision': '6dc75f0da012c4a9f638b78eefa86876a8349e77',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'b4d39a07b317257d31b1fa3cdb2aecd822918ca7',
+  'angle_revision': 'dcbcee8ab32af9ddc7ae1e91c42d995e5281602c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -315,7 +315,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '0be9b6bf152df319d17d9e4b05b2845d3226f5a5',
+  'pdfium_revision': '9d59dcd0a1e2781f2ac5c1c5f3ddb77e06173912',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -375,7 +375,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': 'de2f8a499257e1622a1c122fab1c84a46b98e469',
+  'crossbench_revision': '85adce1424ed4df795f8c810fc1a8ee22bffe3fa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -415,7 +415,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': 'c4b1eaf4958270e3a14c361720792dd073d6e4c5',
+  'dawn_revision': 'a3bfb33a777c75f77da36a7eb5ea4be24b86810f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1486,7 +1486,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'e899bd830b7f2571c4f3054290353a35f85ed0f6',
+    'de8849c98f8b6f841b915b569f38ac6c7e3cbf77',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1645,7 +1645,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'Lnwi6S4AHbruhZPbul63nDrhnbshtefsUCrilju6ptEC',
+          'version': '9gK5fctsrqSL7ITHbaKR8oEVCBo_gw0XIMzM9kvuSI0C',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -1990,7 +1990,7 @@
     Var('chromium_git') + '/external/github.com/jk-jeon/dragonbox.git' + '@' + '6c7c925b571d54486b9ffae8d9d18a822801cbda',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '729443409942a1816ddf74b95224003b83f4925c',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'ae3aba99db4c829b4cc4d9fdd54321dedd814dc4',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@@ -2500,7 +2500,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '652bdb7719f30b52b08e506645a7322ff1b2cc6f',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '4b64bb75ad30c5d9e170caa21c6f5065583cb49c',
+    Var('chromium_git') + '/openscreen' + '@' + '8cc5a0e8f6695263d44206cf5930641979cb3179',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '781f2eab3698d653c804ecbd11e0aed47eaad1c6',
@@ -2670,7 +2670,7 @@
     Var('chromium_git') + '/external/github.com/protocolbuffers/protobuf-javascript' + '@' + 'eb785a9363664a402b6336dfe96aad27fb33ffa8',
 
   'src/third_party/pthreadpool/src':
-    Var('chromium_git') + '/external/github.com/google/pthreadpool.git' + '@' + '290ee6fff0c36614702d6b297c148e3fa08e056a',
+    Var('chromium_git') + '/external/github.com/google/pthreadpool.git' + '@' + 'dcc9f28589066af0dbd4555579281230abbf74dd',
 
   # Dependency of skia.
   'src/third_party/pyelftools': {
@@ -2746,6 +2746,11 @@
   'src/third_party/search_engines_data/resources':
     Var('chromium_git') + '/external/search_engines_data.git' + '@' + 'c1a6f733f61d866e415f0e6a91b8e3d88cfbadea',
 
+  'src/third_party/search_engines_data/resources_internal': {
+    'url': Var('chrome_git') + '/external/search_engines_data_internal.git' + '@' + '665a33dd0140d181ed70ab33eda19e8c1c8c118d',
+    'condition': 'checkout_src_internal',
+  },
+
   'src/third_party/skia':
     Var('skia_git') + '/skia.git' + '@' +  Var('skia_revision'),
 
@@ -2827,7 +2832,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' + '@' + 'c4aa8ff91256b43fe0cecc246c77a00e2145b3bd',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '151774faba661a5985a8264653f4457c70a56dea',
 
   'src/third_party/turbine/cipd': {
       'packages': [
@@ -2918,7 +2923,7 @@
   },
 
   'src/third_party/xnnpack/src':
-    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '1b2beba83092bed68775b6e2433596627988c74b',
+    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'f82ad65ca52cb4d39b73088468a5fe00f56fb47c',
 
   'src/third_party/libei/cipd': {
 
@@ -3005,7 +3010,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'GnQgtoHVaf4bQUm9TxPaGiRJRQHjDcl8qQyO-kwu_MIC',
+        'version': 'keAY-vnasUZokMpEPoxPxhUIttbG3euVEtmSaLsne6IC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4520,7 +4525,7 @@
   # grepping.
   'src/chrome/installer/mac/internal': {
       'url': Var('chrome_git') + '/chrome/installer/mac/internal.git' + '@' +
-        '6460c6c38734ceabe0bb49c02640b6c2040b1e63',
+        'f6030c49cc22768ce47357e5a35e872cec925a65',
       'condition': 'checkout_src_internal',
   },
 
@@ -4614,7 +4619,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '82e030463d0f2a06bc82506a047a6a075ba69263',
+        '7062789227d77cf3b9d99e973da9b0ecc29056c9',
       'condition': 'checkout_src_internal',
   },
 
@@ -4692,7 +4697,7 @@
 
   'src/remoting/internal': {
       'url': Var('chrome_git') + '/chrome/remoting/internal.git' + '@' +
-        '4a463f330397bebbca3b05702e27f7a8450cada3',
+        'e2527eef826745f968d1e26247d7ba5d5b289012',
       'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/system/OWNERS b/ash/system/OWNERS
index 35354e5..37e29ee 100644
--- a/ash/system/OWNERS
+++ b/ash/system/OWNERS
@@ -5,6 +5,4 @@
 tbarzic@chromium.org
 
 per-file caps_lock_notification_controller*=jimmyxgong@chromium.org
-per-file caps_lock_notification_controller*=dpad@google.com
 per-file *brightness*=jimmyxgong@chromium.org
-per-file *brightness*=dpad@google.com
diff --git a/ash/system/brightness/OWNERS b/ash/system/brightness/OWNERS
index 79793ad8..e69de29 100644
--- a/ash/system/brightness/OWNERS
+++ b/ash/system/brightness/OWNERS
@@ -1 +0,0 @@
-per-file *controller*=dpad@google.com
diff --git a/base/android/java/src/org/chromium/base/DeviceInfo.java b/base/android/java/src/org/chromium/base/DeviceInfo.java
index e141743..dcb3b464 100644
--- a/base/android/java/src/org/chromium/base/DeviceInfo.java
+++ b/base/android/java/src/org/chromium/base/DeviceInfo.java
@@ -176,9 +176,7 @@
                 Build.VERSION.SDK_INT >= VERSION_CODES.R
                         && pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_HINGE_ANGLE);
 
-        mIsDesktop =
-                pm.hasSystemFeature(PackageManager.FEATURE_PC)
-                        || CommandLine.getInstance().hasSwitch(BaseSwitches.FORCE_DESKTOP_ANDROID);
+        mIsDesktop = pm.hasSystemFeature(PackageManager.FEATURE_PC);
 
         int vulkanLevel = 0;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
diff --git a/base/base_switches.cc b/base/base_switches.cc
index 3ed0d33..f67fc3b 100644
--- a/base/base_switches.cc
+++ b/base/base_switches.cc
@@ -163,10 +163,6 @@
 // Adds additional thread idle time information into the trace event output.
 const char kEnableIdleTracing[] = "enable-idle-tracing";
 
-// Forces the DeviceInfo.isDesktop() check to return true. Can be used to enable
-// desktop-only features on other form factors.
-const char kForceDesktopAndroid[] = "force-desktop-android";
-
 // When we retrieve the package name within the SDK Runtime, we need to use
 // a bit of a hack to do this by taking advantage of the fact that the pid
 // is the same pid as the application's pid + 10000.
diff --git a/base/base_switches.h b/base/base_switches.h
index 9abcdc0..9764270e 100644
--- a/base/base_switches.h
+++ b/base/base_switches.h
@@ -53,7 +53,6 @@
 extern const char kAndroidSkipChildServiceInitForTesting[];
 extern const char kDefaultCountryCodeAtInstall[];
 extern const char kEnableIdleTracing[];
-extern const char kForceDesktopAndroid[];
 extern const char kHostPackageName[];
 extern const char kHostPackageLabel[];
 extern const char kHostVersionCode[];
diff --git a/build/config/siso/android.star b/build/config/siso/android.star
index 5a9fb155..1eac27ac 100644
--- a/build/config/siso/android.star
+++ b/build/config/siso/android.star
@@ -284,6 +284,7 @@
             "name": "android/partition_action",
             "command_prefix": "python3 ../../build/extract_partition.py",
             "remote": config.get(ctx, "remote-link") or config.get(ctx, "builder"),
+            "platform_ref": "large",
             "timeout": "4m",
         },
     ])
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc
index 6f6692fe..f48a650 100644
--- a/cc/mojo_embedder/viz_layer_context.cc
+++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -162,6 +162,16 @@
       old_node->subtree_size == new_node.subtree_size &&
       old_node->blend_mode == new_node.blend_mode &&
       old_node->target_id == new_node.target_id &&
+      old_node->view_transition_target_id ==
+          new_node.view_transition_target_id &&
+      old_node->closest_ancestor_with_cached_render_surface_id ==
+          new_node.closest_ancestor_with_cached_render_surface_id &&
+      old_node->closest_ancestor_with_copy_request_id ==
+          new_node.closest_ancestor_with_copy_request_id &&
+      old_node->closest_ancestor_being_captured_id ==
+          new_node.closest_ancestor_being_captured_id &&
+      old_node->closest_ancestor_with_shared_element_id ==
+          new_node.closest_ancestor_with_shared_element_id &&
       old_node->view_transition_element_resource_id ==
           new_node.view_transition_element_resource_id &&
       old_node->has_copy_request == new_node.has_copy_request &&
@@ -216,6 +226,15 @@
   wire->subtree_size = new_node.subtree_size;
   wire->blend_mode = base::checked_cast<uint32_t>(new_node.blend_mode);
   wire->target_id = new_node.target_id;
+  wire->view_transition_target_id = new_node.view_transition_target_id;
+  wire->closest_ancestor_with_cached_render_surface_id =
+      new_node.closest_ancestor_with_cached_render_surface_id;
+  wire->closest_ancestor_with_copy_request_id =
+      new_node.closest_ancestor_with_copy_request_id;
+  wire->closest_ancestor_being_captured_id =
+      new_node.closest_ancestor_being_captured_id;
+  wire->closest_ancestor_with_shared_element_id =
+      new_node.closest_ancestor_with_shared_element_id;
   wire->view_transition_element_resource_id =
       new_node.view_transition_element_resource_id;
   wire->copy_output_requests = std::move(copy_requests);
diff --git a/chrome/VERSION b/chrome/VERSION
index d674e4e..a9391cdd 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=138
 MINOR=0
-BUILD=7190
+BUILD=7191
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 6d86ae5b..4159ace 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -370,6 +370,7 @@
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderProperties.java",
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHeaderViewBinder.java",
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java",
+  "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithCheckboxViewBinder.java",
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithIconButtonProperties.java",
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithIconButtonViewBinder.java",
   "java/src/org/chromium/chrome/browser/contextmenu/ContextMenuListView.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetView.java
index 48ac79e..93b3aa8 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetView.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetView.java
@@ -185,11 +185,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return BottomSheetContent.HeightMode.DISABLED;
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetView.java
index 9d2e557b..c7a093ad 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetView.java
@@ -100,11 +100,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public boolean hideOnScroll() {
         return true;
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupShareNoticeBottomSheetView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupShareNoticeBottomSheetView.java
index 3428ef4..bb9c232a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupShareNoticeBottomSheetView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupShareNoticeBottomSheetView.java
@@ -86,11 +86,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public boolean hideOnScroll() {
         return true;
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index 84a610c..0adc19c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -117,7 +117,6 @@
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;
-import org.chromium.ui.util.MotionEventUtils;
 import org.chromium.ui.util.XrUtils;
 import org.chromium.url.GURL;
 
@@ -1199,8 +1198,7 @@
                         Tab currentTab = TabModelUtils.getCurrentTab(tabModel);
                         Tab nextTab = currentTab == closingTab ? getNextTab(tabId) : null;
                         boolean allowUndo =
-                                triggeringMotionEvent == null
-                                        || !MotionEventUtils.isMouseEvent(triggeringMotionEvent);
+                                TabClosureParamsUtils.shouldAllowUndo(triggeringMotionEvent);
                         TabClosureParams closureParams =
                                 TabClosureParams.closeTab(closingTab)
                                         .recommendedNextTab(nextTab)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/archived_tabs_auto_delete_promo/ArchivedTabsAutoDeletePromoSheetContent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/archived_tabs_auto_delete_promo/ArchivedTabsAutoDeletePromoSheetContent.java
index 3790d45..bbbc0631 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/archived_tabs_auto_delete_promo/ArchivedTabsAutoDeletePromoSheetContent.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/archived_tabs_auto_delete_promo/ArchivedTabsAutoDeletePromoSheetContent.java
@@ -63,11 +63,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
index 9325db30..b6b70a98 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
@@ -87,7 +87,7 @@
     @Rule
     public ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus()
-                    .setRevision(7)
+                    .setRevision(8)
                     .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_MOBILE_HUB)
                     .build();
 
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java
index d7e74b1..ffaa29bf 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java
@@ -146,6 +146,7 @@
             ChromeRenderTestRule.Builder.withPublicCorpus()
                     .setBugComponent(
                             ChromeRenderTestRule.Component.UI_BROWSER_CONTENT_SUGGESTIONS_FEED)
+                    .setRevision(1)
                     .build();
 
     public final SigninTestRule mSigninTestRule = new SigninTestRule();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/iban/AutofillSaveIbanBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/iban/AutofillSaveIbanBottomSheetContent.java
index 6b43affa..be4316e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/iban/AutofillSaveIbanBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/iban/AutofillSaveIbanBottomSheetContent.java
@@ -61,11 +61,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetContent.java
index 61c1381..2db631da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/save_card/AutofillSaveCardBottomSheetContent.java
@@ -85,11 +85,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public boolean hideOnScroll() {
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetContent.java
index d3d2897..78c565f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetContent.java
@@ -94,11 +94,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 0944c40..d7dd4bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -91,6 +91,7 @@
 import org.chromium.chrome.browser.tab_group_sync.TabGroupSyncServiceFactory;
 import org.chromium.chrome.browser.tab_ui.ActionConfirmationManager;
 import org.chromium.chrome.browser.tabmodel.TabClosureParams;
+import org.chromium.chrome.browser.tabmodel.TabClosureParamsUtils;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabGroupColorUtils;
 import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
@@ -2919,10 +2920,7 @@
                     handleCloseTab(tab, tabClosureParams.allowUndo);
                 };
 
-        // Allow undo of tab closure only when the click wasn't from a button on peripherals like
-        // mouses, trackpads, etc.
-        boolean allowUndo = (motionEventButtonState == MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
-
+        boolean allowUndo = TabClosureParamsUtils.shouldAllowUndo(motionEventButtonState);
         TabClosureParams params = TabClosureParams.closeTab(realTab).allowUndo(allowUndo).build();
         mTabGroupModelFilter
                 .getTabModel()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
index 1bef33f..91c3d80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuCoordinator.java
@@ -345,6 +345,10 @@
                 ListItemType.CONTEXT_MENU_ITEM_WITH_ICON_BUTTON,
                 new LayoutViewBuilder(R.layout.context_menu_share_row),
                 ContextMenuItemWithIconButtonViewBinder::bind);
+        adapter.registerType(
+                ListItemType.CONTEXT_MENU_ITEM_WITH_CHECKBOX,
+                new LayoutViewBuilder<>(R.layout.checkbox_layout),
+                ContextMenuItemWithCheckboxViewBinder::bind);
 
         mListView.setOnItemClickListener(
                 (p, v, pos, id) -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithCheckboxViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithCheckboxViewBinder.java
new file mode 100644
index 0000000..3ce42832
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemWithCheckboxViewBinder.java
@@ -0,0 +1,42 @@
+// 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.
+
+package org.chromium.chrome.browser.contextmenu;
+
+import static org.chromium.ui.listmenu.ContextMenuCheckItemProperties.CHECKED;
+import static org.chromium.ui.listmenu.ContextMenuCheckItemProperties.ENABLED;
+import static org.chromium.ui.listmenu.ContextMenuCheckItemProperties.TITLE;
+
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.ui.listmenu.ContextMenuCheckItemProperties;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * View binder for a context menu item with checkbox (of type {@code
+ * ListItemType.CONTEXT_MENU_ITEM_WITH_CHECKBOX}, with property keys {@link
+ * ContextMenuCheckItemProperties}).
+ */
+class ContextMenuItemWithCheckboxViewBinder {
+    public static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
+        CheckBox checkBox = view.findViewById(R.id.checkbox);
+        TextView title = view.findViewById(R.id.checkbox_title);
+
+        if (propertyKey == TITLE) {
+            title.setText(model.get(TITLE));
+        } else if (propertyKey == ENABLED) {
+            checkBox.setEnabled(model.get(ENABLED));
+            title.setEnabled(model.get(ENABLED));
+        } else if (propertyKey == CHECKED) {
+            checkBox.setChecked(model.get(CHECKED));
+        }
+        // MENU_ITEM_ID and ON_CLICK are used by the ContextMenuCoordinator.
+        // Note that because this will be an item inside of a list, this view itself does not need
+        // to implement the on-click behavior (it's handled by ContextMenuCoordinator).
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
index 2527020..2fcd59f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -32,6 +32,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
+import org.chromium.base.TimeUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
@@ -84,12 +85,13 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 class MultiInstanceManagerApi31 extends MultiInstanceManagerImpl implements ActivityStateListener {
     private static final String TAG = "MIMApi31";
     private static final String TAG_MULTI_INSTANCE = "MultiInstance";
     public static final int INVALID_TASK_ID = MultiWindowUtils.INVALID_TASK_ID;
-
+    /* package */ static final long SIX_MONTHS_MS = TimeUnit.DAYS.toMillis(6 * 30);
     private static final String EMPTY_DATA = "";
     private static MultiInstanceState sState;
 
@@ -413,8 +415,17 @@
                     type = InstanceInfo.Type.ADJACENT;
                 }
             }
-
             int taskId = getTaskFromMap(i);
+            // It is generally assumed and expected that the last-accessed time for the current
+            // activity is already updated to a "current" time when this method is called. However,
+            // we will avoid closing the current instance explicitly to avoid an unexpected outcome
+            // if this is not the case.
+            if (ChromeFeatureList.sDisableInstanceLimit.isEnabled()
+                    && isOlderThanSixMonths(readLastAccessedTime(i))
+                    && type != InstanceInfo.Type.CURRENT) {
+                closeInstance(i, taskId);
+                continue;
+            }
             result.add(
                     new InstanceInfo(
                             i,
@@ -427,13 +438,16 @@
                             readIncognitoSelected(i),
                             readLastAccessedTime(i)));
         }
-
         // Move the current instance always to the top of the list.
         assert currentItemPos != -1;
         if (currentItemPos != 0 && result.size() > 1) result.add(0, result.remove(currentItemPos));
         return result;
     }
 
+    private boolean isOlderThanSixMonths(long timestampMillis) {
+        return (TimeUtils.currentTimeMillis() - timestampMillis) > SIX_MONTHS_MS;
+    }
+
     @Override
     public int getCurrentInstanceId() {
         List<InstanceInfo> allInstances = getInstanceInfo();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
index dc07fcba..feaa381 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -33,6 +33,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.ResettersForTesting;
+import org.chromium.base.TimeUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
@@ -685,12 +686,13 @@
 
     /**
      * Write the time this instance is accessed.
+     *
      * @param index Instance ID
      */
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     public static void writeLastAccessedTime(int index) {
         ChromeSharedPreferences.getInstance()
-                .writeLong(lastAccessedTimeKey(index), System.currentTimeMillis());
+                .writeLong(lastAccessedTimeKey(index), TimeUtils.currentTimeMillis());
     }
 
     @VisibleForTesting
@@ -732,7 +734,7 @@
                     long startTime = prefs.readLong(ChromePreferenceKeys.MULTI_WINDOW_START_TIME);
                     if (startTime == 0) {
                         RecordUserAction.record("Android.MultiWindowMode.Enter2");
-                        long current = System.currentTimeMillis();
+                        long current = TimeUtils.currentTimeMillis();
                         prefs.writeLong(ChromePreferenceKeys.MULTI_WINDOW_START_TIME, current);
                     }
                 } else {
@@ -743,7 +745,7 @@
                     SharedPreferencesManager prefs = ChromeSharedPreferences.getInstance();
                     long startTime = prefs.readLong(ChromePreferenceKeys.MULTI_WINDOW_START_TIME);
                     if (startTime > 0) {
-                        long current = System.currentTimeMillis();
+                        long current = TimeUtils.currentTimeMillis();
                         RecordUserAction.record("Android.MultiWindowMode.Exit2");
                         RecordHistogram.recordLongTimesHistogram(
                                 "Android.MultiWindowMode.TotalDuration", current - startTime);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 03e79cb..0d1d3997 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -657,6 +657,7 @@
                 mIsTablet,
                 mTabStripHeightSupplier);
 
+        mNewTabPageLayout.updateSearchBoxHintText();
         initializeHomeModules();
 
         TraceEvent.end(TAG);
@@ -846,6 +847,7 @@
 
     private void onSearchEngineUpdated() {
         updateSearchProviderHasLogo();
+        mNewTabPageLayout.updateSearchBoxHintText();
         setSearchProviderInfoOnView(
                 mSearchProviderHasLogo, mTemplateUrlService.isDefaultSearchEngineGoogle());
         // TODO(crbug.com/40226731): Remove this call when the Feed position experiment is
@@ -854,8 +856,8 @@
     }
 
     /**
-     * Set the search provider info on the main child view, so that it can change layouts if
-     * needed.
+     * Set the search provider info on the main child view, so that it can change layouts if needed.
+     *
      * @param hasLogo Whether the search provider has a logo.
      * @param isGoogle Whether the search provider is Google.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 184a73948..5672643 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -17,6 +17,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -40,6 +41,7 @@
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
 import org.chromium.chrome.browser.ntp.search.SearchBoxCoordinator;
+import org.chromium.chrome.browser.omnibox.SearchEngineUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.suggestions.tile.MostVisitedTilesCoordinator;
 import org.chromium.chrome.browser.suggestions.tile.TileGroup;
@@ -134,6 +136,7 @@
     // This variable is only valid when the NTP surface is in tablet mode.
     private boolean mIsInMultiWindowModeOnTablet;
     private View mFakeSearchBoxLayout;
+    private TextView mFakeSearchBoxEditText;
     private Callback<Logo> mOnLogoAvailableCallback;
 
     /** Constructor for inflating from XML. */
@@ -165,6 +168,7 @@
 
         mMiddleSpacer = findViewById(R.id.ntp_middle_spacer);
         mFakeSearchBoxLayout = findViewById(R.id.search_box);
+        mFakeSearchBoxEditText = findViewById(R.id.search_box_text);
         insertSiteSectionView();
 
         Log.i(TAG, "NewTabPageLayout.onFinishInflate after insertSiteSectionView");
@@ -1008,4 +1012,10 @@
         return isTablet
                 && uiConfig.getCurrentDisplayStyle().horizontal < HorizontalDisplayStyle.WIDE;
     }
+
+    /** Update text hint to capture the Search Engine name. */
+    /* package */ void updateSearchBoxHintText() {
+        mFakeSearchBoxEditText.setHint(
+                SearchEngineUtils.getForProfile(mProfile).getSearchBoxHintText());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
index 3bc0aa6..b26bb9c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
@@ -133,11 +133,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public boolean handleBackPress() {
         mBackPressCallback.run();
         return true; // Prevent further handling of the back press.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index c507706..33ab778 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -650,7 +650,9 @@
                 isIncognito
                         ? R.string.hub_search_empty_hint_incognito
                         : R.string.hub_search_empty_hint;
-        mLocationBarCoordinator.getUrlBarCoordinator().setUrlBarHintText(hintTextRes);
+        mLocationBarCoordinator
+                .getUrlBarCoordinator()
+                .setUrlBarHintText(getResources().getString(hintTextRes));
     }
 
     /* package */ boolean loadUrl(@NonNull OmniboxLoadUrlParams params, boolean isIncognito) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index c233e6c..9d94b59 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -133,7 +133,7 @@
 public class NewTabPageTest {
     private static final int ARTICLE_SECTION_HEADER_POSITION = 1;
 
-    private static final int RENDER_TEST_REVISION = 6;
+    private static final int RENDER_TEST_REVISION = 7;
 
     private static final String HISTOGRAM_NTP_MODULE_CLICK = "NewTabPage.Module.Click";
     private static final String HISTOGRAM_NTP_MODULE_LONGCLICK = "NewTabPage.Module.LongClick";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 1f4c1505..4710651 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -114,7 +114,7 @@
                 mActivityTestRule
                         .getActivity()
                         .getResources()
-                        .getString(R.string.omnibox_empty_hint),
+                        .getString(R.string.omnibox_empty_hint_with_dse_name, "Google"),
                 urlBar.getHint().toString());
 
         // Type something in the omnibox.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawableRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawableRenderTest.java
index f0af1bef..1c315bbb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawableRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawableRenderTest.java
@@ -46,7 +46,7 @@
     public final ChromeRenderTestRule mRenderTestRule =
             ChromeRenderTestRule.Builder.withPublicCorpus()
                     .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE_TAB_GROUPS)
-                    .setRevision(2)
+                    .setRevision(3)
                     .build();
 
     @ClassRule
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
index c816289f..49c51d4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
@@ -52,6 +52,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.FakeTimeTestRule;
 import org.chromium.base.Token;
 import org.chromium.base.lifetime.Destroyable;
 import org.chromium.base.supplier.ObservableSupplier;
@@ -141,6 +142,7 @@
     private static final GURL URL3 = JUnitTestGURLs.URL_3;
 
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule public FakeTimeTestRule mFakeTimeTestRule = new FakeTimeTestRule();
 
     @Mock MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher;
     @Mock ObservableSupplier<TabModelOrchestrator> mTabModelOrchestratorSupplier;
@@ -196,6 +198,17 @@
     private final OneshotSupplierImpl<ProfileProvider> mProfileProviderSupplier =
             new OneshotSupplierImpl<>();
 
+    private MultiInstanceManagerApi31 createMultiInstanceManager(Activity activity) {
+        return new TestMultiInstanceManagerApi31(
+                activity,
+                mTabModelOrchestratorSupplier,
+                mMultiWindowModeStateDispatcher,
+                mActivityLifecycleDispatcher,
+                mModalDialogManagerSupplier,
+                mMenuOrKeyboardActionController,
+                mDesktopWindowStateManagerSupplier);
+    }
+
     private static class TestMultiInstanceManagerApi31 extends MultiInstanceManagerApi31 {
         // Running tasks containing Chrome activity ~ ActivityManager.getAppTasks()
         private final Set<Integer> mAppTaskIds = new HashSet<>();
@@ -620,7 +633,7 @@
         MultiInstanceManagerApi31.writeLastAccessedTime(1);
         // These two writes can often use the same timestamp, and cause the result to be random.
         // Wait for the next millisecond to guarantee this doesn't happen.
-        Thread.sleep(1);
+        mFakeTimeTestRule.advanceMillis(1);
         MultiInstanceManagerApi31.writeLastAccessedTime(2); // Accessed most recently.
 
         assertEquals(2, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask59));
@@ -631,6 +644,29 @@
     }
 
     @Test
+    @EnableFeatures(ChromeFeatureList.DISABLE_INSTANCE_LIMIT)
+    public void testGetInstanceInfo_closesInstancesOlderThanSixMonths() {
+        MultiWindowTestUtils.enableMultiInstance();
+        // Setting up two additional Multi-instance managers; mMultiInstanceManager already exists.
+        MultiInstanceManagerApi31 multiInstanceManager1 =
+                createMultiInstanceManager(mActivityTask57);
+        MultiInstanceManagerApi31 multiInstanceManager2 =
+                createMultiInstanceManager(mActivityTask58);
+
+        // Current activity is mActivityTask56, managed by mMultiInstanceManager.
+        assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask56));
+        assertEquals(1, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask57));
+        assertEquals(2, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask58));
+        assertEquals(3, mMultiInstanceManager.getInstanceInfo().size());
+
+        // Advancing time by well over six months.
+        mFakeTimeTestRule.advanceMillis(MultiInstanceManagerApi31.SIX_MONTHS_MS + 5000000);
+        // Closing the two other instances that are not managing the current activity.
+        assertEquals(1, mMultiInstanceManager.getInstanceInfo().size());
+        verify(mMultiInstanceManager, times(2)).closeInstance(anyInt(), anyInt());
+    }
+
+    @Test
     public void testGetInstanceInfo_size() {
         assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask56));
         assertEquals(1, allocInstanceIndex(PASSED_ID_INVALID, mActivityTask57));
@@ -1447,6 +1483,8 @@
         // Simulate creation of activity |mTabbedActivityTask62| with index 0 and
         // |mTabbedActivityTask63| with index 1.
         assertEquals(0, allocInstanceIndex(PASSED_ID_INVALID, mTabbedActivityTask62));
+        // Advancing time by at least 1ms apart to record different instance access times.
+        mFakeTimeTestRule.advanceMillis(1);
         assertEquals(1, allocInstanceIndex(PASSED_ID_INVALID, mTabbedActivityTask63));
 
         long accessTime0 = MultiInstanceManagerApi31.readLastAccessedTime(0);
@@ -1506,7 +1544,9 @@
         multiInstanceManager0.onTopResumedActivityChanged(false);
         multiInstanceManager1.onTopResumedActivityChanged(true);
         long instance1CreationTime = MultiInstanceManagerApi31.readLastAccessedTime(1);
-
+        // Advance time by 1ms to record a different access time for the instances when the top
+        // resumed activity changes.
+        mFakeTimeTestRule.advanceMillis(1);
         // Resume instance0, so it becomes the top resumed activity.
         multiInstanceManager0.onTopResumedActivityChanged(true);
         multiInstanceManager1.onTopResumedActivityChanged(false);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUnitTest.java
index 2611f74..5faa6fc 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/searchwidget/SearchActivityUnitTest.java
@@ -888,7 +888,9 @@
         ShadowProfileManager.setProfile(mProfile);
         mActivity.finishNativeInitialization();
 
-        verify(urlBarCoordinator).setUrlBarHintText(R.string.hub_search_empty_hint);
+        String expectedText = mActivity.getResources().getString(R.string.hub_search_empty_hint);
+
+        verify(urlBarCoordinator).setUrlBarHintText(expectedText);
     }
 
     @Test
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 74d7855..85cda57 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1214,8 +1214,6 @@
     "predictors/resource_prefetch_predictor_tables.h",
     "preloading/chrome_preloading.cc",
     "preloading/chrome_preloading.h",
-    "preloading/navigation_ablation_throttle.cc",
-    "preloading/navigation_ablation_throttle.h",
     "preloading/prefetch/chrome_prefetch_manager.cc",
     "preloading/prefetch/chrome_prefetch_manager.h",
     "preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.cc",
@@ -2975,8 +2973,6 @@
       "dom_distiller/tab_utils_android.cc",
       "download/android/dangerous_download_dialog_bridge.cc",
       "download/android/dangerous_download_dialog_bridge.h",
-      "download/android/dangerous_download_infobar_delegate.cc",
-      "download/android/dangerous_download_infobar_delegate.h",
       "download/android/download_callback_validator.cc",
       "download/android/download_callback_validator.h",
       "download/android/download_controller.cc",
diff --git a/chrome/browser/ai/ai_language_model.h b/chrome/browser/ai/ai_language_model.h
index a13334f..03a804ee 100644
--- a/chrome/browser/ai/ai_language_model.h
+++ b/chrome/browser/ai/ai_language_model.h
@@ -212,9 +212,6 @@
   // owned by `context_bound_object_set_`, and they will be destroyed together.
   base::raw_ref<AIContextBoundObjectSet> context_bound_object_set_;
 
-  // Holds state for any currently active prompt.
-  std::unique_ptr<PromptState> prompt_state_;
-
   // Holds the queue of operations to be run.
   base::queue<QueueCallback> queue_;
   // Whether a task is currently running.
@@ -223,6 +220,10 @@
   std::unique_ptr<optimization_guide::SafetyChecker> safety_checker_;
   base::WeakPtr<optimization_guide::ModelClient> model_client_;
 
+  // Holds state for any currently active prompt. This holds a reference to
+  // `safety_checker_` so must be ordered after that member.
+  std::unique_ptr<PromptState> prompt_state_;
+
   mojo::Receiver<blink::mojom::AILanguageModel> receiver_{this};
 
   base::WeakPtrFactory<AILanguageModel> weak_ptr_factory_{this};
diff --git a/chrome/browser/ai/ai_language_model_unittest.cc b/chrome/browser/ai/ai_language_model_unittest.cc
index f75d62b..2cfbc652 100644
--- a/chrome/browser/ai/ai_language_model_unittest.cc
+++ b/chrome/browser/ai/ai_language_model_unittest.cc
@@ -667,6 +667,20 @@
   run_loop.Run();
 }
 
+TEST_F(AILanguageModelTest, DestroyWithActivePrompt) {
+  fake_broker_.settings().set_execute_delay(base::Minutes(1));
+  auto session = CreateSession();
+  base::RunLoop run_loop;
+  session.set_disconnect_handler(run_loop.QuitClosure());
+
+  TestStreamingResponder responder;
+  session->Prompt(MakeInput("foo"), nullptr, responder.BindRemote());
+  session->Destroy();
+  run_loop.Run();
+
+  EXPECT_FALSE(responder.WaitForCompletion());
+}
+
 TEST_F(AILanguageModelTest, UnsupportedLanguage) {
   base::test::TestFuture<blink::mojom::AIManagerCreateClientError> future;
   AITestUtils::MockCreateLanguageModelClient language_model_client;
diff --git a/chrome/browser/android/tinker_tank/OWNERS b/chrome/browser/android/tinker_tank/OWNERS
index e2ef192a..3c120dc 100644
--- a/chrome/browser/android/tinker_tank/OWNERS
+++ b/chrome/browser/android/tinker_tank/OWNERS
@@ -1,3 +1,2 @@
-eirage@chromium.org
 hartmanng@chromium.org
 yfriedman@chromium.org
diff --git a/chrome/browser/ash/crosapi/multi_capture_service_ash.cc b/chrome/browser/ash/crosapi/multi_capture_service_ash.cc
index e4b959d3..5d7dc02 100644
--- a/chrome/browser/ash/crosapi/multi_capture_service_ash.cc
+++ b/chrome/browser/ash/crosapi/multi_capture_service_ash.cc
@@ -47,7 +47,6 @@
 void MultiCaptureServiceAsh::IsMultiCaptureAllowed(
     const GURL& url,
     IsMultiCaptureAllowedCallback callback) {
-  // This function is only called from the primary user on the Lacros side.
   content::BrowserContext* context =
       ash::BrowserContextHelper::Get()->GetBrowserContextByUser(
           user_manager::UserManager::Get()->GetPrimaryUser());
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
index 4629b83..88d50c1 100644
--- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
+++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file has been duplicated for lacros in
-// //chrome/browser/lacros/guest_os/vm_sk_forwarding_native_message_host.cc and
-// should eventually be removed.
-
 #include "chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h"
 
 #include <utility>
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h
index 2869ee1..bb946c1 100644
--- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h
+++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h
@@ -5,10 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_GUEST_OS_VM_SK_FORWARDING_NATIVE_MESSAGE_HOST_H_
 #define CHROME_BROWSER_ASH_GUEST_OS_VM_SK_FORWARDING_NATIVE_MESSAGE_HOST_H_
 
-// This file has been duplicated for lacros in
-// //chrome/browser/lacros/guest_os/vm_sk_forwarding_native_message_host.h and
-// should eventually be removed.
-
 #include <memory>
 #include <string>
 
diff --git a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host_unittest.cc b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host_unittest.cc
index a65a03cb..20bab1b1 100644
--- a/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host_unittest.cc
+++ b/chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host_unittest.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file has been duplicated for lacros in
-// //chrome/browser/lacros/guest_os/vm_sk_forwarding_native_message_host_unittest.cc
-// and should eventually be removed.
-
 #include "chrome/browser/ash/guest_os/vm_sk_forwarding_native_message_host.h"
 
 #include "base/check.h"
diff --git a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
index 8076762..c602c9763 100644
--- a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
@@ -1580,7 +1580,7 @@
   scoped_refptr<extensions::CrxInstaller> installer =
       extensions::CrxInstaller::CreateSilent(profile);
   installer->set_allow_silent_install(true);
-  installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
+  installer->set_was_triggered_by_user_download();
   installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE);
 
   {
diff --git a/chrome/browser/ash/release_notes/release_notes_notification.cc b/chrome/browser/ash/release_notes/release_notes_notification.cc
index 8aec5ef..f48b09f 100644
--- a/chrome/browser/ash/release_notes/release_notes_notification.cc
+++ b/chrome/browser/ash/release_notes/release_notes_notification.cc
@@ -40,7 +40,8 @@
 void ReleaseNotesNotification::MaybeShowReleaseNotes() {
   release_notes_storage_ = std::make_unique<ReleaseNotesStorage>(profile_);
   if (!release_notes_storage_->ShouldNotify() ||
-      features::IsForestFeatureEnabled()) {
+      !base::FeatureList::IsEnabled(
+          features::kReleaseNotesNotificationAlwaysEligible)) {
     return;
   }
   ShowReleaseNotesNotification();
diff --git a/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc b/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
index 8efc15a..d091be4 100644
--- a/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
+++ b/chrome/browser/ash/release_notes/release_notes_notification_unittest.cc
@@ -25,14 +25,12 @@
 
 class ReleaseNotesNotificationTest
     : public BrowserWithTestWindowTest,
-      public ::testing::WithParamInterface</*forest_feature=*/bool> {
+      public ::testing::WithParamInterface</*notification_eligible=*/bool> {
  public:
-  ReleaseNotesNotificationTest() : forest_feature_enabled_(GetParam()) {}
-
+  ReleaseNotesNotificationTest() : notification_eligible_(GetParam()) {}
   ReleaseNotesNotificationTest(const ReleaseNotesNotificationTest&) = delete;
   ReleaseNotesNotificationTest& operator=(const ReleaseNotesNotificationTest&) =
       delete;
-
   ~ReleaseNotesNotificationTest() override = default;
 
   // BrowserWithTestWindowTest:
@@ -46,15 +44,17 @@
                             base::Unretained(this)));
     release_notes_notification_ =
         std::make_unique<ReleaseNotesNotification>(profile());
-    if (forest_feature_enabled()) {
+    if (notification_eligible()) {
       scoped_feature_list_.InitWithFeatures(
           /*enabled_features=*/{features::kReleaseNotesNotificationAllChannels,
-                                features::kForestFeature},
+                                features::
+                                    kReleaseNotesNotificationAlwaysEligible},
           /*disabled_features=*/{});
     } else {
       scoped_feature_list_.InitWithFeatures(
           /*enabled_features=*/{features::kReleaseNotesNotificationAllChannels},
-          /*disabled_features=*/{features::kForestFeature});
+          /*disabled_features=*/{
+              features::kReleaseNotesNotificationAlwaysEligible});
     }
   }
 
@@ -72,7 +72,7 @@
 
   void OnNotificationAdded() { notification_count_++; }
 
-  bool forest_feature_enabled() const { return forest_feature_enabled_; }
+  bool notification_eligible() const { return notification_eligible_; }
 
  protected:
   bool HasReleaseNotesNotification() {
@@ -90,14 +90,18 @@
  private:
   std::unique_ptr<NotificationDisplayServiceTester> tester_;
   base::test::ScopedFeatureList scoped_feature_list_;
-  const bool forest_feature_enabled_;
+  const bool notification_eligible_;
 };
 
 INSTANTIATE_TEST_SUITE_P(All,
                          ReleaseNotesNotificationTest,
-                         /*forest_feature=*/testing::Bool());
+                         /*notification_eligible=*/testing::Bool());
 
 TEST_P(ReleaseNotesNotificationTest, DoNotShowReleaseNotesNotification) {
+  if (notification_eligible()) {
+    GTEST_SKIP() << "Notification is always shown with the notification "
+                    "eligible feature turned on.";
+  }
   auto release_notes_storage = std::make_unique<ReleaseNotesStorage>(profile());
 
   // Set the pref to the last shown milestone to ensure release notes do not
@@ -120,11 +124,11 @@
 
   release_notes_notification_->MaybeShowReleaseNotes();
 
-  // If forest feature is enabled, then release notes should not show.
-  EXPECT_EQ(forest_feature_enabled(), !HasReleaseNotesNotification());
-  EXPECT_EQ(forest_feature_enabled() ? 0 : 1, notification_count_);
-  EXPECT_EQ(forest_feature_enabled(),
-            !release_notes_storage->ShouldShowSuggestionChip());
+  // If notification eligible is enabled, then release notes should show.
+  EXPECT_EQ(notification_eligible(), HasReleaseNotesNotification());
+  EXPECT_EQ(notification_eligible() ? 1 : 0, notification_count_);
+  EXPECT_EQ(notification_eligible(),
+            release_notes_storage->ShouldShowSuggestionChip());
   if (HasReleaseNotesNotification()) {
     EXPECT_TRUE(HasReleaseNotesNotification());
     EXPECT_EQ(ui::SubstituteChromeOSDeviceType(
diff --git a/chrome/browser/ash/release_notes/release_notes_storage.h b/chrome/browser/ash/release_notes/release_notes_storage.h
index f4bb9ae..d69a188 100644
--- a/chrome/browser/ash/release_notes/release_notes_storage.h
+++ b/chrome/browser/ash/release_notes/release_notes_storage.h
@@ -16,7 +16,7 @@
 // This stores the latest milestone with new Release Notes content. If the last
 // milestone the user has seen the notification is before this, a new
 // notification will be shown.
-inline constexpr int kLastChromeVersionWithReleaseNotes = 130;
+inline constexpr int kLastChromeVersionWithReleaseNotes = 138;
 
 // Class used to determine when/if to show user notification that release notes
 // are available for their recently updated device.
diff --git a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc
index f6f00d6..0af8fc5 100644
--- a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc
+++ b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller.cc
@@ -60,12 +60,11 @@
 HelpAppNotificationController::~HelpAppNotificationController() = default;
 
 void HelpAppNotificationController::MaybeShowReleaseNotesNotification() {
-  if (IsNotificationShownForCurrentMilestone(profile_) &&
-      !base::FeatureList::IsEnabled(
-          features::kReleaseNotesNotificationAlwaysEligible)) {
+  if (IsNotificationShownForCurrentMilestone(profile_)) {
     return;
   }
-  if (features::IsForestFeatureEnabled()) {
+  if (!base::FeatureList::IsEnabled(
+          features::kReleaseNotesNotificationAlwaysEligible)) {
     return;
   }
   ReleaseNotesStorage release_notes_storage(profile_);
diff --git a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller_unittest.cc b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller_unittest.cc
index 5191d6c5..53e122b 100644
--- a/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller_unittest.cc
+++ b/chrome/browser/ash/system_web_apps/apps/help_app/help_app_notification_controller_unittest.cc
@@ -71,11 +71,15 @@
     notification_tester_->SetNotificationAddedClosure(base::BindRepeating(
         &HelpAppNotificationControllerTest::OnNotificationAdded,
         base::Unretained(this)));
+
+    // The notification is turned off by default since there is a chip shown in
+    // the birch bar. Turn it on for this test.
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/
         {features::kReleaseNotesNotificationAllChannels,
-         features::kHelpAppOpensInsteadOfReleaseNotesNotification},
-        /*disabled_features=*/{features::kForestFeature});
+         features::kHelpAppOpensInsteadOfReleaseNotesNotification,
+         features::kReleaseNotesNotificationAlwaysEligible},
+        /*disabled_features=*/{});
   }
 
   void TearDown() override {
@@ -86,14 +90,14 @@
 
   void OnNotificationAdded() { notification_count_++; }
 
-  void TurnOnBirchFeature() {
+  void TurnOffNotificationEligible() {
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitWithFeatures(
         /*enabled_features=*/
         {features::kReleaseNotesNotificationAllChannels,
-         features::kHelpAppOpensInsteadOfReleaseNotesNotification,
-         features::kForestFeature},
-        /*disabled_features=*/{});
+         features::kHelpAppOpensInsteadOfReleaseNotesNotification},
+        /*disabled_features=*/{
+            features::kReleaseNotesNotificationAlwaysEligible});
   }
 
  protected:
@@ -125,7 +129,7 @@
             features::kReleaseNotesNotificationAllChannels,
         },
         /*disabled_features=*/{
-            features::kForestFeature,
+            features::kReleaseNotesNotificationAlwaysEligible,
             features::kHelpAppOpensInsteadOfReleaseNotesNotification});
     BrowserWithTestWindowTest::SetUp();
     help_app_notification_controller_ =
@@ -144,36 +148,23 @@
 TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
        DoesNotShowAnyNotificationIfNewRegularProfile) {
   Profile* profile = CreateRegularProfile();
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
-
   EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasReleaseNotesNotification());
+  EXPECT_FALSE(HasReleaseNotesNotification());
 }
 
 TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
-       ShowsReleaseNotesNotificationIfShownInOlderMilestone) {
+       DoesNotShowsReleaseNotesNotificationIfShownInOlderMilestone) {
   Profile* profile = CreateRegularProfile();
   profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
                                   20);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
-  if (features::IsForestFeatureEnabled()) {
-    EXPECT_EQ(0, notification_count_);
-    EXPECT_EQ(false, HasReleaseNotesNotification());
-    EXPECT_EQ(20, profile->GetPrefs()->GetInteger(
-                      prefs::kHelpAppNotificationLastShownMilestone));
-  } else {
-    EXPECT_EQ(1, notification_count_);
-    EXPECT_EQ(true, HasReleaseNotesNotification());
-    EXPECT_EQ(CurrentMilestone(),
-              profile->GetPrefs()->GetInteger(
-                  prefs::kHelpAppNotificationLastShownMilestone));
-  }
+  EXPECT_EQ(0, notification_count_);
+  EXPECT_FALSE(HasReleaseNotesNotification());
 }
 
 TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
@@ -181,77 +172,22 @@
   Profile* profile = CreateRegularProfile();
   profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
                                   CurrentMilestone());
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
-
   EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasReleaseNotesNotification());
+  EXPECT_FALSE(HasReleaseNotesNotification());
 }
 
 // Tests for Child profile.
 TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
        DoesNotShowAnyNotificationIfNewChildProfile) {
   Profile* profile = CreateChildProfile();
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
-
   EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasReleaseNotesNotification());
-}
-
-TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
-       DoesNotShowMoreThanOneNotificationPerMilestone) {
-  Profile* profile = CreateChildProfile();
-  profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
-                                  91);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
-
-  controller->MaybeShowReleaseNotesNotification();
-
-  if (features::IsForestFeatureEnabled()) {
-    EXPECT_EQ(0, notification_count_);
-    EXPECT_EQ(false, HasReleaseNotesNotification());
-  } else {
-    EXPECT_EQ(1, notification_count_);
-    EXPECT_EQ(true, HasReleaseNotesNotification());
-  }
-
-  controller->MaybeShowReleaseNotesNotification();
-
-  if (features::IsForestFeatureEnabled()) {
-    EXPECT_EQ(0, notification_count_);
-    EXPECT_EQ(false, HasReleaseNotesNotification());
-  } else {
-    EXPECT_EQ(1, notification_count_);
-    EXPECT_EQ(true, HasReleaseNotesNotification());
-  }
-}
-
-// Tests for suggestion chips.
-TEST_F(HelpAppNotificationControllerTestWithHelpAppOpensInsteadDisabled,
-       UpdatesReleaseNotesChipPrefWhenReleaseNotesNotificationShown) {
-  Profile* profile = CreateRegularProfile();
-  profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
-                                  20);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
-
-  EXPECT_EQ(0, profile->GetPrefs()->GetInteger(
-                   prefs::kReleaseNotesSuggestionChipTimesLeftToShow));
-
-  controller->MaybeShowReleaseNotesNotification();
-  if (features::IsForestFeatureEnabled()) {
-    EXPECT_EQ(0, profile->GetPrefs()->GetInteger(
-                     prefs::kReleaseNotesSuggestionChipTimesLeftToShow));
-  } else {
-    EXPECT_EQ(3, profile->GetPrefs()->GetInteger(
-                     prefs::kReleaseNotesSuggestionChipTimesLeftToShow));
-  }
+  EXPECT_FALSE(HasReleaseNotesNotification());
 }
 
 // Tests that help app opens instead of release notes notification by default.
@@ -259,32 +195,30 @@
   Profile* profile = CreateRegularProfile();
   profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
                                   91);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
 
   EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasReleaseNotesNotification());
+  EXPECT_FALSE(HasReleaseNotesNotification());
   EXPECT_EQ(CurrentMilestone(),
             profile->GetPrefs()->GetInteger(
                 prefs::kHelpAppNotificationLastShownMilestone));
 }
 
-// Tests that release notes don't auto open if the birch feature is enabled.
+// Tests that release notes don't auto open if the notification eligible feature
+// is disabled.
 TEST_F(HelpAppNotificationControllerTest,
        DoesNotOpenHelpAppIfBirchFeatureEnabled) {
-  TurnOnBirchFeature();
+  TurnOffNotificationEligible();
   Profile* profile = CreateRegularProfile();
   profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
                                   91);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile);
+  auto controller = std::make_unique<HelpAppNotificationController>(profile);
 
   controller->MaybeShowReleaseNotesNotification();
-
   EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasReleaseNotesNotification());
+  EXPECT_FALSE(HasReleaseNotesNotification());
   EXPECT_EQ(91, profile->GetPrefs()->GetInteger(
                     prefs::kHelpAppNotificationLastShownMilestone));
 }
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index af635d90..0e7b96c5 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "components/omnibox/browser/search_provider.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <array>
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/base64.h"
 #include "base/command_line.h"
@@ -208,7 +204,7 @@
     ResultInfo(GURL gurl,
                AutocompleteMatch::Type result_type,
                bool allowed_to_be_default_match,
-               std::u16string fill_into_edit)
+               std::u16string_view fill_into_edit)
         : gurl(gurl),
           result_type(result_type),
           allowed_to_be_default_match(allowed_to_be_default_match),
@@ -217,17 +213,17 @@
     const GURL gurl;
     const AutocompleteMatch::Type result_type;
     const bool allowed_to_be_default_match;
-    const std::u16string fill_into_edit;
+    const std::u16string_view fill_into_edit;
   };
 
   struct TestData {
-    const std::u16string input;
+    const std::u16string_view input;
     const size_t num_results;
     const std::array<ResultInfo, 3> output;
   };
 
   struct ExpectedMatch {
-    std::string contents;
+    std::string_view contents;
     bool allowed_to_be_default_match;
   };
 
@@ -271,12 +267,12 @@
 
   void TearDown() override;
 
-  void RunTest(TestData* cases, int num_cases, bool prefer_keyword);
+  void RunTest(base::span<const TestData> cases, bool prefer_keyword);
 
  protected:
   // Default values used for testing.
-  static const char kNotApplicable[];
-  static const ExpectedMatch kEmptyExpectedMatch;
+  static constexpr char kNotApplicable[] = "Not Applicable";
+  static constexpr ExpectedMatch kEmptyExpectedMatch = {kNotApplicable, false};
 
   // Adds a search for |term|, using the engine |t_url| to the history, and
   // returns the URL for that search.
@@ -327,20 +323,19 @@
   void QueryForInputAndWaitForFetcherResponses(
       const std::u16string& text,
       const bool prefer_keyword,
-      const std::string& default_fetcher_response,
-      const std::string& keyword_fetcher_response);
+      std::string_view default_fetcher_response,
+      std::string_view keyword_fetcher_response);
 
   // Notifies the URLFetcher for the suggest query corresponding to the default
   // search provider that it's done.
   // Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
   void FinishDefaultSuggestQuery(const std::u16string& query_text);
 
-  // Verifies that |matches| and |expected_matches| agree on the first
-  // |num_expected_matches|, displaying an error message that includes
-  // |description| for any disagreement.
+  // Verifies that `matches` and `expected_matches` agree on the first
+  // `matches.size()`, displaying an error message that includes
+  // `description` for any disagreement.
   void CheckMatches(const std::string& description,
-                    const size_t num_expected_matches,
-                    const ExpectedMatch expected_matches[],
+                    base::span<const ExpectedMatch> expected_matches,
                     const ACMatches& matches);
 
   void ClearAllResults();
@@ -360,21 +355,16 @@
   // See description above class for details of these fields.
   // TemplateURLs can not outlive `profile_`.
   raw_ptr<TemplateURL> default_t_url_ = nullptr;
-  const std::u16string term1_ = u"term1";
+  static constexpr std::u16string_view term1_ = u"term1";
   GURL term1_url_;
   raw_ptr<TemplateURL> keyword_t_url_ = nullptr;
-  const std::u16string keyword_term_ = u"keyword";
+  static constexpr std::u16string_view keyword_term_ = u"keyword";
   GURL keyword_url_;
 
   // If not nullptr, OnProviderUpdate quits the current |run_loop_|.
   raw_ptr<base::RunLoop> run_loop_ = nullptr;
 };
 
-// static
-const char BaseSearchProviderTest::kNotApplicable[] = "Not Applicable";
-const BaseSearchProviderTest::ExpectedMatch
-    BaseSearchProviderTest::kEmptyExpectedMatch = {kNotApplicable, false};
-
 void BaseSearchProviderTest::CustomizableSetUp(
     const std::string& search_url,
     const std::string& suggestions_url) {
@@ -394,7 +384,7 @@
   ASSERT_NE(0, default_provider_id);
 
   // Add url1, with search term term1_.
-  term1_url_ = AddSearchToHistory(default_t_url_, term1_, 1);
+  term1_url_ = AddSearchToHistory(default_t_url_, std::u16string(term1_), 1);
 
   // Create another TemplateURL.
   data.SetShortName(u"k");
@@ -405,7 +395,8 @@
   ASSERT_NE(0, keyword_t_url_->id());
 
   // Add a page and search term for keyword_t_url_.
-  keyword_url_ = AddSearchToHistory(keyword_t_url_, keyword_term_, 1);
+  keyword_url_ =
+      AddSearchToHistory(keyword_t_url_, std::u16string(keyword_term_), 1);
 
   // Keywords are updated by the InMemoryHistoryBackend only after the message
   // has been processed on the history thread. Block until history processes all
@@ -425,26 +416,27 @@
   provider_ = nullptr;
 }
 
-void BaseSearchProviderTest::RunTest(TestData* cases,
-                                     int num_cases,
+void BaseSearchProviderTest::RunTest(base::span<const TestData> cases,
                                      bool prefer_keyword) {
   ACMatches matches;
-  for (int i = 0; i < num_cases; ++i) {
-    AutocompleteInput input(cases[i].input, metrics::OmniboxEventProto::OTHER,
+  for (const auto& test_case : cases) {
+    AutocompleteInput input(std::u16string(test_case.input),
+                            metrics::OmniboxEventProto::OTHER,
                             ChromeAutocompleteSchemeClassifier(profile_.get()));
     input.set_prefer_keyword(prefer_keyword);
     provider_->Start(input, false);
     matches = provider_->matches();
-    SCOPED_TRACE(
-        base::StrCat({u"Input was: ", cases[i].input, u"; prefer_keyword was: ",
-                      base::ASCIIToUTF16(base::ToString(prefer_keyword))}));
-    EXPECT_EQ(cases[i].num_results, matches.size());
-    if (matches.size() == cases[i].num_results) {
-      for (size_t j = 0; j < cases[i].num_results; ++j) {
-        EXPECT_EQ(cases[i].output[j].gurl, matches[j].destination_url);
-        EXPECT_EQ(cases[i].output[j].result_type, matches[j].type);
-        EXPECT_EQ(cases[i].output[j].fill_into_edit, matches[j].fill_into_edit);
-        EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
+    SCOPED_TRACE(base::StrCat(
+        {u"Input was: ", test_case.input, u"; prefer_keyword was: ",
+         base::ASCIIToUTF16(base::ToString(prefer_keyword))}));
+    EXPECT_EQ(test_case.num_results, matches.size());
+    if (matches.size() == test_case.num_results) {
+      for (size_t j = 0; j < test_case.num_results; ++j) {
+        EXPECT_EQ(test_case.output[j].gurl, matches[j].destination_url);
+        EXPECT_EQ(test_case.output[j].result_type, matches[j].type);
+        EXPECT_EQ(test_case.output[j].fill_into_edit,
+                  matches[j].fill_into_edit);
+        EXPECT_EQ(test_case.output[j].allowed_to_be_default_match,
                   matches[j].allowed_to_be_default_match);
       }
     }
@@ -509,13 +501,13 @@
 void BaseSearchProviderTest::QueryForInputAndWaitForFetcherResponses(
     const std::u16string& text,
     const bool prefer_keyword,
-    const std::string& default_fetcher_response,
-    const std::string& keyword_fetcher_response) {
+    std::string_view default_fetcher_response,
+    std::string_view keyword_fetcher_response) {
   test_url_loader_factory_.ClearResponses();
   QueryForInput(text, false, prefer_keyword);
 
   std::string text8;
-  ASSERT_TRUE(base::UTF16ToUTF8(text.data(), text.length(), &text8));
+  ASSERT_TRUE(base::UTF16ToUTF8(text.data(), text.size(), &text8));
 
   if (!default_fetcher_response.empty()) {
     test_url_loader_factory_.AddResponse(
@@ -584,8 +576,7 @@
 void BaseSearchProviderTest::FinishDefaultSuggestQuery(
     const std::u16string& query_text) {
   std::string text8;
-  ASSERT_TRUE(
-      base::UTF16ToUTF8(query_text.data(), query_text.length(), &text8));
+  ASSERT_TRUE(base::UTF16ToUTF8(query_text.data(), query_text.size(), &text8));
   std::string url =
       base::StrCat({"https://defaultturl2/", base::EscapePath(text8)});
 
@@ -597,11 +588,10 @@
 
 void BaseSearchProviderTest::CheckMatches(
     const std::string& description,
-    const size_t num_expected_matches,
-    const ExpectedMatch expected_matches[],
+    base::span<const ExpectedMatch> expected_matches,
     const ACMatches& matches) {
   ASSERT_FALSE(matches.empty());
-  ASSERT_LE(matches.size(), num_expected_matches);
+  ASSERT_LE(matches.size(), expected_matches.size());
   size_t i = 0;
   SCOPED_TRACE(description);
   // Ensure that the returned matches equal the expectations.
@@ -612,7 +602,7 @@
               matches[i].allowed_to_be_default_match);
   }
   // Ensure that no expected matches are missing.
-  for (; i < num_expected_matches; ++i) {
+  for (; i < expected_matches.size(); ++i) {
     SCOPED_TRACE(base::StrCat({" Case # ", base::NumberToString(i)}));
     EXPECT_EQ(kNotApplicable, expected_matches[i].contents);
   }
@@ -643,7 +633,7 @@
 // Make sure we query history for the default provider and a URLFetcher is
 // created for the default provider suggest results.
 TEST_F(SearchProviderTest, QueryDefaultProvider) {
-  std::u16string term = term1_.substr(0, term1_.length() - 1);
+  const std::u16string term(term1_.substr(0, term1_.size() - 1));
   QueryForInput(term, false, false);
 
   // Make sure the default providers suggest service was queried.
@@ -687,7 +677,7 @@
 // Make sure we do NOT query history for the default provider. However a
 // URLFetcher is created for the default provider suggest results.
 TEST_F(SearchProviderTest, QueryDefaultProvider_LensSearchbox) {
-  std::u16string term = term1_.substr(0, term1_.length() - 1);
+  const std::u16string term(term1_.substr(0, term1_.size() - 1));
   AutocompleteInput input(term,
                           metrics::OmniboxEventProto::LENS_SIDE_PANEL_SEARCHBOX,
                           ChromeAutocompleteSchemeClassifier(profile_.get()));
@@ -712,7 +702,7 @@
 
   // Make sure the SearchProvider does NOT have a history result for "term1".
   AutocompleteMatch term1_match;
-  EXPECT_FALSE(FindMatchWithContents(term1_, &term1_match));
+  EXPECT_FALSE(FindMatchWithContents(std::u16string(term1_), &term1_match));
 
   // Make sure the SearchProvider has a Suggest result for "term2".
   AutocompleteMatch term2_match;
@@ -764,7 +754,7 @@
 }
 
 TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
-  std::u16string term = term1_.substr(0, term1_.length() - 1);
+  const std::u16string term(term1_.substr(0, term1_.size() - 1));
   QueryForInput(term, true, false);
 
   ASSERT_FALSE(provider_->matches().empty());
@@ -776,7 +766,7 @@
 // Issues a query that matches the registered keyword and makes sure history
 // is queried as well as URLFetchers getting created.
 TEST_F(SearchProviderTest, QueryKeywordProvider) {
-  std::u16string term = keyword_term_.substr(0, keyword_term_.length() - 1);
+  const std::u16string term(keyword_term_.substr(0, keyword_term_.size() - 1));
   QueryForInput(base::StrCat({u"k ", term}), false, false);
 
   // Make sure the default providers suggest service was queried.
@@ -815,12 +805,11 @@
 }
 
 TEST_F(SearchProviderTest, SendDataToSuggestAtAppropriateTimes) {
-  constexpr bool fileNameTreatedAsQuery =
-      (BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID));
+  constexpr bool file_name_treated_as_query = BUILDFLAG(IS_ANDROID);
   struct {
-    std::string input;
+    std::string_view input;
     const bool expect_to_send_to_default_provider;
-  } cases[] = {
+  } static constexpr kCases[] = {
       // None of the following input strings should be sent to the default
       // suggest server because they may contain potentially private data.
       {"username:password", false},
@@ -829,7 +818,7 @@
       {"https://username:password", false},
       {"username:password@hostname", false},
       {"http://username:password@hostname/", false},
-      {"file://filename", fileNameTreatedAsQuery},
+      {"file://filename", file_name_treated_as_query},
       {"data://data", false},
       {"unknownscheme:anything", false},
       {"http://hostname/?query=q", false},
@@ -860,7 +849,7 @@
       {"foo https://hostname/path", true},
   };
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     SCOPED_TRACE(base::StrCat({"for input=", test_case.input}));
     QueryForInput(ASCIIToUTF16(test_case.input), false, false);
     // Make sure the default provider's suggest service was or was not queried
@@ -1144,7 +1133,7 @@
 }
 
 TEST_F(SearchProviderTest, KeywordVerbatim) {
-  TestData cases[] = {
+  const TestData kCases[] = {
       // Test a simple keyword input.
       {u"k foo",
        1,
@@ -1215,10 +1204,10 @@
   };
 
   // Test not in keyword mode.
-  RunTest(cases, std::size(cases), false);
+  RunTest(kCases, false);
 
   // Test in keyword mode.  (Both modes should give the same result.)
-  RunTest(cases, std::size(cases), true);
+  RunTest(kCases, true);
 }
 
 // Verifies Navsuggest results don't set a TemplateURL, which Instant relies on.
@@ -1265,10 +1254,10 @@
 // keyword provider returns suggested relevance scores.
 TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) {
   struct {
-    const std::string default_provider_json;
-    const std::string keyword_provider_json;
-    const std::array<std::string, 5> matches;
-  } cases[] = {
+    const std::string_view default_provider_json;
+    const std::string_view keyword_provider_json;
+    const std::array<std::string_view, 5> matches;
+  } static constexpr kCases[] = {
       // First, try an input where the keyword provider does not deliver
       // suggested relevance scores.
       {"[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
@@ -1289,7 +1278,7 @@
        "\"google:suggestrelevance\":[9600]}]",
        {"akeyword-query", "a", "", "", ""}}};
 
-  for (auto& test_case : cases) {
+  for (auto& test_case : kCases) {
     // Send the query twice in order to have a synchronous pass after the first
     // response is received.  This is necessary because SearchProvider doesn't
     // allow an asynchronous response to change the default match.
@@ -1330,10 +1319,10 @@
       },
       {omnibox::kDynamicMaxAutocomplete});
   struct {
-    const std::string json;
+    const std::string_view json;
     const ExpectedMatch matches[6];
-    const std::string inline_autocompletion;
-  } cases[] = {
+    const std::string_view inline_autocompletion;
+  } static constexpr kCases[] = {
       // Ensure that suggestrelevance scores reorder matches.
       {"[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
        {{"a", true},
@@ -1342,7 +1331,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
        "\"google:suggestrelevance\":[1, 2]}]",
@@ -1352,7 +1341,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
 
       // Without suggested relevance scores, we should only allow one
       // navsuggest result to be be displayed.
@@ -1364,7 +1353,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
 
       // Ensure that verbatimrelevance scores reorder or suppress verbatim.
       // Negative values will have no effect; the calculated value will be used.
@@ -1376,7 +1365,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
        "\"google:suggestrelevance\":[9999]}]",
        {{"a1", true},
@@ -1414,7 +1403,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:verbatimrelevance\":9998,"
@@ -1471,7 +1460,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
        "\"google:verbatimrelevance\":0}]",
        {{"a", true},
@@ -1480,7 +1469,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999]}]",
@@ -1490,7 +1479,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999],"
@@ -1501,7 +1490,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
 
       // Allow low-scoring matches.
       {"[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
@@ -1579,7 +1568,7 @@
         {"f", false},
         {"e", false},
         {"d", false}},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
        "\"http://e.com\", \"http://f.com\", \"http://g.com\","
        "\"http://h.com\"],[],[],"
@@ -1594,7 +1583,7 @@
         {"f.com", false},
         {"e.com", false},
         {"d.com", false}},
-       std::string()},
+       std::string_view()},
 
       // Ensure that incorrectly sized suggestion relevance lists are ignored.
       {"[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10]}]",
@@ -1604,7 +1593,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 10]}]",
        {{"a", true},
         {"a1", false},
@@ -1612,7 +1601,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
        "\"google:suggestrelevance\":[10]}]",
@@ -1622,7 +1611,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[\"http://a1.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999, 10]}]",
@@ -1632,7 +1621,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
 
       // Ensure that all 'verbatim' results are merged with their maximum score.
       {"[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
@@ -1664,7 +1653,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
       {"[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
        {{"a", true},
         kEmptyExpectedMatch,
@@ -1672,10 +1661,10 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
-       std::string()},
+       std::string_view()},
   };
 
-  for (auto& test_case : cases) {
+  for (auto& test_case : kCases) {
     // Send the query twice in order to have a synchronous pass after the first
     // response is received.  This is necessary because SearchProvider doesn't
     // allow an asynchronous response to change the default match.
@@ -1686,8 +1675,7 @@
 
     const std::string description =
         base::StrCat({"for input with json=", test_case.json});
-    CheckMatches(description, std::size(test_case.matches), test_case.matches,
-                 provider_->matches());
+    CheckMatches(description, test_case.matches, provider_->matches());
   }
 }
 
@@ -1710,25 +1698,27 @@
       {omnibox::kDynamicMaxAutocomplete});
 
   struct KeywordFetcherMatch {
-    std::string contents;
+    std::string_view contents;
     bool from_keyword;
     bool allowed_to_be_default_match;
   };
-  const KeywordFetcherMatch kEmptyMatch = {kNotApplicable, false, false};
+  static constexpr KeywordFetcherMatch kEmptyMatch = {kNotApplicable, false,
+                                                      false};
   struct Cases {
-    const std::string json;
-    const KeywordFetcherMatch matches[6];
-    const std::string inline_autocompletion;
+    const std::string_view json;
+    const std::array<KeywordFetcherMatch, 6> matches;
+    const std::string_view inline_autocompletion;
   };
-  auto cases = std::to_array<Cases>({
+  static constexpr auto kCases = std::to_array<Cases>({
       // clang-format off
     // Ensure that suggest relevance scores reorder matches.
     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "c",   true,  false },
         { "b",   true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // Again, check that relevance scores reorder matches, just this
     // time with navigation matches.  This also checks that with
     // suggested relevance scores we allow multiple navsuggest results.
@@ -1738,136 +1728,154 @@
     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
        "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "d",     true,  false },
         { "c.com", false, false },
         { "b.com", false, false },
-        kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // Without suggested relevance scores, we should only allow one
     // navsuggest result to be be displayed.
     { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "b.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
     // Negative values will have no effect; the calculated value will be used.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
                              "\"google:suggestrelevance\":[9998]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { { "a1",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
         { "a",   true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { { "a1",  true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
                              "\"google:suggestrelevance\":[9999]}]",
-      { { "a1",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
         { "a",   true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9999,"
         "\"google:suggestrelevance\":[9998]}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "a.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // Ensure that both types of relevance scores reorder matches together.
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
                                      "\"google:verbatimrelevance\":9998}]",
-      { { "a1",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
         { "a",   true,  true },
         { "a2",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
 
     // Check that an inlineable match appears first regardless of its score.
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "b",   true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999]}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "b.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // If there is no inlineable match, restore the keyword verbatim score.
     // The keyword verbatim match will then appear first.
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
                             "\"google:verbatimrelevance\":0}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "b",   true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999],"
         "\"google:verbatimrelevance\":0}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "b.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // The top result does not have to score as highly as calculated
     // verbatim.  i.e., there are no minimum score restrictions in
     // this provider.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
-      { { "a1",  true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":10}]",
-      { { "a1",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
         { "a",   true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[10],"
                              "\"google:verbatimrelevance\":0}]",
-      { { "a1",  true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::to_array<KeywordFetcherMatch>({
+        { "a1",  true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "1" },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 20],"
                                      "\"google:verbatimrelevance\":0}]",
-      { { "a2",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a2",  true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "2" },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[10, 30],"
       "\"google:verbatimrelevance\":20}]",
-      { { "a2",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a2",  true,  true },
         { "a",   true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "2" },
 
     // Ensure that all suggestions are considered, regardless of order.
     { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
        "{\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "h",   true,  false },
         { "g",   true,  false },
         { "f",   true,  false },
         { "e",   true,  false },
-        { "d",   true,  false }, },
-      std::string() },
+        { "d",   true,  false }, }),
+      std::string_view() },
     { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
               "\"http://e.com\", \"http://f.com\", \"http://g.com\","
               "\"http://h.com\"],[],[],"
@@ -1876,73 +1884,82 @@
                                 "\"NAVIGATION\", \"NAVIGATION\","
                                 "\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[10, 20, 30, 40, 50, 60, 70]}]",
-      { { "a",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",     true,  true },
         { "h.com", false, false },
         { "g.com", false, false },
         { "f.com", false, false },
         { "e.com", false, false },
-        { "d.com", false, false }, },
-      std::string() },
+        { "d.com", false, false }, }),
+      std::string_view() },
 
     // Ensure that incorrectly sized suggestion relevance lists are ignored.
     // Note that keyword suggestions by default (not in suggested relevance
     // mode) score more highly than the default verbatim.
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "a1",  true,  false },
         { "a2",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // In this case, ignoring the suggested relevance scores means we keep
     // only one navsuggest result.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a1.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://a1.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
        "\"google:suggestrelevance\":[9999, 1]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a1.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // Ensure that all 'verbatim' results are merged with their maximum score.
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
        "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
-      { { "a2",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a2",  true,  true },
         { "a",   true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "2" },
     { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
        "{\"google:suggestrelevance\":[9998, 9997, 9999],"
         "\"google:verbatimrelevance\":0}]",
-      { { "a2",  true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a2",  true,  true },
         { "a",   true,  true },
         { "a1",  true,  false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "2" },
 
     // Ensure that verbatim is always generated without other suggestions.
     // TODO(mpearson): Ensure the value of verbatimrelevance is respected
     // (except when suggested relevances are ignored).
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
-      { { "a",   true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
-      { { "a",   true,  true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
 
     // In reorder mode, navsuggestions will not need to be demoted (because
     // they are marked as not allowed to be default match and will be
@@ -1951,88 +1968,97 @@
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9998, 9999]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9999, 9998]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"https://a/\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999]}]",
-      { { "a",   true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",   true,  true },
         { "a",   false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // Check when navsuggest scores more than verbatim and there is query
     // suggestion but it scores lower.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
         { "a3",     true,  false },
-        kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9999, 9998, 1300]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
         { "a3",     true,  false },
-        kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // Check when navsuggest scores more than a query suggestion.  There is
     // a verbatim but it scores lower.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
         { "a",      true,  true },
-        kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch }),
       "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
         { "a",      true,  true },
-        kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch }),
       "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9999, 9998, 9997]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
       "3" },
     // Check when there is neither verbatim nor a query suggestion that,
     // because we can't demote navsuggestions below a query suggestion,
@@ -2041,45 +2067,49 @@
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9998, 9999]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9999, 9998]}]",
-      { { "a",      true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a",      true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
-      std::string() },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch }),
+      std::string_view() },
     // More checks that everything works when it's not necessary to demote.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a2.com", false, false },
         { "a1.com", false, false },
         { "a",      true,  true },
-        kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch }),
       "3" },
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
         "\"google:verbatimrelevance\":9990,"
         "\"google:suggestrelevance\":[9998, 9997, 9999]}]",
-      { { "a3",     true,  true },
+      std::to_array<KeywordFetcherMatch>({
+        { "a3",     true,  true },
         { "a1.com", false, false },
         { "a2.com", false, false },
         { "a",      true,  true },
-        kEmptyMatch, kEmptyMatch },
+        kEmptyMatch, kEmptyMatch }),
       "3" },
       // clang-format on
   });
 
-  for (size_t i = 0; i < std::size(cases); ++i) {
+  for (size_t i = 0; i < std::size(kCases); ++i) {
     // Send the query twice in order to have a synchronous pass after the first
     // response is received.  This is necessary because SearchProvider doesn't
     // allow an asynchronous response to change the default match.
@@ -2096,35 +2126,35 @@
       ASSERT_TRUE(
           test_url_loader_factory_.IsPending("http://suggest_keyword/a"));
       test_url_loader_factory_.AddResponse("http://suggest_keyword/a",
-                                           cases[i].json);
+                                           kCases[i].json);
 
       RunTillProviderDone();
     }
 
-    SCOPED_TRACE(base::StrCat({"for input with json=", cases[i].json}));
+    SCOPED_TRACE(base::StrCat({"for input with json=", kCases[i].json}));
     const ACMatches& matches = provider_->matches();
     ASSERT_FALSE(matches.empty());
     // Find the first match that's allowed to be the default match and check
     // its inline_autocompletion.
     auto it = FindDefaultMatch(matches);
     ASSERT_NE(matches.end(), it);
-    EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
+    EXPECT_EQ(ASCIIToUTF16(kCases[i].inline_autocompletion),
               it->inline_autocompletion);
 
-    ASSERT_LE(matches.size(), std::size(cases[i].matches));
+    ASSERT_LE(matches.size(), std::size(kCases[i].matches));
     size_t j = 0;
     // Ensure that the returned matches equal the expectations.
     for (; j < matches.size(); ++j) {
-      EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
+      EXPECT_EQ(ASCIIToUTF16(kCases[i].matches[j].contents),
                 matches[j].contents);
-      EXPECT_EQ(cases[i].matches[j].from_keyword, matches[j].keyword == u"k");
-      EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
+      EXPECT_EQ(kCases[i].matches[j].from_keyword, matches[j].keyword == u"k");
+      EXPECT_EQ(kCases[i].matches[j].allowed_to_be_default_match,
                 matches[j].allowed_to_be_default_match);
     }
     // Ensure that no expected matches are missing.
-    for (; j < std::size(cases[i].matches); ++j) {
+    for (; j < std::size(kCases[i].matches); ++j) {
       SCOPED_TRACE(base::StrCat({" Case # ", base::NumberToString(i)}));
-      EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents);
+      EXPECT_EQ(kNotApplicable, kCases[i].matches[j].contents);
     }
   }
 }
@@ -2137,12 +2167,12 @@
   // expected matches.  In particular, receiving the second response shouldn't
   // cause an unexpected inline autcompletion.
   struct {
-    const std::string first_json;
+    const std::string_view first_json;
     const ExpectedMatch first_async_matches[4];
     const ExpectedMatch sync_matches[4];
-    const std::string second_json;
+    const std::string_view second_json;
     const ExpectedMatch second_async_matches[4];
-  } cases[] = {
+  } static constexpr kCases[] = {
       // A simple test that verifies we don't inline autocomplete after the
       // first asynchronous response, but we do at the next keystroke if the
       // response's results were good enough.  Furthermore, we should continue
@@ -2280,7 +2310,7 @@
         kEmptyExpectedMatch,
         kEmptyExpectedMatch},
        {{"ab", true}, {"A", false}, kEmptyExpectedMatch, kEmptyExpectedMatch},
-       std::string(),
+       std::string_view(),
        {{"ab", true}, {"A", false}, kEmptyExpectedMatch, kEmptyExpectedMatch}},
 
       // Note: it's possible that the suggest server returns a suggestion with
@@ -2322,7 +2352,7 @@
        {{"ab", true}, {"ab3", false}, {"ab1", true}, kEmptyExpectedMatch}},
   };
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     // First, send the query "a" and receive the JSON response |first_json|.
     ClearAllResults();
     QueryForInputAndWaitForFetcherResponses(u"a", false, test_case.first_json,
@@ -2332,8 +2362,8 @@
     std::string description =
         base::StrCat({"first asynchronous response for input with first_json=",
                       test_case.first_json});
-    CheckMatches(description, std::size(test_case.first_async_matches),
-                 test_case.first_async_matches, provider_->matches());
+    CheckMatches(description, test_case.first_async_matches,
+                 provider_->matches());
 
     // Then, send the query "ab" and check the synchronous matches.
     description =
@@ -2341,8 +2371,7 @@
                       "input with first_json=",
                       test_case.first_json});
     QueryForInput(u"ab", false, false);
-    CheckMatches(description, std::size(test_case.sync_matches),
-                 test_case.sync_matches, provider_->matches());
+    CheckMatches(description, test_case.sync_matches, provider_->matches());
 
     // Finally, get the provided JSON response, |second_json|, and verify the
     // matches after the second asynchronous response are as expected.
@@ -2353,8 +2382,8 @@
     test_url_loader_factory_.AddResponse("https://defaultturl2/ab",
                                          test_case.second_json);
     RunTillProviderDone();
-    CheckMatches(description, std::size(test_case.second_async_matches),
-                 test_case.second_async_matches, provider_->matches());
+    CheckMatches(description, test_case.second_async_matches,
+                 provider_->matches());
   }
 }
 
@@ -2364,7 +2393,7 @@
   // synchronously) we have the expected matches.  The new keystroke should
   // immediately invalidate old calculator suggestions.
   struct Cases {
-    std::string json;
+    std::string_view json;
     ExpectedMatch async_matches[4];
     ExpectedMatch sync_matches[4];
   };
@@ -2397,7 +2426,7 @@
   if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_DESKTOP)
     cases[0].async_matches[1].contents = "1+2 = 3";
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : cases) {
     // First, send the query "1+2" and receive the JSON response |first_json|.
     ClearAllResults();
     QueryForInputAndWaitForFetcherResponses(u"1+2", false, test_case.json,
@@ -2406,8 +2435,7 @@
     // Verify that the matches after the asynchronous results are as expected.
     std::string description = base::StrCat(
         {"first asynchronous response for input with json=", test_case.json});
-    CheckMatches(description, std::size(test_case.async_matches),
-                 test_case.async_matches, provider_->matches());
+    CheckMatches(description, test_case.async_matches, provider_->matches());
 
     // Then, send the query "1+23" and check the synchronous matches.
     description =
@@ -2415,8 +2443,7 @@
                       "input with json=",
                       test_case.json});
     QueryForInput(u"1+23", false, false);
-    CheckMatches(description, std::size(test_case.sync_matches),
-                 test_case.sync_matches, provider_->matches());
+    CheckMatches(description, test_case.sync_matches, provider_->matches());
   }
 }
 
@@ -2432,17 +2459,18 @@
   // We hardcode the string "term1" below, so ensure that the search term that
   // got added to history already is that string.
   ASSERT_EQ(u"term1", term1_);
-  std::u16string term = term1_.substr(0, term1_.length() - 1);
+  static constexpr std::u16string_view term =
+      term1_.substr(0, term1_.size() - 1);
 
   AddSearchToHistory(default_t_url_, base::StrCat({term, u"2"}), 2);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 
   struct Cases {
-    const std::u16string input;
-    const std::string json;
-    const std::array<std::string, 6> matches;
+    const std::u16string_view input;
+    const std::string_view json;
+    const std::array<std::string_view, 6> matches;
   };
-  auto cases = std::to_array<Cases>({
+  static constexpr auto kCases = std::to_array<Cases>({
       // The history results outscore the default verbatim score.  term2 has
       // more
       // visits so it outscores term1.  The suggestions are still returned since
@@ -2491,43 +2519,44 @@
        {"term", "a1", "a2", "term2", "a3", "a4"}},
   });
 
-  for (size_t i = 0; i < std::size(cases); ++i) {
-    QueryForInputAndWaitForFetcherResponses(cases[i].input, false,
-                                            cases[i].json, std::string());
+  for (size_t i = 0; i < std::size(kCases); ++i) {
+    QueryForInputAndWaitForFetcherResponses(
+        std::u16string(kCases[i].input), false, kCases[i].json, std::string());
 
     const std::string description =
-        base::StrCat({"for input with json=", cases[i].json});
+        base::StrCat({"for input with json=", kCases[i].json});
     const ACMatches& matches = provider_->matches();
 
     // Ensure no extra matches are present.
-    ASSERT_LE(matches.size(), std::size(cases[i].matches));
+    ASSERT_LE(matches.size(), std::size(kCases[i].matches));
 
     size_t j = 0;
     // Ensure that the returned matches equal the expectations.
     for (; j < matches.size(); ++j)
-      EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents)
+      EXPECT_EQ(ASCIIToUTF16(kCases[i].matches[j]), matches[j].contents)
           << description;
     // Ensure that no expected matches are missing.
-    for (; j < std::size(cases[i].matches); ++j)
-      EXPECT_EQ(kNotApplicable, cases[i].matches[j])
+    for (; j < std::size(kCases[i].matches); ++j) {
+      EXPECT_EQ(kNotApplicable, kCases[i].matches[j])
           << "Case # " << i << " " << description;
+    }
   }
 }
 
 // Verifies suggest relevance behavior for URL input.
 TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
   struct DefaultFetcherUrlInputMatch {
-    const std::string match_contents;
+    const std::string_view match_contents;
     AutocompleteMatch::Type match_type;
     bool allowed_to_be_default_match;
   };
-  const DefaultFetcherUrlInputMatch kEmptyMatch = {
+  static constexpr DefaultFetcherUrlInputMatch kEmptyMatch = {
       kNotApplicable, AutocompleteMatchType::NUM_TYPES, false};
   struct {
-    const std::string input;
-    const std::string json;
-    const DefaultFetcherUrlInputMatch output[4];
-  } cases[] = {
+    const std::string_view input;
+    const std::string_view json;
+    const std::array<DefaultFetcherUrlInputMatch, 4> output;
+  } static constexpr kCases[] = {
       // clang-format off
     // Ensure NAVIGATION matches are allowed to be listed first for URL input.
     // Non-inlineable matches should not be allowed to be the default match.
@@ -2536,52 +2565,59 @@
     { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
                 "{\"google:suggesttype\":[\"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9999]}]",
-      { { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
         { "b.com",   AutocompleteMatchType::NAVSUGGEST,            false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
     { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
                 "{\"google:suggesttype\":[\"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9999]}]",
-      { { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
         { "b.com",   AutocompleteMatchType::NAVSUGGEST,            false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
     { "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
                 "{\"google:suggesttype\":[\"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9999]}]",
-      { { "a.com/a", AutocompleteMatchType::NAVSUGGEST,            true },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com/a", AutocompleteMatchType::NAVSUGGEST,            true },
         { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
 
     // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
     // input.  SearchProvider disregards search and verbatim suggested
     // relevances.
     { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
                 "{\"google:suggestrelevance\":[9999]}]",
-      { { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
         { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST,        false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
     { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
                 "{\"google:suggestrelevance\":[9999]}]",
-      { { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
         { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST,        false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
 
     // Ensure the fallback mechanism allows inlineable NAVIGATION matches.
     { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9999, 9998]}]",
-      { { "a.com/b",    AutocompleteMatchType::NAVSUGGEST,            true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com/b",    AutocompleteMatchType::NAVSUGGEST,            true  },
         { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST,        false },
         { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
-        kEmptyMatch } },
+        kEmptyMatch }) },
     { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
                 "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9998, 9997],"
                  "\"google:verbatimrelevance\":9999}]",
-      { { "a.com/b",    AutocompleteMatchType::NAVSUGGEST,            true },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com/b",    AutocompleteMatchType::NAVSUGGEST,            true },
         { "a.com",      AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
         { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST,        false },
-        kEmptyMatch } },
+        kEmptyMatch }) },
 
     // Ensure non-inlineable SUGGEST matches are allowed for URL input
     // assuming the best inlineable match is not a query (i.e., is a
@@ -2589,14 +2625,16 @@
     // list regardless of its score.
     { "a.com", "[\"a.com\",[\"info\"],[],[],"
                 "{\"google:suggestrelevance\":[9999]}]",
-      { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
         { "info",  AutocompleteMatchType::SEARCH_SUGGEST,        false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
     { "a.com", "[\"a.com\",[\"info\"],[],[],"
                 "{\"google:suggestrelevance\":[9999]}]",
-      { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true  },
         { "info",  AutocompleteMatchType::SEARCH_SUGGEST,        false },
-        kEmptyMatch, kEmptyMatch } },
+        kEmptyMatch, kEmptyMatch }) },
 
     // Ensure that if the user explicitly enters a scheme, a navsuggest
     // result for a URL with a different scheme is not inlineable.
@@ -2604,15 +2642,16 @@
                "[\"http://a.com/1\", \"https://a.com/\"],[],[],"
                 "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
                  "\"google:suggestrelevance\":[9000, 8000]}]",
-      { { "http://a.com/1", AutocompleteMatchType::NAVSUGGEST,   true  },
+      std::to_array<DefaultFetcherUrlInputMatch>({
+        { "http://a.com/1", AutocompleteMatchType::NAVSUGGEST,   true  },
         { "https://a.com", AutocompleteMatchType::NAVSUGGEST,    false },
         { "http://a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
                                                                  true  },
-        kEmptyMatch } },
+        kEmptyMatch }) },
       // clang-format on
   };
 
-  for (auto& test_case : cases) {
+  for (auto& test_case : kCases) {
     // Send the query twice in order to have a synchronous pass after the first
     // response is received.  This is necessary because SearchProvider doesn't
     // allow an asynchronous response to change the default match.
@@ -2679,16 +2718,16 @@
 // A basic test that verifies the specific type identifier parsing logic.
 TEST_F(SearchProviderTest, SpecificTypeIdentifierParsing) {
   struct Match {
-    std::string contents;
+    std::string_view contents;
     base::flat_set<omnibox::SuggestSubtype> subtypes;
   };
 
   struct {
-    const std::string input_text;
-    const std::string provider_response_json;
+    const std::string_view input_text;
+    const std::string_view provider_response_json;
     // The order of the expected matches is not important.
     const std::vector<Match> expected_matches;
-  } cases[] = {
+  } const kCases[] = {
       // Check that the specific type is set to 0 when these values are not
       // provide in the response.
       {"a",
@@ -2794,7 +2833,7 @@
          {static_cast<omnibox::SuggestSubtype>(4),
           static_cast<omnibox::SuggestSubtype>(100)}}}}};
 
-  for (const auto& test : cases) {
+  for (const auto& test : kCases) {
     QueryForInputAndWaitForFetcherResponses(ASCIIToUTF16(test.input_text),
                                             false, test.provider_response_json,
                                             std::string());
@@ -2816,52 +2855,57 @@
 // Verifies inline autocompletion of navigational results.
 TEST_F(SearchProviderTest, NavigationInline) {
   struct {
-    const std::string input;
-    const std::string url;
+    const std::string_view input;
+    const std::string_view url;
     // Test the expected fill_into_edit, which may drop "http://".
     // Some cases do not trim "http://" to match from the start of the scheme.
-    const std::string fill_into_edit;
-    const std::string inline_autocompletion;
+    const std::string_view fill_into_edit;
+    const std::string_view inline_autocompletion;
     const bool allowed_to_be_default_match_in_regular_mode;
     const bool allowed_to_be_default_match_in_prevent_inline_mode;
-  } cases[] = {
+  } static constexpr kCases[] = {
       // Do not inline matches that do not contain the input; trim http as
       // needed.
-      {"x", "http://www.abc.com", "www.abc.com", std::string(), false, false},
-      {"https:", "http://www.abc.com", "www.abc.com", std::string(), false,
+      {"x", "http://www.abc.com", "www.abc.com", std::string_view(), false,
+       false},
+      {"https:", "http://www.abc.com", "www.abc.com", std::string_view(), false,
        false},
       {"http://www.abc.com/a", "http://www.abc.com", "http://www.abc.com",
-       std::string(), false, false},
+       std::string_view(), false, false},
 
       // Do not inline matches with invalid input prefixes; trim http as needed.
-      {"ttp", "http://www.abc.com", "www.abc.com", std::string(), false, false},
-      {"://w", "http://www.abc.com", "www.abc.com", std::string(), false,
+      {"ttp", "http://www.abc.com", "www.abc.com", std::string_view(), false,
        false},
-      {"ww.", "http://www.abc.com", "www.abc.com", std::string(), false, false},
-      {".ab", "http://www.abc.com", "www.abc.com", std::string(), false, false},
-      {"bc", "http://www.abc.com", "www.abc.com", std::string(), false, false},
-      {".com", "http://www.abc.com", "www.abc.com", std::string(), false,
+      {"://w", "http://www.abc.com", "www.abc.com", std::string_view(), false,
+       false},
+      {"ww.", "http://www.abc.com", "www.abc.com", std::string_view(), false,
+       false},
+      {".ab", "http://www.abc.com", "www.abc.com", std::string_view(), false,
+       false},
+      {"bc", "http://www.abc.com", "www.abc.com", std::string_view(), false,
+       false},
+      {".com", "http://www.abc.com", "www.abc.com", std::string_view(), false,
        false},
 
       // Do not inline matches that omit input domain labels; trim http as
       // needed.
-      {"www.a", "http://a.com", "a.com", std::string(), false, false},
-      {"http://www.a", "http://a.com", "http://a.com", std::string(), false,
-       false},
-      {"www.a", "ftp://a.com", "ftp://a.com", std::string(), false, false},
-      {"ftp://www.a", "ftp://a.com", "ftp://a.com", std::string(), false,
+      {"www.a", "http://a.com", "a.com", std::string_view(), false, false},
+      {"http://www.a", "http://a.com", "http://a.com", std::string_view(),
+       false, false},
+      {"www.a", "ftp://a.com", "ftp://a.com", std::string_view(), false, false},
+      {"ftp://www.a", "ftp://a.com", "ftp://a.com", std::string_view(), false,
        false},
 
       // Input matching but with nothing to inline will not yield an offset, but
       // will be allowed to be default.
-      {"abc.com", "http://www.abc.com", "www.abc.com", std::string(), true,
+      {"abc.com", "http://www.abc.com", "www.abc.com", std::string_view(), true,
        true},
       {"http://www.abc.com", "http://www.abc.com", "http://www.abc.com",
-       std::string(), true, true},
+       std::string_view(), true, true},
 
       // Inputs with trailing whitespace should inline when possible.
-      {"abc.com ", "http://www.abc.com", "www.abc.com", std::string(), true,
-       true},
+      {"abc.com ", "http://www.abc.com", "www.abc.com", std::string_view(),
+       true, true},
       {"abc.com ", "http://www.abc.com/bar", "www.abc.com/bar", "/bar", false,
        false},
 
@@ -2932,7 +2976,7 @@
        true, false},
   };
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     // First test regular mode.
     QueryForInput(ASCIIToUTF16(test_case.input), false, false);
     SearchSuggestionParser::NavigationResult result(
@@ -3161,14 +3205,15 @@
 // Verify entity suggestion parsing.
 TEST_F(SearchProviderTest, ParseEntitySuggestion) {
   struct Match {
-    std::string contents;
-    std::string description;
-    std::string query_params;
-    std::string fill_into_edit;
+    std::string_view contents;
+    std::string_view description;
+    std::string_view query_params;
+    std::string_view fill_into_edit;
     AutocompleteMatchType::Type type;
   };
-  const Match kEmptyMatch = {kNotApplicable, kNotApplicable, kNotApplicable,
-                             kNotApplicable, AutocompleteMatchType::NUM_TYPES};
+  static constexpr Match kEmptyMatch = {kNotApplicable, kNotApplicable,
+                                        kNotApplicable, kNotApplicable,
+                                        AutocompleteMatchType::NUM_TYPES};
 
   omnibox::EntityInfo entity_info;
   entity_info.set_name("xy");
@@ -3176,10 +3221,10 @@
   entity_info.set_suggest_search_parameters("p=v");
 
   struct {
-    const std::string input_text;
+    const std::string_view input_text;
     const std::string response_json;
-    const Match matches[5];
-  } cases[] = {
+    const std::array<Match, 5> matches;
+  } const kCases[] = {
       // A query and an entity suggestion with different search terms.
       {
           "x",
@@ -3205,12 +3250,13 @@
         "google:suggesttype":["QUERY","ENTITY"]
       }]
       )",
-          {{"x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-           {"xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
-           {"xy", "A", "p=v", "yy",
-            AutocompleteMatchType::SEARCH_SUGGEST_ENTITY},
-           kEmptyMatch,
-           kEmptyMatch},
+          std::to_array<Match>(
+              {{"x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+               {"xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
+               {"xy", "A", "p=v", "yy",
+                AutocompleteMatchType::SEARCH_SUGGEST_ENTITY},
+               kEmptyMatch,
+               kEmptyMatch}),
       },
       // A query and an entity suggestion with same search terms.
       {
@@ -3237,15 +3283,16 @@
         "google:suggesttype":["QUERY","ENTITY"]
       }]
       )",
-          {{"x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
-           {"xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
-           {"xy", "A", "p=v", "xy",
-            AutocompleteMatchType::SEARCH_SUGGEST_ENTITY},
-           kEmptyMatch,
-           kEmptyMatch},
+          std::to_array<Match>(
+              {{"x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+               {"xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
+               {"xy", "A", "p=v", "xy",
+                AutocompleteMatchType::SEARCH_SUGGEST_ENTITY},
+               kEmptyMatch,
+               kEmptyMatch}),
       },
   };
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     QueryForInputAndWaitForFetcherResponses(ASCIIToUTF16(test_case.input_text),
                                             false, test_case.response_json,
                                             std::string());
@@ -3287,7 +3334,7 @@
 // A basic test that verifies the prefetch metadata parsing logic.
 TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
   struct Match {
-    std::string contents;
+    std::string_view contents;
     bool allowed_to_be_prefetched;
     AutocompleteMatchType::Type type;
     bool from_keyword;
@@ -3297,24 +3344,26 @@
                              false};
 
   struct {
-    const std::string input_text;
+    const std::string_view input_text;
     bool prefer_keyword_provider_results;
-    const std::string default_provider_response_json;
-    const std::string keyword_provider_response_json;
-    const Match matches[5];
-  } cases[] = {
+    const std::string_view default_provider_response_json;
+    const std::string_view keyword_provider_response_json;
+    const std::array<Match, 5> matches;
+  } kCases[] = {
       // Default provider response does not have prefetch details. Ensure that
       // the suggestions are not marked as prefetch query.
       {
           "a",
           false,
           "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
-          std::string(),
-          {{"a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false},
-           {"c", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
-           {"b", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
-           kEmptyMatch,
-           kEmptyMatch},
+          std::string_view(),
+          std::to_array<Match>(
+              {{"a", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                false},
+               {"c", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
+               {"b", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
+               kEmptyMatch,
+               kEmptyMatch}),
       },
       // Ensure that default provider suggest response prefetch details are
       // parsed and recorded in AutocompleteMatch.
@@ -3325,12 +3374,14 @@
           "{\"google:clientdata\":{\"phi\": 0},"
           "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\", \"NAVIGATION\"],"
           "\"google:suggestrelevance\":[999, 12, 1]}]",
-          std::string(),
-          {{"ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false},
-           {"abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false},
-           {"b.com", false, AutocompleteMatchType::NAVSUGGEST, false},
-           {"c.com", false, AutocompleteMatchType::NAVSUGGEST, false},
-           kEmptyMatch},
+          std::string_view(),
+          std::to_array<Match>(
+              {{"ab", false, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                false},
+               {"abc", true, AutocompleteMatchType::SEARCH_SUGGEST, false},
+               {"b.com", false, AutocompleteMatchType::NAVSUGGEST, false},
+               {"c.com", false, AutocompleteMatchType::NAVSUGGEST, false},
+               kEmptyMatch}),
       },
       // Default provider suggest response has prefetch details.
       // SEARCH_WHAT_YOU_TYPE suggestion outranks SEARCH_SUGGEST suggestion for
@@ -3343,12 +3394,14 @@
           "{\"google:clientdata\":{\"phi\": 0},"
           "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
           "\"google:suggestrelevance\":[99, 98]}]",
-          std::string(),
-          {{"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, false},
-           {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false},
-           kEmptyMatch,
-           kEmptyMatch,
-           kEmptyMatch},
+          std::string_view(),
+          std::to_array<Match>(
+              {{"ab", true, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                false},
+               {"ab.com", false, AutocompleteMatchType::NAVSUGGEST, false},
+               kEmptyMatch,
+               kEmptyMatch,
+               kEmptyMatch}),
       },
       // Default provider response has prefetch details. We prefer keyword
       // provider results. Ensure that prefetch bit for a suggestion from the
@@ -3361,21 +3414,22 @@
           "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
           "\"google:suggestrelevance\":[9, 12]}]",
           "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
-          {{"a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
-           {"c", false, AutocompleteMatchType::SEARCH_SUGGEST, true},
-           {"b", false, AutocompleteMatchType::SEARCH_SUGGEST, true},
-           {"ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
-           kEmptyMatch},
+          std::to_array<Match>(
+              {{"a", false, AutocompleteMatchType::SEARCH_OTHER_ENGINE, true},
+               {"c", false, AutocompleteMatchType::SEARCH_SUGGEST, true},
+               {"b", false, AutocompleteMatchType::SEARCH_SUGGEST, true},
+               {"ab", false, AutocompleteMatchType::SEARCH_SUGGEST, false},
+               kEmptyMatch}),
       }};
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     QueryForInputAndWaitForFetcherResponses(
         ASCIIToUTF16(test_case.input_text),
         test_case.prefer_keyword_provider_results,
         test_case.default_provider_response_json,
         test_case.prefer_keyword_provider_results
             ? test_case.keyword_provider_response_json
-            : std::string());
+            : std::string_view());
 
     const std::string description = base::StrCat(
         {"for input with json =", test_case.default_provider_response_json});
@@ -3418,29 +3472,30 @@
 // correctly.
 TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
   struct Match {
-    std::string contents;
+    std::string_view contents;
     AutocompleteMatchType::Type type;
   };
-  const Match kEmptyMatch = {kNotApplicable, AutocompleteMatchType::NUM_TYPES};
+  static constexpr Match kEmptyMatch = {kNotApplicable,
+                                        AutocompleteMatchType::NUM_TYPES};
 
   struct Cases {
-    const std::string input_text;
-    const std::string default_provider_response_json;
-    const Match matches[4];
+    const std::string_view input_text;
+    const std::string_view default_provider_response_json;
+    const std::array<Match, 4> matches;
   };
-  auto cases = std::to_array<Cases>({
+  static constexpr auto kCases = std::to_array<Cases>({
       // No XSSI guard.
       {
           "a",
           "[\"a\",[\"b\", \"c\"],[],[],"
           "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
           "\"google:suggestrelevance\":[1, 2]}]",
-          {
+          std::to_array<Match>({
               {"a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
               {"c", AutocompleteMatchType::SEARCH_SUGGEST},
               {"b", AutocompleteMatchType::SEARCH_SUGGEST},
               kEmptyMatch,
-          },
+          }),
       },
       // Standard XSSI guard - )]}'\n.
       {
@@ -3448,12 +3503,12 @@
           ")]}'\n[\"a\",[\"b\", \"c\"],[],[],"
           "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
           "\"google:suggestrelevance\":[1, 2]}]",
-          {
+          std::to_array<Match>({
               {"a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
               {"c", AutocompleteMatchType::SEARCH_SUGGEST},
               {"b", AutocompleteMatchType::SEARCH_SUGGEST},
               kEmptyMatch,
-          },
+          }),
       },
       // Modified XSSI guard - contains "[".
       {
@@ -3461,20 +3516,20 @@
           ")]}'\n[)\"[\"a\",[\"b\", \"c\"],[],[],"
           "{\"google:suggesttype\":[\"QUERY\",\"QUERY\"],"
           "\"google:suggestrelevance\":[1, 2]}]",
-          {
+          std::to_array<Match>({
               {"a", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
               {"c", AutocompleteMatchType::SEARCH_SUGGEST},
               {"b", AutocompleteMatchType::SEARCH_SUGGEST},
               kEmptyMatch,
-          },
+          }),
       },
   });
 
-  for (size_t i = 0; i < std::size(cases); ++i) {
+  for (size_t i = 0; i < std::size(kCases); ++i) {
     ClearAllResults();
     QueryForInputAndWaitForFetcherResponses(
-        ASCIIToUTF16(cases[i].input_text), false,
-        cases[i].default_provider_response_json, std::string());
+        ASCIIToUTF16(kCases[i].input_text), false,
+        kCases[i].default_provider_response_json, std::string());
 
     const ACMatches& matches = provider_->matches();
     // The top match must inline and score as highly as calculated verbatim.
@@ -3482,19 +3537,19 @@
     EXPECT_GE(matches[0].relevance, 1300);
 
     SCOPED_TRACE(base::StrCat({"for case: ", base::NumberToString(i)}));
-    ASSERT_LE(matches.size(), std::size(cases[i].matches));
+    ASSERT_LE(matches.size(), std::size(kCases[i].matches));
     size_t j = 0;
     // Ensure that the returned matches equal the expectations.
     for (; j < matches.size(); ++j) {
       SCOPED_TRACE(base::StrCat({"and match: ", base::NumberToString(j)}));
-      EXPECT_EQ(cases[i].matches[j].contents,
+      EXPECT_EQ(kCases[i].matches[j].contents,
                 base::UTF16ToUTF8(matches[j].contents));
-      EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
+      EXPECT_EQ(kCases[i].matches[j].type, matches[j].type);
     }
-    for (; j < std::size(cases[i].matches); ++j) {
+    for (; j < std::size(kCases[i].matches); ++j) {
       SCOPED_TRACE(base::StrCat({"and match: ", base::NumberToString(j)}));
-      EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
-      EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
+      EXPECT_EQ(kCases[i].matches[j].contents, kNotApplicable);
+      EXPECT_EQ(kCases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
     }
   }
 }
@@ -3503,15 +3558,14 @@
 // personalized query or a personalized URL.
 TEST_F(SearchProviderTest, ParseDeletionUrl) {
   struct Match {
-    std::string contents;
-    std::string deletion_url;
+    std::string_view contents;
+    std::string_view deletion_url;
     AutocompleteMatchType::Type type;
   };
 
-  const Match kEmptyMatch = {kNotApplicable, std::string(),
-                             AutocompleteMatchType::NUM_TYPES};
-
-  auto url = std::to_array<const char*>({
+  static constexpr Match kEmptyMatch = {kNotApplicable, std::string_view(),
+                                        AutocompleteMatchType::NUM_TYPES};
+  static constexpr auto url = std::to_array<const char*>({
       "http://defaultturl/complete/deleteitems"
       "?delq=ab&client=chrome&deltok=xsrf124",
       "http://defaultturl/complete/deleteitems"
@@ -3519,10 +3573,10 @@
   });
 
   struct {
-    const std::string input_text;
-    const std::string response_json;
-    const Match matches[5];
-  } cases[] = {
+    const std::string_view input_text;
+    const std::string_view response_json;
+    const std::array<Match, 5> matches;
+  } static constexpr kCases[] = {
       // clang-format off
       // A deletion URL on a personalized query should be reflected in the
       // resulting AutocompleteMatch.
@@ -3536,13 +3590,14 @@
          "&deltok=xsrf124\"}, {}, {\"du\":"
         "\"/complete/deleteitems?delq=www.amazon.com&"
         "client=chrome&deltok=xsrf123\"}]}]",
-        { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        std::to_array<Match>({
+          { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
           { "ab", url[0], AutocompleteMatchType::SEARCH_SUGGEST },
           { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
           { "amazon.com", url[1],
              AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
           kEmptyMatch,
-        },
+        }),
       },
       // Personalized queries or a personalized URL without deletion URLs
       // shouldn't cause errors.
@@ -3552,13 +3607,14 @@
         "\"PERSONALIZED_NAVIGATION\"],"
         "\"google:suggestrelevance\":[1, 2],"
         "\"google:suggestdetail\":[{}, {}]}]",
-        { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        std::to_array<Match>({
+          { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
           { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
           { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
           { "amazon.com", "",
              AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
           kEmptyMatch,
-        },
+        }),
       },
       // Personalized queries or a personalized URL without
       // google:suggestdetail shouldn't cause errors.
@@ -3567,18 +3623,19 @@
         "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
         "\"PERSONALIZED_NAVIGATION\"],"
         "\"google:suggestrelevance\":[1, 2]}]",
-        { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+        std::to_array<Match>({
+          { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
           { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
           { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
           { "amazon.com", "",
              AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
           kEmptyMatch,
-        },
+        }),
       },
       // clang-format on
   };
 
-  for (auto& test_case : cases) {
+  for (const auto& test_case : kCases) {
     QueryForInputAndWaitForFetcherResponses(ASCIIToUTF16(test_case.input_text),
                                             false, test_case.response_json,
                                             std::string());
@@ -3862,7 +3919,7 @@
   default_t_url_ = turl_model->Add(std::make_unique<TemplateURL>(data));
   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
 
-  std::u16string term = term1_.substr(0, term1_.length() - 1);
+  const std::u16string term(term1_.substr(0, term1_.size() - 1));
   QueryForInput(term, false, false);
 
   // And the URL matches what we expected.
@@ -4288,12 +4345,12 @@
   default_t_url_ = turl_model->Add(std::make_unique<TemplateURL>(data));
   turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
 
-  TestData cases[] = {
+  const TestData kCases[] = {
       {u"k a",
        1,
        {ResultInfo(GURL("http://keyword/a"),
                    AutocompleteMatchType::SEARCH_OTHER_ENGINE, true, u"k a")}},
   };
 
-  RunTest(cases, std::size(cases), false);
+  RunTest(kCases, false);
 }
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
index 26bff22..0f8b296 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowCoordinator.java
@@ -282,11 +282,6 @@
         }
 
         @Override
-        public int getPeekHeight() {
-            return BottomSheetContent.HeightMode.DISABLED;
-        }
-
-        @Override
         public float getFullHeightRatio() {
             return BottomSheetContent.HeightMode.WRAP_CONTENT;
         }
diff --git a/chrome/browser/chrome_content_browser_client_navigation_throttles.cc b/chrome/browser/chrome_content_browser_client_navigation_throttles.cc
index c945ba2..ea2c0d1 100644
--- a/chrome/browser/chrome_content_browser_client_navigation_throttles.cc
+++ b/chrome/browser/chrome_content_browser_client_navigation_throttles.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/lookalikes/lookalike_url_navigation_throttle.h"
 #include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h"
 #include "chrome/browser/policy/policy_util.h"
-#include "chrome/browser/preloading/navigation_ablation_throttle.h"
 #include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
 #include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_navigation_throttle.h"
 #include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
@@ -515,8 +514,6 @@
         profile);
   }
 
-  MaybeCreateAndAddNavigationAblationThrottle(registry);
-
 #if !BUILDFLAG(IS_ANDROID)
   MaybeCreateAndAddWebViewSidePanelThrottle(registry);
 #endif
diff --git a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContent.java b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContent.java
index 0d69494..c6e55e4 100644
--- a/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContent.java
+++ b/chrome/browser/commerce/android/java/src/org/chromium/chrome/browser/commerce/CommerceBottomSheetContent.java
@@ -65,11 +65,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         float containerHeight = mBottomSheetController.getContainerHeight();
         if (containerHeight == 0 || mIsHalfHeightDisabled) {
diff --git a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetContent.java b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetContent.java
index e3a649c..db6ee09 100644
--- a/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetContent.java
+++ b/chrome/browser/commerce/merchant_viewer/android/java/src/org/chromium/chrome/browser/merchant_viewer/MerchantTrustBottomSheetContent.java
@@ -75,11 +75,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HALF_HEIGHT_RATIO;
     }
diff --git a/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsBottomSheetContent.java b/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsBottomSheetContent.java
index dbc7ec1..88e546d 100644
--- a/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsBottomSheetContent.java
+++ b/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsBottomSheetContent.java
@@ -52,11 +52,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
index f053ebed..5f907175 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
@@ -310,11 +310,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DEFAULT;
     }
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/TabGridDialogShareBottomSheetContent.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/TabGridDialogShareBottomSheetContent.java
index bb8e95b..7fda351a 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/TabGridDialogShareBottomSheetContent.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/TabGridDialogShareBottomSheetContent.java
@@ -51,11 +51,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityBottomSheetContent.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityBottomSheetContent.java
index c91d59c..8bd5e522 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityBottomSheetContent.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/ui/recent_activity/RecentActivityBottomSheetContent.java
@@ -66,11 +66,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/download/android/dangerous_download_infobar_delegate.cc b/chrome/browser/download/android/dangerous_download_infobar_delegate.cc
deleted file mode 100644
index 1aa0428b..0000000
--- a/chrome/browser/download/android/dangerous_download_infobar_delegate.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/android/dangerous_download_infobar_delegate.h"
-
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/infobars/android/confirm_infobar.h"
-#include "components/infobars/content/content_infobar_manager.h"
-#include "components/infobars/core/infobar.h"
-#include "ui/base/l10n/l10n_util.h"
-
-// static
-void DangerousDownloadInfoBarDelegate::Create(
-    infobars::ContentInfoBarManager* infobar_manager,
-    download::DownloadItem* download_item) {
-  if (infobar_manager->AddInfoBar(
-          std::make_unique<infobars::ConfirmInfoBar>(base::WrapUnique(
-              new DangerousDownloadInfoBarDelegate(download_item))))) {}
-}
-
-DangerousDownloadInfoBarDelegate::DangerousDownloadInfoBarDelegate(
-    download::DownloadItem* download_item)
-    : download_item_(download_item) {
-  download_item_->AddObserver(this);
-  message_text_ = l10n_util::GetStringFUTF16(
-      IDS_PROMPT_DANGEROUS_DOWNLOAD,
-      base::UTF8ToUTF16(download_item_->GetFileNameToReportUser().value()));
-}
-
-DangerousDownloadInfoBarDelegate::~DangerousDownloadInfoBarDelegate() {
-  if (download_item_)
-    download_item_->RemoveObserver(this);
-}
-
-void DangerousDownloadInfoBarDelegate::OnDownloadDestroyed(
-    download::DownloadItem* download_item) {
-  DCHECK_EQ(download_item, download_item_);
-  download_item_ = nullptr;
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-DangerousDownloadInfoBarDelegate::GetIdentifier() const {
-  return DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID;
-}
-
-int DangerousDownloadInfoBarDelegate::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_WARNING;
-}
-
-bool DangerousDownloadInfoBarDelegate::ShouldExpire(
-    const NavigationDetails& details) const {
-  return false;
-}
-
-void DangerousDownloadInfoBarDelegate::InfoBarDismissed() {
-  if (download_item_)
-    download_item_->Remove();
-}
-
-std::u16string DangerousDownloadInfoBarDelegate::GetMessageText() const {
-  return message_text_;
-}
-
-bool DangerousDownloadInfoBarDelegate::Accept() {
-  if (download_item_)
-    download_item_->ValidateDangerousDownload();
-  return true;
-}
-
-bool DangerousDownloadInfoBarDelegate::Cancel() {
-  if (download_item_)
-    download_item_->Remove();
-  return true;
-}
diff --git a/chrome/browser/download/android/dangerous_download_infobar_delegate.h b/chrome/browser/download/android/dangerous_download_infobar_delegate.h
deleted file mode 100644
index c2a285a..0000000
--- a/chrome/browser/download/android/dangerous_download_infobar_delegate.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_ANDROID_DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_DOWNLOAD_ANDROID_DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/download/public/common/download_item.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-
-namespace infobars {
-class ContentInfoBarManager;
-}
-
-// An infobar that asks if user wants to download a dangerous file.
-// Note that this infobar does not expire if the user subsequently navigates,
-// since such navigations won't automatically cancel the underlying download.
-class DangerousDownloadInfoBarDelegate
-    : public ConfirmInfoBarDelegate,
-      public download::DownloadItem::Observer {
- public:
-  static void Create(infobars::ContentInfoBarManager* infobar_manager,
-                     download::DownloadItem* download_item);
-
-  DangerousDownloadInfoBarDelegate(const DangerousDownloadInfoBarDelegate&) =
-      delete;
-  DangerousDownloadInfoBarDelegate& operator=(
-      const DangerousDownloadInfoBarDelegate&) = delete;
-
-  ~DangerousDownloadInfoBarDelegate() override;
-
-  // download::DownloadItem::Observer:
-  void OnDownloadDestroyed(download::DownloadItem* download_item) override;
-
- private:
-  explicit DangerousDownloadInfoBarDelegate(
-      download::DownloadItem* download_item);
-
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  void InfoBarDismissed() override;
-  std::u16string GetMessageText() const override;
-  bool Accept() override;
-  bool Cancel() override;
-
-  // The download item that is requesting the infobar. Could get deleted while
-  // the infobar is showing.
-  raw_ptr<download::DownloadItem> download_item_;
-  std::u16string message_text_;
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/download/android/download_controller.cc b/chrome/browser/download/android/download_controller.cc
index f411a44..96e33eb 100644
--- a/chrome/browser/download/android/download_controller.cc
+++ b/chrome/browser/download/android/download_controller.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/android/profile_key_startup_accessor.h"
 #include "chrome/browser/android/profile_key_util.h"
 #include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/download/android/dangerous_download_infobar_delegate.h"
 #include "chrome/browser/download/android/download_manager_service.h"
 #include "chrome/browser/download/android/download_utils.h"
 #include "chrome/browser/download/android/new_navigation_observer.h"
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 5ac8997..1a19814 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item_utils.h"
 #include "extensions/buildflags/buildflags.h"
+#include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/user_script.h"
 
@@ -105,7 +106,7 @@
 
   installer->set_error_on_unsupported_requirements(true);
   installer->set_delete_source(true);
-  installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
+  installer->set_was_triggered_by_user_download();
   installer->set_original_mime_type(download_item.GetOriginalMimeType());
   installer->set_apps_require_extension_mime_type(true);
 
diff --git a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoBottomSheetContent.java b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoBottomSheetContent.java
index f8e06c1..01696f5 100644
--- a/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoBottomSheetContent.java
+++ b/chrome/browser/educational_tip/java/src/org/chromium/chrome/browser/educational_tip/cards/DefaultBrowserPromoBottomSheetContent.java
@@ -53,11 +53,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 1e395a63..3f0db6f5 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -123,7 +123,6 @@
       apps_require_extension_mime_type_(false),
       allow_silent_install_(false),
       grant_permissions_(true),
-      install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
       creation_flags_(Extension::NO_FLAGS),
       off_store_install_allow_reason_(OffStoreInstallDisallowed),
       did_handle_successfully_(true),
@@ -297,7 +296,6 @@
 
   expected_id_ = extension_id;
   install_source_ = extension->location();
-  install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
   InitializeCreationFlagsForUpdate(extension, Extension::NO_FLAGS);
 
   const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
@@ -397,8 +395,7 @@
         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
   }
 
-  if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD &&
-      !is_gallery_install() &&
+  if (was_triggered_by_user_download() && !is_gallery_install() &&
       off_store_install_allow_reason_ == OffStoreInstallDisallowed) {
     // Don't delete source in this case so that the user can install
     // manually if they want.
@@ -1005,8 +1002,9 @@
   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
 
   // Tracking number of extensions installed by users
-  if (install_cause() == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD)
+  if (was_triggered_by_user_download()) {
     UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionInstalled", 1, 2);
+  }
 
   if (!content::GetUIThreadTaskRunner({})->PostTask(
           FROM_HERE,
@@ -1172,7 +1170,6 @@
     update_from_settings_page_ = true;
     expected_id_ = installed_extension->id();
     install_source_ = installed_extension->location();
-    install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
   }
 }
 
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index a787099..c6fe89b 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -219,11 +219,11 @@
     original_mime_type_ = original_mime_type;
   }
 
-  extension_misc::CrxInstallCause install_cause() const {
-    return install_cause_;
+  bool was_triggered_by_user_download() const {
+    return was_triggered_by_user_download_;
   }
-  void set_install_cause(extension_misc::CrxInstallCause install_cause) {
-    install_cause_ = install_cause;
+  void set_was_triggered_by_user_download() {
+    was_triggered_by_user_download_ = true;
   }
 
   OffStoreInstallAllowReason off_store_install_allow_reason() const {
@@ -519,9 +519,8 @@
   // Ignored unless `require_extension_mime_type_` is true.
   std::string original_mime_type_;
 
-  // What caused this install?  Used only for histograms that report
-  // on failure rates, broken down by the cause of the install.
-  extension_misc::CrxInstallCause install_cause_;
+  // Was the extension install initiated by a user downloading the extension?
+  bool was_triggered_by_user_download_ = false;
 
   // Creation flags to use for the extension.  These flags will be used
   // when calling Extension::Create() by the crx installer.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index f070f44..23321e2f 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -551,8 +551,7 @@
 
     scoped_refptr<CrxInstaller> crx_installer(
         CrxInstaller::Create(profile(), mock_prompt->CreatePrompt()));
-    crx_installer->set_install_cause(
-        extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
+    crx_installer->set_was_triggered_by_user_download();
 
     if (kTestData[i]) {
       crx_installer->set_off_store_install_allow_reason(
diff --git a/chrome/browser/extensions/external_provider_manager.cc b/chrome/browser/extensions/external_provider_manager.cc
index 8772fed..3268908f 100644
--- a/chrome/browser/extensions/external_provider_manager.cc
+++ b/chrome/browser/extensions/external_provider_manager.cc
@@ -305,7 +305,6 @@
   installer->set_expected_id(info.extension_id);
   installer->set_expected_version(info.version,
                                   true /* fail_install_if_unexpected */);
-  installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE);
   installer->set_install_immediately(info.install_immediately);
   installer->set_creation_flags(info.creation_flags);
 
diff --git a/chrome/browser/extensions/service_worker_tracking_browsertest.cc b/chrome/browser/extensions/service_worker_tracking_browsertest.cc
index 27f37c2..27bf3c6a 100644
--- a/chrome/browser/extensions/service_worker_tracking_browsertest.cc
+++ b/chrome/browser/extensions/service_worker_tracking_browsertest.cc
@@ -203,8 +203,7 @@
       : allow_multiple_worker_per_extension_in_worker_id_set_(
             WorkerIdSet::AllowMultipleWorkersPerExtensionForTesting()),
         allow_multiple_workers_per_extension_in_task_queue_(
-            ServiceWorkerTaskQueue::
-                AllowMultipleWorkersPerExtensionForTesting()) {}
+            ServiceWorkerState::AllowMultipleWorkersPerExtensionForTesting()) {}
 
  protected:
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index ea7d049..127dfe3 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -979,7 +979,6 @@
   }
 
   installer->set_delete_source(file_ownership_passed);
-  installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
 
   return installer;
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
index ad306ac..62a8abd 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
@@ -175,11 +175,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/CardMenuBottomSheetContent.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/CardMenuBottomSheetContent.java
index 755be77..3740ba10 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/CardMenuBottomSheetContent.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/CardMenuBottomSheetContent.java
@@ -51,11 +51,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java
index 60feee1..e9b92ad 100644
--- a/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java
+++ b/chrome/browser/history/java/src/org/chromium/chrome/browser/history/AppFilterSheetContent.java
@@ -64,11 +64,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return BottomSheetContent.HeightMode.DISABLED;
     }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 52ff9fc..f04ad34 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -98,7 +98,6 @@
     scoped_refptr<extensions::CrxInstaller> installer(
         extensions::CrxInstaller::Create(browser()->profile(),
                                          std::move(client)));
-    installer->set_install_cause(extension_misc::INSTALL_CAUSE_AUTOMATION);
     installer->InstallCrx(path);
 
     observer.WaitForExtensionLoaded();
diff --git a/chrome/browser/mandatory_reauth/android/internal/java/src/org/chromium/chrome/browser/mandatory_reauth/MandatoryReauthOptInBottomSheet.java b/chrome/browser/mandatory_reauth/android/internal/java/src/org/chromium/chrome/browser/mandatory_reauth/MandatoryReauthOptInBottomSheet.java
index cdc3bd9d..bccacb98 100644
--- a/chrome/browser/mandatory_reauth/android/internal/java/src/org/chromium/chrome/browser/mandatory_reauth/MandatoryReauthOptInBottomSheet.java
+++ b/chrome/browser/mandatory_reauth/android/internal/java/src/org/chromium/chrome/browser/mandatory_reauth/MandatoryReauthOptInBottomSheet.java
@@ -77,11 +77,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java
index d65ef0d..6e49934 100644
--- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java
+++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java
@@ -187,11 +187,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
index 8db2a90b..14aa8bb 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
@@ -68,11 +68,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeView.java b/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeView.java
index 91e8f5e..64db9604 100644
--- a/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeView.java
+++ b/chrome/browser/password_manager/android/account_storage_notice/java/src/org/chromium/chrome/browser/password_manager/account_storage_notice/AccountStorageNoticeView.java
@@ -77,11 +77,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java
index 22f2bed..ab00787 100644
--- a/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java
+++ b/chrome/browser/password_manager/android/bottom_sheet/java/src/org/chromium/chrome/browser/bottom_sheet/SimpleNoticeSheetView.java
@@ -127,9 +127,4 @@
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
-
-    @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
 }
diff --git a/chrome/browser/password_manager/android/grouped_affiliations/java/src/org/chromium/chrome/browser/grouped_affiliations/AcknowledgeGroupedCredentialSheetView.java b/chrome/browser/password_manager/android/grouped_affiliations/java/src/org/chromium/chrome/browser/grouped_affiliations/AcknowledgeGroupedCredentialSheetView.java
index 2f22073..7d19b4c 100644
--- a/chrome/browser/password_manager/android/grouped_affiliations/java/src/org/chromium/chrome/browser/grouped_affiliations/AcknowledgeGroupedCredentialSheetView.java
+++ b/chrome/browser/password_manager/android/grouped_affiliations/java/src/org/chromium/chrome/browser/grouped_affiliations/AcknowledgeGroupedCredentialSheetView.java
@@ -167,9 +167,4 @@
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
-
-    @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
 }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetView.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetView.java
index 23ba8fe9..489b4d49 100644
--- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetView.java
+++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PostPasswordMigrationSheetView.java
@@ -178,9 +178,4 @@
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
-
-    @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
 }
diff --git a/chrome/browser/pdf/pdf_extension_util.cc b/chrome/browser/pdf/pdf_extension_util.cc
index 655800a1..d55b118 100644
--- a/chrome/browser/pdf/pdf_extension_util.cc
+++ b/chrome/browser/pdf/pdf_extension_util.cc
@@ -200,6 +200,23 @@
       {"ink2BrushColorGreen3", IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_3},
       {"ink2BrushColorBlue3", IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_3},
       {"ink2BrushColorTan3", IDS_PDF_INK2_ANNOTATION_COLOR_TAN_3},
+      {"ink2TextAnnotation", IDS_PDF_INK2_TEXT_ANNOTATION},
+      {"ink2TextFont", IDS_PDF_INK2_TEXT_FONT},
+      {"ink2TextFontSansSerif", IDS_PDF_INK2_TEXT_FONT_SANS_SERIF},
+      {"ink2TextFontSerif", IDS_PDF_INK2_TEXT_FONT_SERIF},
+      {"ink2TextFontMonospace", IDS_PDF_INK2_TEXT_FONT_MONOSPACE},
+      {"ink2TextFontSize", IDS_PDF_INK2_TEXT_FONT_SIZE},
+      {"ink2TextStyles", IDS_PDF_INK2_TEXT_STYLES},
+      {"ink2TextStyleBold", IDS_PDF_INK2_TEXT_STYLE_BOLD},
+      {"ink2TextStyleItalic", IDS_PDF_INK2_TEXT_STYLE_ITALIC},
+      {"ink2TextAlignment", IDS_PDF_INK2_TEXT_ALIGNMENT},
+      {"ink2TextAlignLeft", IDS_PDF_INK2_TEXT_ALIGN_LEFT},
+      {"ink2TextAlignCenter", IDS_PDF_INK2_TEXT_ALIGN_CENTER},
+      {"ink2TextAlignRight", IDS_PDF_INK2_TEXT_ALIGN_RIGHT},
+      {"ink2TextColor", IDS_PDF_INK2_TEXT_COLOR},
+      {"ink2TextColorCyan1", IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_1},
+      {"ink2TextColorCyan2", IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_2},
+      {"ink2TextColorCyan3", IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_3},
 #endif  // BUILDFLAG(ENABLE_PDF_INK2)
   };
   for (const auto& resource : kPdfResources)
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc
index d83cb59..e2de620 100644
--- a/chrome/browser/policy/extension_policy_browsertest.cc
+++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -224,7 +224,6 @@
   scoped_refptr<extensions::CrxInstaller> installer =
       extensions::CrxInstaller::CreateSilent(browser_context);
   installer->set_allow_silent_install(true);
-  installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
   installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE);
   installer->set_off_store_install_allow_reason(
       extensions::CrxInstaller::OffStoreInstallAllowReason::
diff --git a/chrome/browser/preloading/latency_ablation_browsertest.cc b/chrome/browser/preloading/latency_ablation_browsertest.cc
deleted file mode 100644
index e021d0bf3..0000000
--- a/chrome/browser/preloading/latency_ablation_browsertest.cc
+++ /dev/null
@@ -1,502 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "base/feature_list.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/chrome_test_utils.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/search_test_utils.h"
-#include "components/search_engines/template_url_data.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_mock_cert_verifier.h"
-#include "content/public/test/prerender_test_util.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "url/gurl.h"
-
-namespace {
-
-using ::net::test_server::BasicHttpResponse;
-using ::net::test_server::HttpRequest;
-using ::net::test_server::HttpResponse;
-
-constexpr static char kSearchDomain[] = "a.test";
-constexpr static char kSuggestionDomain[] = "a.test";
-constexpr static char16_t kSearchDomain16[] = u"a.test";
-
-// Copy of the feature here to test the actual feature string.
-BASE_FEATURE(kNavigationLatencyAblation,
-             "NavigationLatencyAblation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-std::unique_ptr<HttpResponse> ReturnOKResponseForAllRequests(
-    const HttpRequest& request) {
-  auto http_response = std::make_unique<BasicHttpResponse>();
-  http_response->set_code(net::HTTP_OK);
-  http_response->set_content_type("text/plain");
-  http_response->set_content(request.GetURL().spec());
-  return http_response;
-}
-
-}  // namespace
-
-class LatencyAblationBrowserTest : public InProcessBrowserTest {
- public:
-  LatencyAblationBrowserTest() = default;
-  ~LatencyAblationBrowserTest() override = default;
-
- protected:
-  void SetUpOnMainThread() override {
-    InProcessBrowserTest::SetUpOnMainThread();
-
-    host_resolver()->AddRule("*", "127.0.0.1");
-    https_server_ = std::make_unique<net::EmbeddedTestServer>(
-        net::EmbeddedTestServer::TYPE_HTTPS);
-    https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
-    https_server_->ServeFilesFromSourceDirectory("chrome/test/data");
-    prerender_helper_->RegisterServerRequestMonitor(https_server_.get());
-    https_server_->RegisterRequestHandler(
-        base::BindRepeating(&ReturnOKResponseForAllRequests));
-    ASSERT_TRUE(https_server_->Start());
-
-    TemplateURLService* model = TemplateURLServiceFactory::GetForProfile(
-        chrome_test_utils::GetProfile(this));
-    ASSERT_TRUE(model);
-    search_test_utils::WaitForTemplateURLServiceToLoad(model);
-    ASSERT_TRUE(model->loaded());
-    TemplateURLData data;
-    data.SetShortName(kSearchDomain16);
-    data.SetKeyword(data.short_name());
-    data.SetURL(
-        https_server_->GetURL(kSearchDomain, "/title1.html?q={searchTerms}")
-            .spec());
-    data.suggestions_url =
-        https_server_->GetURL(kSuggestionDomain, "/?q={searchTerms}").spec();
-    TemplateURL* template_url = model->Add(std::make_unique<TemplateURL>(data));
-    ASSERT_TRUE(template_url);
-    model->SetUserSelectedDefaultSearchProvider(template_url);
-
-    mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
-  }
-
-  void SetUpInProcessBrowserTestFixture() override {
-    mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
-    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
-  }
-
-  void TearDownInProcessBrowserTestFixture() override {
-    mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
-    InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
-  }
-
-  void SetUpCommandLine(base::CommandLine* cmd) override {
-    cmd->AppendSwitch("ignore-certificate-errors");
-
-    mock_cert_verifier_.SetUpCommandLine(cmd);
-    InProcessBrowserTest::SetUpCommandLine(cmd);
-  }
-
-  virtual void SetUpFieldTrial() {}
-
-  content::WebContents* GetWebContents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  // Convenient for sub-classes to not have to define this.
-  base::test::ScopedFeatureList scoped_feature_list_;
-  std::unique_ptr<content::test::PrerenderTestHelper> prerender_helper_;
-  std::unique_ptr<net::EmbeddedTestServer> https_server_;
-
- private:
-  void SetUp() override {
-    SetUpFieldTrial();
-
-    prerender_helper_ = std::make_unique<content::test::PrerenderTestHelper>(
-        base::BindRepeating(&LatencyAblationBrowserTest::GetWebContents,
-                            base::Unretained(this)));
-    InProcessBrowserTest::SetUp();
-  }
-
-  content::ContentMockCertVerifier mock_cert_verifier_;
-};
-
-// Check that the default behavior is that there is no ablation.
-IN_PROC_BROWSER_TEST_F(LatencyAblationBrowserTest, DenyIPAddress) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-class LatencyAblationDisabledBrowserTest : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationDisabledBrowserTest() = default;
-  ~LatencyAblationDisabledBrowserTest() override = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {}, {kNavigationLatencyAblation});
-  }
-};
-
-// Check that when the feature is off, there is no ablation.
-IN_PROC_BROWSER_TEST_F(LatencyAblationDisabledBrowserTest, DenyIPAddress) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-class LatencyAblationEnabledBrowserTest : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationEnabledBrowserTest() = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{kNavigationLatencyAblation, {{"duration", "5ms"}}}}, {});
-  }
-};
-
-// Check that IP navigations are not ablated when there is a duration
-// configured. Use the histogram as a proxy for actual ablation.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest, DontAblateIPAddress) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-// Check that prerender navigations and activations are not ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest, DontAblatePrerender) {
-  EXPECT_TRUE(content::NavigateToURL(
-      GetWebContents(), https_server_->GetURL(kSearchDomain, "/title2.html")));
-
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html"));
-  content::FrameTreeNodeId host_id = prerender_helper_->AddPrerender(url);
-  EXPECT_TRUE(host_id);
-  prerender_helper_->NavigatePrimaryPage(url);
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-// Search query navigations should be ablated by default.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest, AblateNonSearch) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("anysite.com", "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search navigations should be ablated by default.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest, AblateSearchHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search hosts that are not search queries should be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest,
-                       AblateSearchRealtedHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSuggestionDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search queries should be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledBrowserTest, AblateSearchQuery) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html?q=cat"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-class LatencyAblationEnabledSearchQueryDisabledBrowserTest
-    : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationEnabledSearchQueryDisabledBrowserTest() = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{kNavigationLatencyAblation,
-          {{"duration", "5ms"}, {"ablate_default_search_queries", "false"}}}},
-        {});
-  }
-};
-
-// Non search queries should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchQueryDisabledBrowserTest,
-                       AblateNonSearch) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("anysite.com", "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search hosts that aren't queries should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchQueryDisabledBrowserTest,
-                       AblateSearchHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search related hosts should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchQueryDisabledBrowserTest,
-                       AblateSearchRealtedHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSuggestionDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// With "ablate_default_search_queries" set to "false" search queries should not
-// be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchQueryDisabledBrowserTest,
-                       DoNotAblateSearchQuery) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html?q=cat"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-class LatencyAblationEnabledSearchHostDisabledBrowserTest
-    : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationEnabledSearchHostDisabledBrowserTest() = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{kNavigationLatencyAblation,
-          {{"duration", "5ms"}, {"ablate_default_search_host", "false"}}}},
-        {});
-  }
-};
-
-// Non search navigations should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchHostDisabledBrowserTest,
-                       AblateNonSearch) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("anysite.com", "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// With "ablate_default_search_host" set to "false", search hosts that aren't
-// queries should be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchHostDisabledBrowserTest,
-                       DoNotAblateSearchHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-// With "ablate_default_search_host" set to "false", search related hosts that
-// aren't queries should be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchHostDisabledBrowserTest,
-                       DoNotAblateSearchRealtedHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSuggestionDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-// With "ablate_default_search_host" set to "false", search queries should still
-// be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledSearchHostDisabledBrowserTest,
-                       AblateSearchQuery) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html?q=cat"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-class LatencyAblationEnabledNonSearchDisabledBrowserTest
-    : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationEnabledNonSearchDisabledBrowserTest() = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{kNavigationLatencyAblation,
-          {{"duration", "5ms"}, {"ablate_non_default_search_host", "false"}}}},
-        {});
-  }
-};
-
-// With "ablate_non_default_search_host" set to "false", non search should not
-// be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledNonSearchDisabledBrowserTest,
-                       DoNotAblateNonSearch) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("anysite.com", "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
-
-// Search host should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledNonSearchDisabledBrowserTest,
-                       DoNotAblateSearchHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search related hosts should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledNonSearchDisabledBrowserTest,
-                       AblateSearchRealtedHost) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSuggestionDomain, "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Search queries should still be ablated.
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledNonSearchDisabledBrowserTest,
-                       AblateSearchQuery) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL(kSearchDomain, "/title1.html?q=cat"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-// Test Latency Ablation based on pattern.
-class LatencyAblationEnabledPatternBrowserTest
-    : public LatencyAblationBrowserTest {
- public:
-  LatencyAblationEnabledPatternBrowserTest() = default;
-
- private:
-  void SetUpFieldTrial() override {
-    scoped_feature_list_.InitWithFeaturesAndParameters(
-        {{kNavigationLatencyAblation,
-          {{"duration", "5ms"},
-           {"pattern", "*foo.test*/maps*"},  // we need * after .test to match
-                                             // `foo.test:[port_num]/maps/...`
-           {"ablate_default_search_queries", "false"},
-           {"ablate_default_search_host", "false"},
-           {"ablate_non_default_search_host", "false"}}}},
-        {});
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledPatternBrowserTest,
-                       AblatePattern) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("www.foo.test", "/maps/places/12345"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    1u);
-}
-
-IN_PROC_BROWSER_TEST_F(LatencyAblationEnabledPatternBrowserTest,
-                       DoNotAblateIfNotMatch) {
-  base::HistogramTester histogram_tester;
-
-  GURL url(https_server_->GetURL("anysite.com", "/title1.html"));
-
-  EXPECT_TRUE(content::NavigateToURL(GetWebContents(), url));
-
-  histogram_tester.ExpectTotalCount("Navigation.LatencyAblation.ExcessWaitTime",
-                                    0u);
-}
diff --git a/chrome/browser/preloading/navigation_ablation_throttle.cc b/chrome/browser/preloading/navigation_ablation_throttle.cc
deleted file mode 100644
index 893ef8fb..0000000
--- a/chrome/browser/preloading/navigation_ablation_throttle.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/preloading/navigation_ablation_throttle.h"
-
-#include <memory>
-
-#include "base/feature_list.h"
-#include "base/functional/bind.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/pattern.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "components/search_engines/search_terms_data.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/navigation_throttle.h"
-#include "content/public/browser/navigation_throttle_registry.h"
-#include "content/public/browser/web_contents.h"
-
-namespace {
-BASE_FEATURE(kNavigationLatencyAblation,
-             "NavigationLatencyAblation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-// The amount of time to stall before resuming loading.
-const base::FeatureParam<base::TimeDelta> kNavigationLatencyAblationDuration{
-    &kNavigationLatencyAblation, "duration", base::Milliseconds(250)};
-
-// The `base::MatchPattern` pattern that identifies the URLs should be ablated.
-const base::FeatureParam<std::string> kAblationTargetPattern{
-    &kNavigationLatencyAblation, "pattern", ""};
-
-// Whether default search Search queries should be ablated.
-const base::FeatureParam<bool> kShouldAblateDefaultSearchQueries{
-    &kNavigationLatencyAblation, "ablate_default_search_queries", true};
-
-// Whether default search navigations to any of the related hosts should be
-// ablated.
-const base::FeatureParam<bool> kShouldAblateDefaultSearchHost{
-    &kNavigationLatencyAblation, "ablate_default_search_host", true};
-
-// Whether the corpus of URLs that are not part of the default search host
-// corpus should be ablated.
-const base::FeatureParam<bool> kShouldAblateNonDefaultSearchHost{
-    &kNavigationLatencyAblation, "ablate_non_default_search_host", true};
-
-// Different URLs re grouped into ablation types, which can be configured to be
-// ablated or not.
-enum class AblationType {
-  kDefaultSearchQuery = 0,
-  kDefaultSearchHost = 1,
-  kNonDefaultSearchHost = 2,
-};
-
-// The name of the throttle for logging purposes.
-constexpr char kNavigationAblationThrottleName[] = "NavigationAblationThrottle";
-
-// Return the type of navigation based on whether `navigation_url` is a search
-// query or related to the user's default search provider.
-AblationType GetAblationType(const GURL& navigation_url,
-                             content::BrowserContext* browser_context) {
-  auto* template_url_service = TemplateURLServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(browser_context));
-  if (!template_url_service) {
-    return AblationType::kNonDefaultSearchHost;
-  }
-
-  auto* default_search = template_url_service->GetDefaultSearchProvider();
-  if (!default_search) {
-    return AblationType::kNonDefaultSearchHost;
-  }
-
-  if (default_search->IsSearchURL(navigation_url,
-                                  template_url_service->search_terms_data())) {
-    return AblationType::kDefaultSearchQuery;
-  }
-
-  for (const auto& url_ref : default_search->url_refs()) {
-    if (url::Origin::Create(navigation_url) ==
-        url::Origin::Create(GURL(url_ref.GetURL()))) {
-      return AblationType::kDefaultSearchHost;
-    }
-  }
-
-  return AblationType::kNonDefaultSearchHost;
-}
-
-bool ShouldCreateThrottle(content::NavigationThrottleRegistry& registry) {
-  if (!base::FeatureList::IsEnabled(kNavigationLatencyAblation)) {
-    return false;
-  }
-
-  // Exclude navigations for prerender or other MPArch.
-  content::NavigationHandle& navigation = registry.GetNavigationHandle();
-  if (!navigation.IsInPrimaryMainFrame()) {
-    return false;
-  }
-
-  // Don't slow down activations from prerender or BFCache.
-  if (navigation.IsPageActivation()) {
-    return false;
-  }
-
-  // Avoid ablating pages that likely are served from HTTP Cache.
-  if (navigation.GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK) {
-    return false;
-  }
-
-  // Avoid ablataing client redirects as they may be part of a chain for a
-  // single navigation.
-  if (navigation.GetPageTransition() & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
-    return false;
-  }
-
-  const GURL& url = navigation.GetURL();
-
-  // Ignore navigations that are not HTTP(S).
-  if (!url.SchemeIsHTTPOrHTTPS()) {
-    return false;
-  }
-
-  // Ignore navigations to IP addresses as these may be local network.
-  if (url.HostIsIPAddress()) {
-    return false;
-  }
-
-  std::string pattern = kAblationTargetPattern.Get();
-  if (!pattern.empty() && base::MatchPattern(url.spec(), pattern)) {
-    return true;
-  }
-
-  auto ablation_type =
-      GetAblationType(url, navigation.GetWebContents()->GetBrowserContext());
-  switch (ablation_type) {
-    case AblationType::kDefaultSearchQuery:
-      return kShouldAblateDefaultSearchQueries.Get();
-    case AblationType::kDefaultSearchHost:
-      return kShouldAblateDefaultSearchHost.Get();
-    case AblationType::kNonDefaultSearchHost:
-      return kShouldAblateNonDefaultSearchHost.Get();
-  }
-}
-
-// A navigation throttle that deferes during WillStartRequest and resumes after
-// a fixed duration.
-class NavigationAblationThrottle : public content::NavigationThrottle {
- public:
-  explicit NavigationAblationThrottle(
-      content::NavigationThrottleRegistry& registry)
-      : content::NavigationThrottle(registry) {}
-  ~NavigationAblationThrottle() override = default;
-
- private:
-  const char* GetNameForLogging() override {
-    return kNavigationAblationThrottleName;
-  }
-
-  ThrottleCheckResult WillStartRequest() override {
-    timer_.Start(
-        FROM_HERE, kNavigationLatencyAblationDuration.Get(),
-        base::BindOnce(&NavigationAblationThrottle::ResumeLoading,
-                       base::Unretained(this), base::TimeTicks::Now()));
-    return content::NavigationThrottle::DEFER;
-  }
-
-  void ResumeLoading(base::TimeTicks start_time) {
-    // Measure the actual wait time to make sure we are near the expected wait
-    // time for the experiment arm.
-    auto wait_time = base::TimeTicks::Now() - start_time;
-    auto excess_wait_time =
-        wait_time - kNavigationLatencyAblationDuration.Get();
-
-    // Record the time spent waiting beyond what was configured.
-    base::UmaHistogramTimes("Navigation.LatencyAblation.ExcessWaitTime",
-                            excess_wait_time);
-
-    Resume();
-  }
-
-  // A timer that resumes the loading after a fixed duration. The timer ensures
-  // that if |this| is deleted the callback does not run and cause a UAF.
-  base::OneShotTimer timer_;
-};
-
-}  // namespace
-
-// static
-void MaybeCreateAndAddNavigationAblationThrottle(
-    content::NavigationThrottleRegistry& registry) {
-  if (!ShouldCreateThrottle(registry)) {
-    return;
-  }
-  registry.AddThrottle(std::make_unique<NavigationAblationThrottle>(registry));
-}
diff --git a/chrome/browser/preloading/navigation_ablation_throttle.h b/chrome/browser/preloading/navigation_ablation_throttle.h
deleted file mode 100644
index 7c8bd2f5..0000000
--- a/chrome/browser/preloading/navigation_ablation_throttle.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRELOADING_NAVIGATION_ABLATION_THROTTLE_H_
-#define CHROME_BROWSER_PRELOADING_NAVIGATION_ABLATION_THROTTLE_H_
-
-namespace content {
-class NavigationThrottleRegistry;
-}  // namespace content
-
-// Creates a throttle that will delay the start of the navigation by a fixed
-// amount of time. This ablation occurs for most navigations, but does not occur
-// for subframes, prerenders, fenced frames, bf/restore style navigations,
-// client redirects, web bundles, or the default search engine based on
-// configuration.
-void MaybeCreateAndAddNavigationAblationThrottle(
-    content::NavigationThrottleRegistry& registry);
-
-#endif  // CHROME_BROWSER_PRELOADING_NAVIGATION_ABLATION_THROTTLE_H_
diff --git a/chrome/browser/preloading/search_preload/search_preload_features.cc b/chrome/browser/preloading/search_preload/search_preload_features.cc
index 1edddbd..838e968 100644
--- a/chrome/browser/preloading/search_preload/search_preload_features.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_features.cc
@@ -23,6 +23,10 @@
 const base::FeatureParam<bool> kDsePreload2OnPressTouchDown{
     &kDsePreload2, "kDsePreload2OnPressTouchDown", true};
 
+BASE_FEATURE(kDsePreload2OnPressIncognito,
+             "DsePreload2OnPressIncognito",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kDsePreload2OnSuggestNonDefalutMatch,
              "kDsePreload2OnSuggestNonDefalutMatch",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -48,4 +52,9 @@
   }
 }
 
+bool IsDsePreload2OnPressIncognitoEnabled() {
+  return IsDsePreload2OnPressEnabled() &&
+         base::FeatureList::IsEnabled(kDsePreload2OnPressIncognito);
+}
+
 }  // namespace features
diff --git a/chrome/browser/preloading/search_preload/search_preload_features.h b/chrome/browser/preloading/search_preload/search_preload_features.h
index 3b37bc53..24242d2 100644
--- a/chrome/browser/preloading/search_preload/search_preload_features.h
+++ b/chrome/browser/preloading/search_preload/search_preload_features.h
@@ -30,6 +30,14 @@
 extern const base::FeatureParam<bool> kDsePreload2OnPressUpOrDownArrowButton;
 extern const base::FeatureParam<bool> kDsePreload2OnPressTouchDown;
 
+// Enables on-press trigger in incognito mode.
+//
+// Corresponds to `SearchNavigationPrefetch.allow_incognito`.
+//
+// For more details, see
+// https://docs.google.com/document/d/1f4dcNYP3O_Ft4yMmC42ETxGC5lM7YF5FDbEgnxUua7M/edit?tab=t.38v8gca76tmi
+BASE_DECLARE_FEATURE(kDsePreload2OnPressIncognito);
+
 // Enables on-suggest prefetch for non default match.
 //
 // For more details, see
@@ -46,6 +54,9 @@
 bool DsePreload2OnPressIsPredictorEnabled(
     omnibox::mojom::NavigationPredictor navigation_predictor);
 
+// Returns true iff on-press in incognito is enabled.
+bool IsDsePreload2OnPressIncognitoEnabled();
+
 }  // namespace features
 
 #endif  // CHROME_BROWSER_PRELOADING_SEARCH_PRELOAD_SEARCH_PRELOAD_FEATURES_H_
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
index afb6e4a..8a389825 100644
--- a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
@@ -165,6 +165,11 @@
     return false;
   }
 
+  if (profile.IsOffTheRecord() &&
+      !features::IsDsePreload2OnPressIncognitoEnabled()) {
+    return false;
+  }
+
   if (!AutocompleteMatch::IsSearchType(match.type)) {
     return false;
   }
diff --git a/chrome/browser/preloading/search_preload/search_preload_service_factory.cc b/chrome/browser/preloading/search_preload/search_preload_service_factory.cc
index 5594a78..d60dcdb 100644
--- a/chrome/browser/preloading/search_preload/search_preload_service_factory.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_service_factory.cc
@@ -13,7 +13,14 @@
 namespace {
 
 ProfileSelections GetProfileSelections() {
-  ProfileSelection profile_selection = ProfileSelection::kOwnInstance;
+  // Note `SearchPreloadService` partially supports Incognito profile. For now,
+  // it supports the on-press triggered search prefetch only. Other prefetches
+  // must not be triggered in Incognito. For more details, see
+  // https://crbug.com/394716358.
+  ProfileSelection profile_selection =
+      features::IsDsePreload2OnPressIncognitoEnabled()
+          ? ProfileSelection::kOwnInstance
+          : ProfileSelection::kOriginalOnly;
   return ProfileSelections::Builder()
       .WithRegular(profile_selection)
       // TODO(crbug.com/40257657): Check if this
diff --git a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
index 06cb6a6..4d91b15 100644
--- a/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
+++ b/chrome/browser/privacy_guide/android/java/src/org/chromium/chrome/browser/privacy_guide/PrivacyGuideBottomSheetView.java
@@ -64,11 +64,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return mHalfHeight;
     }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
index dbeeccd..df0cba5 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java
@@ -509,12 +509,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        // Only full height mode enabled.
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         // Only full height mode enabled.
         return HeightMode.DISABLED;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuSheetContent.java
index d66133dbe..ac32960 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuSheetContent.java
@@ -92,12 +92,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        // Only full height mode enabled.
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         // Only full height mode enabled.
         return HeightMode.DISABLED;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
index 6dce3f120..c269f593 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/NegativeFeedbackMenuSheetContent.java
@@ -158,7 +158,8 @@
 
     private void onOptionsMenuClick(int itemId) {
         // TODO(crbug.com/401256755): Actually send the feedback on click.
-        assumeNonNull(mInteractionHandler).onNegativeFeedback(NegativeFeedbackReason.fromValue(itemId));
+        assumeNonNull(mInteractionHandler)
+                .onNegativeFeedback(NegativeFeedbackReason.fromValue(itemId));
         mBottomSheetController.hideContent(this, true);
     }
 
diff --git a/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsPromoSheetContent.java b/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsPromoSheetContent.java
index 2ffdaf1a..aabc322 100644
--- a/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsPromoSheetContent.java
+++ b/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsPromoSheetContent.java
@@ -17,8 +17,8 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.build.annotations.Nullable;
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.recent_tabs.RestoreTabsMetricsHelper.RestoreTabsOnFREBackPressType;
 import org.chromium.chrome.browser.recent_tabs.RestoreTabsMetricsHelper.RestoreTabsOnFRERestoredTabsResult;
 import org.chromium.chrome.browser.recent_tabs.RestoreTabsMetricsHelper.RestoreTabsOnFREResultAction;
@@ -111,11 +111,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return BottomSheetContent.HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/BUILD.gn
index 7a872a54..3c6d9728 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/BUILD.gn
@@ -10,11 +10,17 @@
 import("//extensions/buildflags/buildflags.gni")
 import("//testing/test.gni")
 import("//tools/typescript/ts_library.gni")
+import("//ui/webui/resources/tools/bundle_js.gni")
+import("//ui/webui/resources/tools/minify_js.gni")
 
 assert(is_chromeos)
 
 group("build") {
-  deps = [ ":copied_files" ]
+  deps = [
+    ":copy_misc_files",
+    ":minify_js",
+    ":minify_js_sandboxed_pumpkin_tagger",
+  ]
 }
 
 accessibility_common_dir =
@@ -124,7 +130,7 @@
 
     # For type-checking purposes, map vision_bundle.mjs to the definition file
     # in third_party/.
-    "chrome-extension://egfdjlfmgnehecnclamagfafdccgfndp/accessibility_common/mv2/third_party/mediapipe_task_vision/vision_bundle.mjs|" + rebase_path(
+    "/accessibility_common/mv2/third_party/mediapipe_task_vision/vision_bundle.mjs|" + rebase_path(
             "$mediapipe_dir/vision.d.ts",
             target_gen_dir),
   ]
@@ -136,30 +142,62 @@
   tsconfig_base = "../../tsconfig.base.json"
 }
 
-# Instead of setting up copy targets, use a script to copy all files.
-run_jsbundler("copied_files") {
-  mode = "copy"
-  dest_dir = accessibility_common_dir
-  clear_dest_dirs = [
-    "autoclick",
-    "dictation",
-    "facegaze",
-    "magnifier",
-  ]
+# Bundles the accessibility common files into a single file.
+bundle_js("bundle_js") {
+  visibility = [ ":minify_js" ]
+
+  host = "_ignored_"
+  input = rebase_path("$tsc_out_dir", root_build_dir)
+  js_module_in_files = [ "accessibility_common_loader.js" ]
+  out_folder = "$target_gen_dir/bundle"
+
   deps = [
     ":copy_mediapipe_files",
     ":ts_build",
     "../../common:copied_files",
   ]
+}
 
-  sources =
-      misc_sources + filter_include(get_target_outputs(":ts_build"), [ "*.js" ])
+# Minifies the bundled script to optimize memory footprint.
+# The minified file gets written directly to $accessibility_common_dir.
+minify_js("minify_js") {
+  visibility = [ ":build" ]
 
-  rewrite_rules = [
-    rebase_path("$tsc_out_dir", root_build_dir) + ":",
-    rebase_path(".", root_build_dir) + ":",
-    rebase_path(closure_library_dir, root_build_dir) + ":closure",
-  ]
+  deps = [ ":bundle_js" ]
+  in_folder = "$target_gen_dir/bundle"
+  in_files = [ "accessibility_common_loader.rollup.js" ]
+  out_folder = "$accessibility_common_dir"
+}
+
+# Bundles the sandboxed pumpkin tagger and its imports into a single file, since
+# it is used to initialize a web worker that is separate from the main
+# background script.
+bundle_js("bundle_js_sandboxed_pumpkin_tagger") {
+  visibility = [ ":minify_js_sandboxed_pumpkin_tagger" ]
+
+  host = "_ignored_"
+  input = rebase_path("$tsc_out_dir/dictation/parse", root_build_dir)
+  js_module_in_files = [ "sandboxed_pumpkin_tagger.js" ]
+  out_folder = "$target_gen_dir/bundle/dictation/parse"
+
+  deps = [ ":ts_build" ]
+}
+
+# Minifies the sandboxed pumpkin tagger to optimize memory footprint.
+# The minified file gets written directly to
+# $accessibility_common_dir/dictation/parse.
+minify_js("minify_js_sandboxed_pumpkin_tagger") {
+  visibility = [ ":build" ]
+
+  deps = [ ":bundle_js_sandboxed_pumpkin_tagger" ]
+  in_folder = "$target_gen_dir/bundle/dictation/parse"
+  in_files = [ "sandboxed_pumpkin_tagger.rollup.js" ]
+  out_folder = "$accessibility_common_dir/dictation/parse"
+}
+
+copy("copy_misc_files") {
+  sources = misc_sources
+  outputs = [ "$accessibility_common_dir/{{source_target_relative}}" ]
 }
 
 # Copies required mediapipe files into the accessibility_common extension
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/background.html b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/background.html
index 708ba14..dba898e83 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/background.html
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/background.html
@@ -1,2 +1,2 @@
 <!-- Module entry point. -->
-<script type="module" src="accessibility_common_loader.js"></script>
+<script type="module" src="accessibility_common_loader.rollup.js"></script>
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin/pumpkin_constants.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin/pumpkin_constants.ts
index be65875..a7fa8709 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin/pumpkin_constants.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin/pumpkin_constants.ts
@@ -142,6 +142,6 @@
 }
 
 export const SANDBOXED_PUMPKIN_TAGGER_JS_FILE =
-    'dictation/parse/sandboxed_pumpkin_tagger.js';
+    'dictation/parse/sandboxed_pumpkin_tagger.rollup.js';
 
 TestImportManager.exportForTesting(['SUPPORTED_LOCALES', SUPPORTED_LOCALES]);
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin_parse_strategy.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin_parse_strategy.ts
index f5e07dd..b7ee7360 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin_parse_strategy.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/pumpkin_parse_strategy.ts
@@ -25,7 +25,7 @@
 import {ListCommandsMacro} from '../macros/list_commands_macro.js';
 
 import {ParseStrategy} from './parse_strategy.js';
-import * as PumpkinConstants from './pumpkin/pumpkin_constants.js';
+import {FromPumpkinTagger, FromPumpkinTaggerCommand, HypothesisArgumentName, PumpkinData, PumpkinLocale, SANDBOXED_PUMPKIN_TAGGER_JS_FILE, SUPPORTED_LOCALES, ToPumpkinTagger, ToPumpkinTaggerCommand} from './pumpkin/pumpkin_constants.js';
 
 /** A parsing strategy that utilizes the Pumpkin semantic parser. */
 export class PumpkinParseStrategy extends ParseStrategy {
@@ -35,12 +35,12 @@
     this.init_();
   }
 
-  private pumpkinData_: PumpkinConstants.PumpkinData|null = null;
+  private pumpkinData_: PumpkinData|null = null;
   private pumpkinTaggerReady_ = false;
   private tagResolver_: (
       (results: proto.speech.pumpkin.PumpkinTaggerResults) => void)|null = null;
   private worker_: Worker|null = null;
-  private locale_: PumpkinConstants.PumpkinLocale|null = null;
+  private locale_: PumpkinLocale|null = null;
   private requestedPumpkinInstall_ = false;
   private onPumpkinTaggerReadyChangedForTesting_: VoidFunction|null = null;
 
@@ -58,7 +58,7 @@
     });
   }
 
-  private onPumpkinInstalled_(data: PumpkinConstants.PumpkinData): void {
+  private onPumpkinInstalled_(data: PumpkinData): void {
     if (!data) {
       console.warn('Pumpkin installed, but data is empty');
       return;
@@ -80,7 +80,8 @@
     this.pumpkinData_ = data;
 
     this.worker_ = new Worker(
-        PumpkinConstants.SANDBOXED_PUMPKIN_TAGGER_JS_FILE, {type: 'module'});
+        new URL(SANDBOXED_PUMPKIN_TAGGER_JS_FILE, import.meta.url),
+        {type: 'module'});
     this.worker_.onmessage = (message) => this.onMessage_(message);
   }
 
@@ -89,9 +90,9 @@
    * context.
    */
   private onMessage_(message: MessageEvent): void {
-    const command: PumpkinConstants.FromPumpkinTagger = message.data;
+    const command: FromPumpkinTagger = message.data;
     switch (command.type) {
-      case PumpkinConstants.FromPumpkinTaggerCommand.READY:
+      case FromPumpkinTaggerCommand.READY:
         this.refreshLocale_();
         if (!this.locale_) {
           throw new Error(
@@ -100,23 +101,23 @@
         }
 
         this.sendToSandboxedPumpkinTagger_({
-          type: PumpkinConstants.ToPumpkinTaggerCommand.LOAD,
+          type: ToPumpkinTaggerCommand.LOAD,
           locale: this.locale_,
           pumpkinData: this.pumpkinData_,
         });
         this.pumpkinData_ = null;
         return;
-      case PumpkinConstants.FromPumpkinTaggerCommand.FULLY_INITIALIZED:
+      case FromPumpkinTaggerCommand.FULLY_INITIALIZED:
         this.setPumpkinTaggerReady_(true);
         this.maybeRefresh_();
         return;
-      case PumpkinConstants.FromPumpkinTaggerCommand.TAG_RESULTS:
+      case FromPumpkinTaggerCommand.TAG_RESULTS:
         // TODO(crbug.com/314203187): Not null asserted, check that this is
         // correct.
         this.tagResolver_!
             (command.results as proto.speech.pumpkin.PumpkinTaggerResults);
         return;
-      case PumpkinConstants.FromPumpkinTaggerCommand.REFRESHED:
+      case FromPumpkinTaggerCommand.REFRESHED:
         this.setPumpkinTaggerReady_(true);
         this.maybeRefresh_();
         return;
@@ -127,8 +128,7 @@
     }
   }
 
-  private sendToSandboxedPumpkinTagger_(
-      command: PumpkinConstants.ToPumpkinTagger): void {
+  private sendToSandboxedPumpkinTagger_(command: ToPumpkinTagger): void {
     if (!this.worker_) {
       throw new Error(
           `Worker not ready, cannot send command to SandboxedPumpkinTagger: ${
@@ -157,7 +157,7 @@
     for (let i = 0; i < numArgs; i++) {
       const argument = hypothesis.actionArgumentList[i];
       // See Variable Argument Placeholders in voiceaccess.patterns_template.
-      if (argument.name === PumpkinConstants.HypothesisArgumentName.SEM_TAG) {
+      if (argument.name === HypothesisArgumentName.SEM_TAG) {
         // Map Pumpkin's STOP_LISTENING to generic TOGGLE_DICTATION macro.
         // When this is run by Dictation, it always stops.
         if (argument.value === 'STOP_LISTENING') {
@@ -165,20 +165,13 @@
         } else {
           tag = MacroName[argument.value as keyof typeof MacroName];
         }
-      } else if (
-          argument.name === PumpkinConstants.HypothesisArgumentName.NUM_ARG) {
+      } else if (argument.name === HypothesisArgumentName.NUM_ARG) {
         repeat = argument.value;
-      } else if (
-          argument.name ===
-          PumpkinConstants.HypothesisArgumentName.OPEN_ENDED_TEXT) {
+      } else if (argument.name === HypothesisArgumentName.OPEN_ENDED_TEXT) {
         text = argument.value;
-      } else if (
-          argument.name ===
-          PumpkinConstants.HypothesisArgumentName.BEGIN_PHRASE) {
+      } else if (argument.name === HypothesisArgumentName.BEGIN_PHRASE) {
         beginPhrase = argument.value;
-      } else if (
-          argument.name ===
-          PumpkinConstants.HypothesisArgumentName.END_PHRASE) {
+      } else if (argument.name === HypothesisArgumentName.END_PHRASE) {
         endPhrase = argument.value;
       }
     }
@@ -284,8 +277,8 @@
   }
 
   private refreshLocale_(): void {
-    this.locale_ =
-        PumpkinConstants.SUPPORTED_LOCALES[LocaleInfo.locale as keyof typeof PumpkinConstants.SUPPORTED_LOCALES] || null;
+    this.locale_ = SUPPORTED_LOCALES[
+        LocaleInfo.locale as keyof typeof SUPPORTED_LOCALES] || null;
   }
 
   /**
@@ -293,8 +286,8 @@
    * the pumpkin locale.
    */
   private maybeRefresh_(): void {
-    const dictationLocale =
-        PumpkinConstants.SUPPORTED_LOCALES[LocaleInfo.locale as keyof typeof PumpkinConstants.SUPPORTED_LOCALES] || null;
+    const dictationLocale = SUPPORTED_LOCALES[
+        LocaleInfo.locale as keyof typeof SUPPORTED_LOCALES] || null;
     if (dictationLocale !== this.locale_) {
       this.refresh();
     }
@@ -314,7 +307,7 @@
 
     this.setPumpkinTaggerReady_(false);
     this.sendToSandboxedPumpkinTagger_({
-      type: PumpkinConstants.ToPumpkinTaggerCommand.REFRESH,
+      type: ToPumpkinTaggerCommand.REFRESH,
       locale: this.locale_,
     });
   }
@@ -329,7 +322,7 @@
     // TODO(crbug.com/1264544): Could increase the hypotheses count from 1
     // when we are ready to implement disambiguation.
     this.sendToSandboxedPumpkinTagger_({
-      type: PumpkinConstants.ToPumpkinTaggerCommand.TAG,
+      type: ToPumpkinTaggerCommand.TAG,
       text,
       numResults: 1,
     });
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/sandboxed_pumpkin_tagger.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/sandboxed_pumpkin_tagger.ts
index c328ea4..9587a544 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/sandboxed_pumpkin_tagger.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/dictation/parse/sandboxed_pumpkin_tagger.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import * as PumpkinConstants from './pumpkin/pumpkin_constants.js';
+import {FromPumpkinTagger, FromPumpkinTaggerCommand, PumpkinData, PumpkinLocale, ToPumpkinTagger, ToPumpkinTaggerCommand} from './pumpkin/pumpkin_constants.js';
 
 /**
  * A class that unpacks and loads the pumpkin semantic parser. Runs in a
@@ -14,13 +14,12 @@
   }
 
   private pumpkinTagger_: speech.pumpkin.api.js.PumpkinTagger|null = null;
-  private pumpkinData_: PumpkinConstants.PumpkinData|null = null;
+  private pumpkinData_: PumpkinData|null = null;
 
   private init_(): void {
     globalThis.addEventListener(
         'message', (message) => this.onMessage_(message));
-    this.sendToBackground_(
-        {type: PumpkinConstants.FromPumpkinTaggerCommand.READY});
+    this.sendToBackground_({type: FromPumpkinTaggerCommand.READY});
   }
 
   /**
@@ -28,9 +27,9 @@
    * SandboxedPumpkinTagger's web worker.
    */
   private onMessage_(message: MessageEvent): void {
-    const command: PumpkinConstants.ToPumpkinTagger = message.data;
+    const command: ToPumpkinTagger = message.data;
     switch (command.type) {
-      case PumpkinConstants.ToPumpkinTaggerCommand.LOAD:
+      case ToPumpkinTaggerCommand.LOAD:
         if (!command.pumpkinData) {
           throw new Error(`Can't load pumpkin tagger from empty data`);
         }
@@ -39,12 +38,12 @@
         }
         this.load_(command.pumpkinData, command.locale);
         return;
-      case PumpkinConstants.ToPumpkinTaggerCommand.TAG:
+      case ToPumpkinTaggerCommand.TAG:
         // TODO(crbug.com/314203187): Not null asserted, check that this is
         // correct.
         this.tagAndGetNBestHypotheses_(command.text!, command.numResults!);
         return;
-      case PumpkinConstants.ToPumpkinTaggerCommand.REFRESH:
+      case ToPumpkinTaggerCommand.REFRESH:
         if (!command.locale) {
           throw new Error(`Can't load pumpkin tagger from empty locale`);
         }
@@ -57,7 +56,7 @@
     }
   }
 
-  private sendToBackground_(command: PumpkinConstants.FromPumpkinTagger): void {
+  private sendToBackground_(command: FromPumpkinTagger): void {
     postMessage(command);
   }
 
@@ -66,12 +65,10 @@
     const results =
         this.pumpkinTagger_!.tagAndGetNBestHypotheses(text, numResults);
     this.sendToBackground_(
-        {type: PumpkinConstants.FromPumpkinTaggerCommand.TAG_RESULTS, results});
+        {type: FromPumpkinTaggerCommand.TAG_RESULTS, results});
   }
 
-  private async load_(
-      data: PumpkinConstants.PumpkinData,
-      locale: PumpkinConstants.PumpkinLocale) {
+  private async load_(data: PumpkinData, locale: PumpkinLocale) {
     this.pumpkinData_ = data;
     // Unpack the PumpkinTagger JS.
     const pumpkinTaggerBytes = data.js_pumpkin_tagger_bin_js;
@@ -135,14 +132,13 @@
 
     // Save the PumpkinTagger and notify the background context.
     this.pumpkinTagger_ = pumpkinTagger;
-    this.sendToBackground_(
-        {type: PumpkinConstants.FromPumpkinTaggerCommand.FULLY_INITIALIZED});
+    this.sendToBackground_({type: FromPumpkinTaggerCommand.FULLY_INITIALIZED});
   }
 
   /**
    * Refreshes SandboxedPumpkinTagger in a new locale.
    */
-  refresh_(locale: PumpkinConstants.PumpkinLocale): void {
+  refresh_(locale: PumpkinLocale): void {
     if (!this.pumpkinTagger_) {
       throw new Error(
           'SandboxedPumpkinTagger must be initialized before calling refresh');
@@ -152,34 +148,34 @@
     this.pumpkinTagger_.initializeFromPumpkinConfig(pumpkinConfig);
     this.pumpkinTagger_.loadActionFrame(actionConfig);
     this.sendToBackground_({
-      type: PumpkinConstants.FromPumpkinTaggerCommand.REFRESHED,
+      type: FromPumpkinTaggerCommand.REFRESHED,
     });
   }
 
-  getConfigsForLocale(locale: PumpkinConstants.PumpkinLocale):
+  getConfigsForLocale(locale: PumpkinLocale):
       {pumpkinConfig: ArrayBuffer; actionConfig: ArrayBuffer} {
     let pumpkinConfig;
     let actionConfig;
     // TODO(crbug.com/314203187): Not null asserted, check that this is
     // correct.
     switch (locale) {
-      case PumpkinConstants.PumpkinLocale.EN_US:
+      case PumpkinLocale.EN_US:
         pumpkinConfig = this.pumpkinData_!.en_us_pumpkin_config_binarypb;
         actionConfig = this.pumpkinData_!.en_us_action_config_binarypb;
         break;
-      case PumpkinConstants.PumpkinLocale.FR_FR:
+      case PumpkinLocale.FR_FR:
         pumpkinConfig = this.pumpkinData_!.fr_fr_pumpkin_config_binarypb;
         actionConfig = this.pumpkinData_!.fr_fr_action_config_binarypb;
         break;
-      case PumpkinConstants.PumpkinLocale.IT_IT:
+      case PumpkinLocale.IT_IT:
         pumpkinConfig = this.pumpkinData_!.it_it_pumpkin_config_binarypb;
         actionConfig = this.pumpkinData_!.it_it_action_config_binarypb;
         break;
-      case PumpkinConstants.PumpkinLocale.DE_DE:
+      case PumpkinLocale.DE_DE:
         pumpkinConfig = this.pumpkinData_!.de_de_pumpkin_config_binarypb;
         actionConfig = this.pumpkinData_!.de_de_action_config_binarypb;
         break;
-      case PumpkinConstants.PumpkinLocale.ES_ES:
+      case PumpkinLocale.ES_ES:
         pumpkinConfig = this.pumpkinData_!.es_es_pumpkin_config_binarypb;
         actionConfig = this.pumpkinData_!.es_es_action_config_binarypb;
         break;
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/facegaze/web_cam_face_landmarker.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/facegaze/web_cam_face_landmarker.ts
index 275a6fab..f574d2d 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/facegaze/web_cam_face_landmarker.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv2/facegaze/web_cam_face_landmarker.ts
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {FaceLandmarker} from '/accessibility_common/mv2/third_party/mediapipe_task_vision/vision_bundle.mjs';
 import {TestImportManager} from '/common/testing/test_import_manager.js';
 import type {FaceLandmarkerOptions, FaceLandmarkerResult} from '/third_party/mediapipe/vision.js';
-import {FaceLandmarker} from 'chrome-extension://egfdjlfmgnehecnclamagfafdccgfndp/accessibility_common/mv2/third_party/mediapipe_task_vision/vision_bundle.mjs';
 
 import {BubbleController} from './bubble_controller.js';
 import {PrefNames} from './constants.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
index 8a1b6f0c..6b7b58c 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/BUILD.gn
@@ -37,7 +37,7 @@
   "dictation/earcons/audio_end.wav",
   "dictation/earcons/audio_initiate.wav",
   "dictation/earcons/null_selection.wav",
-  "dictation/offscreen.html",
+  "offscreen.html",
 ]
 
 # TS files to build.
@@ -141,6 +141,8 @@
   tsconfig_base = "../../tsconfig.base.json"
 }
 
+# TODO(crbug.com/388867838): Use bundle_js and minify_js, similar to what is
+# done for mv2.
 # Instead of setting up copy targets, use a script to copy all files.
 run_jsbundler("copied_files") {
   mode = "copy"
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
index 95b94779..7ef4f13 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/accessibility_common_loader.ts
@@ -22,8 +22,7 @@
  * are enabled.
  */
 export class AccessibilityCommon {
-  private static offscreenDocumentPromises_: Map<string, Promise<void>> =
-      new Map();
+  private static offscreenDocumentPromise_: Promise<void>|null;
 
   private autoclick_: Autoclick|null = null;
   private magnifier_: Magnifier|null = null;
@@ -39,7 +38,8 @@
   private facegazeLoadCallbackForTest_: Function|null = null;
 
   static readonly FACEGAZE_PREF_NAME = 'settings.a11y.face_gaze.enabled';
-
+  static readonly OFFSCREEN_DOCUMENT_PATH =
+      'accessibility_common/mv3/offscreen.html';
 
   constructor() {
     this.init_();
@@ -48,16 +48,11 @@
   static async init(): Promise<void> {
     await Flags.init();
     globalThis.accessibilityCommon = new AccessibilityCommon();
-    return AccessibilityCommon.initializeOffscreenDocuments();
+    return this.maybeCreateOffscreenDocument();
   }
 
-  static async initializeOffscreenDocuments(): Promise<void> {
-    await Promise.all([this.maybeCreateOffscreenDocument(
-        'accessibility_common/mv3/dictation/offscreen.html')]);
-  }
-
-  static async maybeCreateOffscreenDocument(url: string): Promise<void> {
-    const offscreenUrl = chrome.runtime.getURL(url);
+  static async maybeCreateOffscreenDocument(): Promise<void> {
+    const offscreenUrl = chrome.runtime.getURL(this.OFFSCREEN_DOCUMENT_PATH);
     const existingContexts = await chrome.runtime.getContexts({
       contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],
       documentUrls: [offscreenUrl]
@@ -65,14 +60,14 @@
     if (existingContexts.length > 0) {
       return;
     }
-    if (!this.offscreenDocumentPromises_.has(url)) {
+    if (!this.offscreenDocumentPromise_) {
       const promise = chrome.offscreen.createDocument({
         url: offscreenUrl,
         reasons: [chrome.offscreen.Reason.WORKERS],
         justification: 'Audio web API and web assembly execution',
       });
       await promise;
-      this.offscreenDocumentPromises_.set(url, promise);
+      this.offscreenDocumentPromise_ = promise;
     }
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html
deleted file mode 100644
index ef0b9824..0000000
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/dictation/offscreen.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!--
-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.
--->
-
-<body>
-  <script type="module" src="offscreen_audio.js"></script>
-  <script type="module" src="offscreen_pumpkin_worker.js"></script>
-</body>
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen.html b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen.html
new file mode 100644
index 0000000..d37c612
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/offscreen.html
@@ -0,0 +1,10 @@
+<!--
+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.
+-->
+
+<body>
+  <script type="module" src="dictation/offscreen_audio.js"></script>
+  <script type="module" src="dictation/offscreen_pumpkin_worker.js"></script>
+</body>
diff --git a/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts b/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts
index 3ed649c..b26af80 100644
--- a/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts
+++ b/chrome/browser/resources/pdf/elements/ink_annotation_text_mixin.ts
@@ -16,10 +16,6 @@
 export const TEXT_SIZES: number[] =
     [6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 40, 48, 64, 72, 100];
 
-// TODO(crbug.com/402547554): Fix labels to correspond to colors, and add
-// the labels to pdf_strings.grdp once they are available from UX. Some
-// "blue" colors are actually teal, "Yellow3" and "Red2" are subtly different
-// from the corresponding brush colors.
 export const TEXT_COLORS: ColorOption[] = [
   // Row 1:
   {label: 'annotationColorBlack', color: '#000000', blended: false},
@@ -31,19 +27,19 @@
   {label: 'ink2BrushColorRed1', color: '#f28b82', blended: false},
   {label: 'ink2BrushColorYellow1', color: '#fdd663', blended: false},
   {label: 'ink2BrushColorGreen1', color: '#81c995', blended: false},
-  {label: 'ink2BrushColorBlue1', color: '#78d9ec', blended: false},
+  {label: 'ink2TextColorCyan1', color: '#78d9ec', blended: false},
   {label: 'ink2BrushColorBlue1', color: '#8ab4f8', blended: false},
   // Row 3:
   {label: 'ink2BrushColorRed2', color: '#e94235', blended: false},
   {label: 'ink2BrushColorYellow2', color: '#fbbc04', blended: false},
   {label: 'ink2BrushColorGreen2', color: '#34a853', blended: false},
-  {label: 'ink2BrushColorBlue2', color: '#24c1e0', blended: false},
+  {label: 'ink2TextColorCyan2', color: '#24c1e0', blended: false},
   {label: 'ink2BrushColorBlue2', color: '#4285f4', blended: false},
   // Row 4:
   {label: 'ink2BrushColorRed3', color: '#c5221f', blended: false},
   {label: 'ink2BrushColorYellow3', color: '#d56e0c', blended: false},
   {label: 'ink2BrushColorGreen3', color: '#188038', blended: false},
-  {label: 'ink2BrushColorBlue3', color: '#12a4af', blended: false},
+  {label: 'ink2TextColorCyan3', color: '#12a4af', blended: false},
   {label: 'ink2BrushColorBlue3', color: '#1967d2', blended: false},
 ];
 
@@ -75,15 +71,13 @@
         accessor sizes: number[] = TEXT_SIZES;
 
         getLabelForTypeface(typeface: TextTypeface): string {
-          // TODO(crbug.com/402547554): These strings should be retrieved from
-          // loadTimeData so they are internationalized once they are final.
           switch (typeface) {
             case TextTypeface.SANS_SERIF:
-              return 'Sans-serif';
+              return 'ink2TextFontSansSerif';
             case TextTypeface.SERIF:
-              return 'Serif';
+              return 'ink2TextFontSerif';
             case TextTypeface.MONOSPACE:
-              return 'Fixed-width';
+              return 'ink2TextFontMonospace';
           }
         }
 
diff --git a/chrome/browser/resources/pdf/elements/ink_color_selector.html.ts b/chrome/browser/resources/pdf/elements/ink_color_selector.html.ts
index 51bf23f..485350f 100644
--- a/chrome/browser/resources/pdf/elements/ink_color_selector.html.ts
+++ b/chrome/browser/resources/pdf/elements/ink_color_selector.html.ts
@@ -11,7 +11,7 @@
 export function getHtml(this: InkColorSelectorElement) {
   return html`<!--_html_template_start_-->
     <cr-grid role="radiogroup" columns="5" focus-selector=".color-chip"
-        aria-label="$i18n{ink2Color}"
+        aria-label="${this.label}"
         @cr-grid-focus-changed="${this.onCrGridFocusChanged_}">
       ${this.colors.map(item => html`
         <label class="color-item">
diff --git a/chrome/browser/resources/pdf/elements/ink_color_selector.ts b/chrome/browser/resources/pdf/elements/ink_color_selector.ts
index 9588207..983ca24 100644
--- a/chrome/browser/resources/pdf/elements/ink_color_selector.ts
+++ b/chrome/browser/resources/pdf/elements/ink_color_selector.ts
@@ -47,11 +47,13 @@
         notify: true,
         type: Object,
       },
+      label: {type: String},
     };
   }
 
   accessor colors: ColorOption[] = [];
   accessor currentColor: Color = {r: 0, g: 0, b: 0};
+  accessor label: string = '';
 
   protected onColorClick_(e: Event) {
     this.setBrushColor_(e.currentTarget as HTMLInputElement);
diff --git a/chrome/browser/resources/pdf/elements/ink_text_box.ts b/chrome/browser/resources/pdf/elements/ink_text_box.ts
index eceb50d..a047f17 100644
--- a/chrome/browser/resources/pdf/elements/ink_text_box.ts
+++ b/chrome/browser/resources/pdf/elements/ink_text_box.ts
@@ -8,6 +8,7 @@
 import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import type {TextAttributes, TextBoxRect} from '../constants.js';
+import {TextTypeface} from '../constants.js';
 import {colorsEqual, convertRotatedCoordinates, Ink2Manager, stylesEqual} from '../ink2_manager.js';
 import type {TextBoxInit, ViewportParams} from '../ink2_manager.js';
 import {colorToHex} from '../pdf_viewer_utils.js';
@@ -35,6 +36,17 @@
 // this value is held constant regardless of zoom due to the rendering issue.
 const MIN_WIDTH_PX = 36;
 
+function getStyleForTypeface(typeface: TextTypeface): string {
+  switch (typeface) {
+    case TextTypeface.SANS_SERIF:
+      return 'Arial, sans-serif';
+    case TextTypeface.SERIF:
+      return 'Times, serif';
+    case TextTypeface.MONOSPACE:
+      return '"Courier New", monospace';
+  }
+}
+
 const InkTextBoxElementBase = InkTextObserverMixin(CrLitElement);
 
 export class InkTextBoxElement extends InkTextBoxElementBase {
@@ -378,7 +390,8 @@
   }
 
   private updateTextAttributes_(newAttributes: TextAttributes) {
-    this.$.textbox.style.fontFamily = newAttributes.typeface;
+    this.$.textbox.style.fontFamily =
+        getStyleForTypeface(newAttributes.typeface);
     this.attributes_ = newAttributes;
     this.styleFontSize_();
     this.$.textbox.style.textAlign = newAttributes.alignment;
diff --git a/chrome/browser/resources/pdf/elements/text_alignment_selector.html.ts b/chrome/browser/resources/pdf/elements/text_alignment_selector.html.ts
index 25596602..2520dd1 100644
--- a/chrome/browser/resources/pdf/elements/text_alignment_selector.html.ts
+++ b/chrome/browser/resources/pdf/elements/text_alignment_selector.html.ts
@@ -15,17 +15,18 @@
 export function getHtml(this: TextAlignmentSelectorElement) {
   // clang-format off
   return html`<!--_html_template_start_-->
-    <cr-radio-group selectable-elements="selectable-icon-button"
+    <cr-radio-group aria-label="$i18n{ink2TextAlignment}"
+        selectable-elements="selectable-icon-button"
         .selected="${this.currentAlignment_}"
         @selected-changed="${this.onSelectedAlignmentChanged_}">
       <selectable-icon-button icon="pdf-ink:text-align-left"
-          name="${TextAlignment.LEFT}" label="Left">
+          name="${TextAlignment.LEFT}" label="$i18n{ink2TextAlignLeft}">
       </selectable-icon-button>
       <selectable-icon-button icon="pdf-ink:text-align-center"
-          name="${TextAlignment.CENTER}" label="Center">
+          name="${TextAlignment.CENTER}" label="$i18n{ink2TextAlignCenter}">
       </selectable-icon-button>
       <selectable-icon-button icon="pdf-ink:text-align-right"
-          name="${TextAlignment.RIGHT}" label="Right">
+          name="${TextAlignment.RIGHT}" label="$i18n{ink2TextAlignRight}">
       </selectable-icon-button>
     </cr-radio-group>
   <!--_html_template_end_-->`;
diff --git a/chrome/browser/resources/pdf/elements/text_styles_selector.html.ts b/chrome/browser/resources/pdf/elements/text_styles_selector.html.ts
index a5f8016..7996cde 100644
--- a/chrome/browser/resources/pdf/elements/text_styles_selector.html.ts
+++ b/chrome/browser/resources/pdf/elements/text_styles_selector.html.ts
@@ -18,8 +18,8 @@
           data-style="${style}"
           iron-icon="pdf-ink:text-format-${style}"
           aria-pressed="${this.getAriaPressed_(style)}"
-          aria-label="${style}"
-          title="${style}">
+          aria-label="${this.getTitle_(style)}"
+          title="${this.getTitle_(style)}">
       </cr-icon-button>`)}
   <!--_html_template_end_-->`;
   // clang-format on
diff --git a/chrome/browser/resources/pdf/elements/text_styles_selector.ts b/chrome/browser/resources/pdf/elements/text_styles_selector.ts
index 0b0dce2..0ff8ccf 100644
--- a/chrome/browser/resources/pdf/elements/text_styles_selector.ts
+++ b/chrome/browser/resources/pdf/elements/text_styles_selector.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
 import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import type {TextAttributes, TextStyles} from '../constants.js';
@@ -12,7 +13,8 @@
 import {getCss} from './text_styles_selector.css.js';
 import {getHtml} from './text_styles_selector.html.js';
 
-const TextStylesSelectorElementBase = InkTextObserverMixin(CrLitElement);
+const TextStylesSelectorElementBase =
+    InkTextObserverMixin(I18nMixinLit(CrLitElement));
 
 export class TextStylesSelectorElement extends TextStylesSelectorElementBase {
   static get is() {
@@ -57,6 +59,15 @@
     return this.currentStyles_[style] ? 'true' : 'false';
   }
 
+  protected getTitle_(style: TextStyle) {
+    switch (style) {
+      case TextStyle.BOLD:
+        return this.i18n('ink2TextStyleBold');
+      case TextStyle.ITALIC:
+        return this.i18n('ink2TextStyleItalic');
+    }
+  }
+
   override onTextAttributesChanged(attributes: TextAttributes) {
     this.currentStyles_ = attributes.styles;
   }
diff --git a/chrome/browser/resources/pdf/elements/viewer_bottom_toolbar.html.ts b/chrome/browser/resources/pdf/elements/viewer_bottom_toolbar.html.ts
index 25d6743..7b6250c 100644
--- a/chrome/browser/resources/pdf/elements/viewer_bottom_toolbar.html.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_bottom_toolbar.html.ts
@@ -15,7 +15,7 @@
 
 export function getHtml(this: ViewerBottomToolbarElement) {
   // clang-format off
-  return html`
+  return html`<!--_html_template_start_-->
     <ink-brush-selector .currentType="${this.currentType}"
         @current-type-changed="${this.onCurrentTypeChanged}">
     </ink-brush-selector>
@@ -32,11 +32,12 @@
       <viewer-bottom-toolbar-dropdown id="color"
           .buttonTitle="${this.getColorTitle_()}">
         <div slot="icon" class="color-chip"></div>
-        <ink-color-selector slot="menu" .colors="${this.availableBrushColors()}"
+        <ink-color-selector slot="menu" label="$i18n{ink2Color}"
+            .colors="${this.availableBrushColors()}"
             .currentColor="${this.currentColor}"
             @current-color-changed="${this.onCurrentColorChanged}">
         </ink-color-selector>
       </viewer-bottom-toolbar-dropdown>` : ''}
-  `;
+  <!--_html_template_end_-->`;
   // clang-format on
 }
diff --git a/chrome/browser/resources/pdf/elements/viewer_side_panel.html.ts b/chrome/browser/resources/pdf/elements/viewer_side_panel.html.ts
index f9002d30..65529da3 100644
--- a/chrome/browser/resources/pdf/elements/viewer_side_panel.html.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_side_panel.html.ts
@@ -20,7 +20,8 @@
             @current-size-changed="${this.onCurrentSizeChanged}">
         </ink-size-selector>
         <h2>$i18n{ink2Color}</h2>
-        <ink-color-selector .colors="${this.availableBrushColors()}"
+        <ink-color-selector label="$i18n{ink2Color}"
+            .colors="${this.availableBrushColors()}"
             .currentColor="${this.currentColor}"
             @current-color-changed="${this.onCurrentColorChanged}">
         </ink-color-selector>
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts
index bc8f8d26..6fcfc4c 100644
--- a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.html.ts
@@ -15,32 +15,36 @@
 
 export function getHtml(this: ViewerTextBottomToolbarElement) {
   // clang-format off
-  return html`
-      <select class="md-select" @change="${this.onTypefaceSelected}"=>
+  return html`<!--_html_template_start_-->
+      <select class="md-select" @change="${this.onTypefaceSelected}"
+          aria-label="$i18n{ink2TextFont}">
         ${this.fontNames.map(typeface => html`
           <option value="${typeface}"
               ?selected="${this.isSelectedTypeface(typeface)}">
-            ${this.getLabelForTypeface(typeface)}
+            ${this.i18n(this.getLabelForTypeface(typeface))}
           </option>`)}
       </select>
-      <select class="md-select size-select" @change="${this.onSizeSelected}">
+      <select class="md-select size-select" @change="${this.onSizeSelected}"
+          aria-label="$i18n{ink2TextFontSize}">
         ${this.sizes.map(size => html`
           <option value="${size}" ?selected="${this.isSelectedSize(size)}">
             ${size}
           </option>`)}
       </select>
       <text-styles-selector></text-styles-selector>
-      <viewer-bottom-toolbar-dropdown id="alignment" .buttonTitle="Alignment">
+      <viewer-bottom-toolbar-dropdown id="alignment"
+          button-title="$i18n{ink2TextAlignment}">
         <cr-icon slot="icon" icon="${this.getAlignmentIcon_()}"></cr-icon>
         <text-alignment-selector slot="menu"></text-alignment-selector>
       </viewer-bottom-toolbar-dropdown>
-      <viewer-bottom-toolbar-dropdown id="color" .buttonTitle="Text Color">
+      <viewer-bottom-toolbar-dropdown id="color"
+          button-title="$i18n{ink2TextColor}">
         <div slot="icon" class="color-chip"></div>
-        <ink-color-selector slot="menu" .colors="${this.colors}"
-            .currentColor="${this.currentColor}"
+        <ink-color-selector slot="menu" label="$i18n{ink2TextColor}"
+            .colors="${this.colors}" .currentColor="${this.currentColor}"
             @current-color-changed="${this.onCurrentColorChanged}">
         </ink-color-selector>
       </viewer-bottom-toolbar-dropdown>
-  `;
+  <!--_html_template_end_-->`;
   // clang-format on
 }
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.ts b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.ts
index b9ab2b8..ed67443 100644
--- a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
 import {assertNotReached} from 'chrome://resources/js/assert.js';
 import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
@@ -17,7 +18,7 @@
 import {getHtml} from './viewer_text_bottom_toolbar.html.js';
 
 const ViewerTextBottomToolbarElementBase =
-    InkAnnotationTextMixin(InkTextObserverMixin(CrLitElement));
+    InkAnnotationTextMixin(InkTextObserverMixin(I18nMixinLit(CrLitElement)));
 
 export interface ViewerTextBottomToolbarElement {
   $: {
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts
index 53194f3a..51c25a94 100644
--- a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.html.ts
@@ -14,15 +14,17 @@
   // clang-format off
   return html`<!--_html_template_start_-->
     <div class="side-panel-content">
-      <h2>Font</h2>
-      <select class="md-select" @change="${this.onTypefaceSelected}">
+      <h2>$i18n{ink2TextFont}</h2>
+      <select class="md-select" @change="${this.onTypefaceSelected}"
+          aria-label="$i18n{ink2TextFont}">
         ${this.fontNames.map(typeface => html`
           <option value="${typeface}"
               ?selected="${this.isSelectedTypeface(typeface)}">
-            ${this.getLabelForTypeface(typeface)}
+            ${this.i18n(this.getLabelForTypeface(typeface))}
           </option>`)}
       </select>
-      <select class="md-select" @change="${this.onSizeSelected}">
+      <select class="md-select" @change="${this.onSizeSelected}"
+          aria-label="$i18n{ink2TextFontSize}">
         ${this.sizes.map(size => html`
           <option value="${size}" ?selected="${this.isSelectedSize(size)}">
             ${size}
@@ -30,14 +32,14 @@
       </select>
     </div>
     <div class="side-panel-content">
-      <h2>Styles</h2>
+      <h2>$i18n{ink2TextStyles}</h2>
       <text-styles-selector></text-styles-selector>
       <text-alignment-selector></text-alignment-selector>
     </div>
     <div class="side-panel-content">
-      <h2>Text color</h2>
-      <ink-color-selector .colors="${this.colors}"
-          .currentColor="${this.currentColor}"
+      <h2>$i18n{ink2TextColor}</h2>
+      <ink-color-selector label="$i18n{ink2TextColor}"
+          .colors="${this.colors}" .currentColor="${this.currentColor}"
           @current-color-changed="${this.onCurrentColorChanged}">
       </ink-color-selector>
     </div>
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.ts b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.ts
index 474fea1..ab77844 100644
--- a/chrome/browser/resources/pdf/elements/viewer_text_side_panel.ts
+++ b/chrome/browser/resources/pdf/elements/viewer_text_side_panel.ts
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
 import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import {InkAnnotationTextMixin} from './ink_annotation_text_mixin.js';
@@ -10,7 +11,7 @@
 import {getHtml} from './viewer_text_side_panel.html.js';
 
 const ViewerTextSidePanelElementBase =
-    InkAnnotationTextMixin(InkTextObserverMixin(CrLitElement));
+    InkAnnotationTextMixin(InkTextObserverMixin(I18nMixinLit(CrLitElement)));
 
 export class ViewerTextSidePanelElement extends ViewerTextSidePanelElementBase {
   static get is() {
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java
index 5976ac13..d47c587 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DevicePickerBottomSheetContent.java
@@ -115,12 +115,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        // Return DISABLED to ensure that the entire bottom sheet is shown.
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         // Return WRAP_CONTENT to have the bottom sheet only open as far as it needs to display the
         // list of devices and nothing beyond that.
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NoTargetDeviceBottomSheetContent.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NoTargetDeviceBottomSheetContent.java
index 7245a50c..ae3a3e9b 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NoTargetDeviceBottomSheetContent.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/NoTargetDeviceBottomSheetContent.java
@@ -63,12 +63,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        // Return DISABLED to ensure that the entire bottom sheet is shown.
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         // Return WRAP_CONTENT to have the bottom sheet only open as far as it needs to display the
         // list of devices and nothing beyond that.
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
index 16699942..b56c439 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContent.java
@@ -669,12 +669,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        // Return false to ensure that the entire bottom sheet is shown.
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         // Return WRAP_CONTENT to have the bottom sheet only open as far as it needs to display the
         // list of devices and nothing beyond that.
diff --git a/chrome/browser/supervised_user/android/java/src/org/chromium/chrome/browser/supervised_user/website_approval/WebsiteApprovalSheetContent.java b/chrome/browser/supervised_user/android/java/src/org/chromium/chrome/browser/supervised_user/website_approval/WebsiteApprovalSheetContent.java
index 7bba882..9c3d3502 100644
--- a/chrome/browser/supervised_user/android/java/src/org/chromium/chrome/browser/supervised_user/website_approval/WebsiteApprovalSheetContent.java
+++ b/chrome/browser/supervised_user/android/java/src/org/chromium/chrome/browser/supervised_user/website_approval/WebsiteApprovalSheetContent.java
@@ -71,11 +71,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/chrome/browser/tab_group_suggestion/android/java/src/org/chromium/chrome/browser/tab_group_suggestion/GroupSuggestionsBottomSheetContent.java b/chrome/browser/tab_group_suggestion/android/java/src/org/chromium/chrome/browser/tab_group_suggestion/GroupSuggestionsBottomSheetContent.java
index 8354f22..a053ce14 100644
--- a/chrome/browser/tab_group_suggestion/android/java/src/org/chromium/chrome/browser/tab_group_suggestion/GroupSuggestionsBottomSheetContent.java
+++ b/chrome/browser/tab_group_suggestion/android/java/src/org/chromium/chrome/browser/tab_group_suggestion/GroupSuggestionsBottomSheetContent.java
@@ -74,11 +74,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public boolean swipeToDismissEnabled() {
         return true;
     }
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtils.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtils.java
index 03008fd7..868a450 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtils.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtils.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.tabmodel;
 
+import android.view.MotionEvent;
+
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.components.browser_ui.widget.list_view.ListViewTouchTracker;
@@ -37,4 +39,31 @@
         // Allow undo as long as the last "single tap up" was *not* from a mouse.
         return !MotionEventUtils.isMouseEvent(lastSingleTapUp.source, lastSingleTapUp.toolType[0]);
     }
+
+    /**
+     * Whether tab / tab group closure should allow undo, depending on the {@link MotionEvent} that
+     * triggered the closure.
+     *
+     * @param triggeringMotionEvent {@link MotionEvent} that triggered the closure.
+     * @return true if undo is allowed.
+     */
+    public static boolean shouldAllowUndo(@Nullable MotionEvent triggeringMotionEvent) {
+        if (triggeringMotionEvent == null) {
+            return true;
+        }
+
+        // Allow undo as long as the triggering motion was *not* from a mouse.
+        return !MotionEventUtils.isMouseEvent(triggeringMotionEvent);
+    }
+
+    /**
+     * Whether tab / tab group closure should allow undo, depending on the button state of the
+     * "down" motion that initiated the closure.
+     *
+     * @param downMotionButtonState the "down" motion's {@link MotionEvent#getButtonState()}
+     * @return true if undo is allowed.
+     */
+    public static boolean shouldAllowUndo(int downMotionButtonState) {
+        return downMotionButtonState == MotionEventUtils.MOTION_EVENT_BUTTON_NONE;
+    }
 }
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtilsUnitTest.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtilsUnitTest.java
index 017e1842..845bc75 100644
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtilsUnitTest.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/TabClosureParamsUtilsUnitTest.java
@@ -18,18 +18,20 @@
 import org.robolectric.RobolectricTestRunner;
 
 import org.chromium.components.browser_ui.widget.list_view.FakeListViewTouchTracker;
+import org.chromium.components.browser_ui.widget.list_view.ListViewTouchTracker;
 import org.chromium.components.browser_ui.widget.list_view.ListViewTouchTracker.ListViewTouchInfo;
+import org.chromium.ui.util.MotionEventUtils;
 
 @RunWith(RobolectricTestRunner.class)
 public class TabClosureParamsUtilsUnitTest {
 
     @Test
-    public void shouldAllowUndo_nullListViewTouchTracker_returnTrue() {
-        assertTrue(TabClosureParamsUtils.shouldAllowUndo(/* listViewTouchTracker= */ null));
+    public void shouldAllowUndo_forListViewTouchTracker_nullListViewTouchTracker_returnTrue() {
+        assertTrue(TabClosureParamsUtils.shouldAllowUndo((ListViewTouchTracker) null));
     }
 
     @Test
-    public void shouldAllowUndo_nullLastSingleTapUp_returnTrue() {
+    public void shouldAllowUndo_forListViewTouchTracker_nullLastSingleTapUp_returnTrue() {
         FakeListViewTouchTracker fakeListViewTouchTracker = new FakeListViewTouchTracker();
         fakeListViewTouchTracker.setLastSingleTapUpInfo(null);
 
@@ -37,7 +39,8 @@
     }
 
     @Test
-    public void shouldAllowUndo_lastSingleTapUpFromTouchScreen_returnTrue() {
+    public void
+            shouldAllowUndo_forListViewTouchTracker_lastSingleTapUpFromTouchScreen_returnTrue() {
         long downMotionTime = SystemClock.uptimeMillis();
         FakeListViewTouchTracker fakeListViewTouchTracker = new FakeListViewTouchTracker();
         fakeListViewTouchTracker.setLastSingleTapUpInfo(
@@ -55,7 +58,7 @@
     }
 
     @Test
-    public void shouldAllowUndo_lastSingleTapUpFromMouse_returnFalse() {
+    public void shouldAllowUndo_forListViewTouchTracker_lastSingleTapUpFromMouse_returnFalse() {
         long downMotionTime = SystemClock.uptimeMillis();
         FakeListViewTouchTracker fakeListViewTouchTracker = new FakeListViewTouchTracker();
         fakeListViewTouchTracker.setLastSingleTapUpInfo(
@@ -72,6 +75,54 @@
         assertFalse(TabClosureParamsUtils.shouldAllowUndo(fakeListViewTouchTracker));
     }
 
+    @Test
+    public void shouldAllowUndo_forTriggeringMotion_nullMotion_returnTrue() {
+        assertTrue(TabClosureParamsUtils.shouldAllowUndo((MotionEvent) null));
+    }
+
+    @Test
+    public void shouldAllowUndo_forTriggeringMotion_touchScreenMotion_returnTrue() {
+        long downMotionTime = SystemClock.uptimeMillis();
+        MotionEvent triggeringMotionEvent =
+                createMotionEvent(
+                        downMotionTime,
+                        /* eventTime= */ downMotionTime + 50,
+                        MotionEvent.ACTION_UP,
+                        /* x= */ 0.0f,
+                        /* y= */ 0.0f,
+                        InputDevice.SOURCE_TOUCHSCREEN,
+                        MotionEvent.TOOL_TYPE_FINGER);
+
+        assertTrue(TabClosureParamsUtils.shouldAllowUndo(triggeringMotionEvent));
+    }
+
+    @Test
+    public void shouldAllowUndo_forTriggeringMotion_mouseMotion_returnFalse() {
+        long downMotionTime = SystemClock.uptimeMillis();
+        MotionEvent triggeringMotionEvent =
+                createMotionEvent(
+                        downMotionTime,
+                        /* eventTime= */ downMotionTime + 50,
+                        MotionEvent.ACTION_UP,
+                        /* x= */ 0.0f,
+                        /* y= */ 0.0f,
+                        InputDevice.SOURCE_MOUSE,
+                        MotionEvent.TOOL_TYPE_MOUSE);
+
+        assertFalse(TabClosureParamsUtils.shouldAllowUndo(triggeringMotionEvent));
+    }
+
+    @Test
+    public void shouldAllowUndo_forDownMotionButtonState_buttonStateAbsent_returnTrue() {
+        assertTrue(
+                TabClosureParamsUtils.shouldAllowUndo(MotionEventUtils.MOTION_EVENT_BUTTON_NONE));
+    }
+
+    @Test
+    public void shouldAllowUndo_forDownMotionButtonState_buttonStatePresent_returnFalse() {
+        assertFalse(TabClosureParamsUtils.shouldAllowUndo(MotionEvent.BUTTON_PRIMARY));
+    }
+
     /**
      * Creates a {@link MotionEvent}.
      *
diff --git a/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillViewBase.java b/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillViewBase.java
index 4c183524..f231542 100644
--- a/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillViewBase.java
+++ b/chrome/browser/touch_to_fill/common/android/java/src/org/chromium/chrome/browser/touch_to_fill/common/TouchToFillViewBase.java
@@ -338,11 +338,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         // WRAP_CONTENT would be the right fit but this disables the HALF state.
         return Math.min(getMaximumSheetHeightPx(), mBottomSheetController.getContainerHeight())
diff --git a/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java b/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
index 4efed0c..3b50489d 100644
--- a/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
+++ b/chrome/browser/touch_to_fill/password_manager/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
@@ -378,6 +378,11 @@
                                                 getSheetClosedAccessibilityStringId() {
                                             return Resources.ID_NULL;
                                         }
+
+                                        @Override
+                                        public int getPeekHeight() {
+                                            return HeightMode.DEFAULT;
+                                        }
                                     };
                             mBottomSheetController.requestShowContent(
                                     content, /* animate= */ false);
diff --git a/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetContent.java b/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetContent.java
index 8ef74cac..8a991c6f 100644
--- a/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetContent.java
+++ b/chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/java/src/org/chromium/chrome/browser/touch_to_fill/no_passkeys/NoPasskeysBottomSheetContent.java
@@ -147,11 +147,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public String getSheetContentDescription(Context context) {
         return context.getString(R.string.no_passkeys_sheet_content_description);
     }
diff --git a/chrome/browser/touch_to_fill/password_manager/password_generation/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/password_generation/TouchToFillPasswordGenerationView.java b/chrome/browser/touch_to_fill/password_manager/password_generation/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/password_generation/TouchToFillPasswordGenerationView.java
index 755ff479..7ce8b4a0 100644
--- a/chrome/browser/touch_to_fill/password_manager/password_generation/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/password_generation/TouchToFillPasswordGenerationView.java
+++ b/chrome/browser/touch_to_fill/password_manager/password_generation/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/password_generation/TouchToFillPasswordGenerationView.java
@@ -164,9 +164,4 @@
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
-
-    @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
 }
diff --git a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
index 1e32152c..c65d328 100644
--- a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
+++ b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
@@ -321,11 +321,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DEFAULT;
     }
diff --git a/chrome/browser/ui/android/extensions/extension_keybinding_registry_android.cc b/chrome/browser/ui/android/extensions/extension_keybinding_registry_android.cc
index 0c0e88635..f42fcb9 100644
--- a/chrome/browser/ui/android/extensions/extension_keybinding_registry_android.cc
+++ b/chrome/browser/ui/android/extensions/extension_keybinding_registry_android.cc
@@ -19,6 +19,7 @@
 #include "ui/events/android/key_event_android.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
 
 ExtensionKeybindingRegistryAndroid::ExtensionKeybindingRegistryAndroid(
     content::BrowserContext* context,
@@ -82,9 +83,8 @@
     return false;
   }
 
-  ui::KeyEventAndroid native_key_event(env, java_key_event);
-  ui::KeyEvent key_event = native_key_event.ToKeyEvent();
-  ui::Accelerator accelerator(key_event);
+  ui::PlatformEvent native_event((ui::KeyEventAndroid(env, java_key_event)));
+  ui::Accelerator accelerator((ui::KeyEvent(native_event)));
 
   if (!active_accelerators_.contains(accelerator)) {
     return false;
diff --git a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java
index bec7461..a82ea408 100644
--- a/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java
+++ b/chrome/browser/ui/android/fast_checkout/internal/java/src/org/chromium/chrome/browser/ui/fast_checkout/FastCheckoutSheetContent.java
@@ -87,11 +87,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         if (shouldWrapContent()) {
             return HeightMode.DISABLED;
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn
index e9c2fa9..b2f05e6 100644
--- a/chrome/browser/ui/android/omnibox/BUILD.gn
+++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -346,6 +346,7 @@
   deps = [
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/styles/android:java_resources",
+    "//components/strings:components_strings_grd",
     "//content/public/android:content_java_resources",
   ]
 }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
index c49cf5e..e109521 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -1093,6 +1093,9 @@
     private void setProfile(Profile profile) {
         if (profile == null || !mNativeInitialized) return;
 
+        mUrlCoordinator.setUrlBarHintText(
+                SearchEngineUtils.getForProfile(mProfileSupplier.get()).getSearchBoxHintText());
+
         assumeNonNull(mOmniboxPrerender);
         mOmniboxPrerender.initializeForProfile(profile);
         mSearchEngineUtils = SearchEngineUtils.getForProfile(profile);
@@ -1379,6 +1382,8 @@
     @Override
     public void onTemplateURLServiceChanged() {
         sLastCachedIsLensOnOmniboxEnabled = Boolean.valueOf(isLensEnabled(LensEntryPoint.OMNIBOX));
+        mUrlCoordinator.setUrlBarHintText(
+                SearchEngineUtils.getForProfile(mProfileSupplier.get()).getSearchBoxHintText());
     }
 
     // OmniboxStub implementation.
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java
index 6d6f68f0..2818b09ae 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtils.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.omnibox;
 
+import android.content.Context;
 import android.text.TextUtils;
 
 import androidx.annotation.IntDef;
@@ -19,6 +20,7 @@
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
+import org.chromium.chrome.browser.omnibox.styles.OmniboxResourceProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.CachedZeroSuggestionsManager;
 import org.chromium.chrome.browser.omnibox.suggestions.CachedZeroSuggestionsManager.SearchEngineMetadata;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -27,6 +29,7 @@
 import org.chromium.chrome.browser.theme.ThemeUtils;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
+import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
 import org.chromium.url.GURL;
@@ -42,6 +45,7 @@
             ProfileKeyedMap.createMapOfDestroyables();
     private static @Nullable SearchEngineUtils sInstanceForTesting;
 
+    private final Context mContext;
     private final Profile mProfile;
     private final boolean mIsOffTheRecord;
     private final TemplateUrlService mTemplateUrlService;
@@ -51,6 +55,7 @@
     private @Nullable Boolean mNeedToCheckForSearchEnginePromo;
     private boolean mDoesDefaultSearchEngineHaveLogo;
     private @Nullable StatusIconResource mSearchEngineLogo;
+    private String mSearchBoxHintText;
 
     /**
      * AndroidSearchEngineLogoEvents defined in tools/metrics/histograms/enums.xml. These values are
@@ -83,12 +88,15 @@
         mProfile = profile;
         mIsOffTheRecord = profile.isOffTheRecord();
         mFaviconHelper = faviconHelper;
+        mContext = ContextUtils.getApplicationContext();
 
         mSearchEngineLogoTargetSizePixels =
-                ContextUtils.getApplicationContext()
-                        .getResources()
+                mContext.getResources()
                         .getDimensionPixelSize(R.dimen.omnibox_search_engine_logo_favicon_size);
 
+        mSearchBoxHintText =
+                OmniboxResourceProvider.getString(mContext, R.string.omnibox_empty_hint);
+
         mTemplateUrlService = TemplateUrlServiceFactory.getForProfile(profile);
         mTemplateUrlService.addObserver(this);
         mDefaultSearchEngineMetadata = CachedZeroSuggestionsManager.readSearchEngineMetadata();
@@ -118,12 +126,24 @@
     @Override
     public void onTemplateURLServiceChanged() {
         mDoesDefaultSearchEngineHaveLogo = mTemplateUrlService.doesDefaultSearchEngineHaveLogo();
+        mSearchBoxHintText =
+                OmniboxResourceProvider.getString(mContext, R.string.omnibox_empty_hint);
+
         var templateUrl = mTemplateUrlService.getDefaultSearchEngineTemplateUrl();
         if (templateUrl == null) {
             recordEvent(Events.FETCH_FAILED_NULL_URL);
             return;
         }
 
+        if (OmniboxFeatures.sOmniboxMobileParityUpdate.isEnabled()
+                && !TextUtils.isEmpty(templateUrl.getShortName())) {
+            mSearchBoxHintText =
+                    OmniboxResourceProvider.getString(
+                            mContext,
+                            R.string.omnibox_empty_hint_with_dse_name,
+                            templateUrl.getShortName());
+        }
+
         if (mDefaultSearchEngineMetadata == null
                 || !TextUtils.equals(
                         mDefaultSearchEngineMetadata.keyword, templateUrl.getKeyword())) {
@@ -248,7 +268,12 @@
     /*
      * Returns whether the current search provider has Logo.
      */
-    boolean doesDefaultSearchEngineHaveLogo() {
+    public boolean doesDefaultSearchEngineHaveLogo() {
         return mDoesDefaultSearchEngineHaveLogo;
     }
+
+    /** Returns the standardized Omnibox hint text for the current Search Engine. */
+    public String getSearchBoxHintText() {
+        return mSearchBoxHintText;
+    }
 }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtilsUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtilsUnitTest.java
index 944ede0..1090de38 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtilsUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineUtilsUnitTest.java
@@ -16,6 +16,7 @@
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 
+import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 
@@ -33,9 +34,11 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.shadow.api.Shadow;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.UmaRecorderHolder;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.locale.LocaleManagerDelegate;
 import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
@@ -49,6 +52,7 @@
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification;
+import org.chromium.components.omnibox.OmniboxFeatureList;
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.url.GURL;
@@ -70,10 +74,12 @@
     @Mock Resources mResources;
     @Mock Profile mProfile;
 
-    Bitmap mBitmap;
+    private Context mContext;
+    private Bitmap mBitmap;
 
     @Before
     public void setUp() {
+        mContext = ContextUtils.getApplicationContext();
         mBitmap = Shadow.newInstanceOf(Bitmap.class);
         shadowOf(mBitmap).appendDescription("test");
 
@@ -114,6 +120,11 @@
         doReturn(true).when(mProfile).isOffTheRecord();
         searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
         assertFalse(searchEngineUtils.shouldShowSearchEngineLogo());
+
+        // Verify default placeholder text.
+        assertEquals(
+                mContext.getString(R.string.omnibox_empty_hint),
+                searchEngineUtils.getSearchBoxHintText());
     }
 
     @Test
@@ -177,9 +188,10 @@
         assertEquals(expected, icon);
     }
 
-    private void configureSearchEngine(String keyword) {
+    private void configureSearchEngine(String keyword, String shortName) {
         doReturn("google".equals(keyword)).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
         doReturn(keyword).when(mTemplateUrl).getKeyword();
+        doReturn(shortName).when(mTemplateUrl).getShortName();
     }
 
     private void verifyPersistedSearchEngine(String keyword) {
@@ -211,7 +223,7 @@
         {
             // To Google
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("google");
+            configureSearchEngine("google", "Google");
             new SearchEngineUtils(mProfile, mFaviconHelper);
             verifyPersistedSearchEngine("google");
             verifyNoSearchEngineSpecificDataInCache();
@@ -220,7 +232,7 @@
         {
             // To Non-Google
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("engine");
+            configureSearchEngine("engine", "Some Engine");
             new SearchEngineUtils(mProfile, mFaviconHelper);
             verifyPersistedSearchEngine("engine");
             verifyNoSearchEngineSpecificDataInCache();
@@ -231,12 +243,12 @@
     public void onTemplateUrlServiceChanged_newTemplateUrl_withDifferentPreviousEngine() {
         {
             // To Google
-            configureSearchEngine("engine");
+            configureSearchEngine("engine", "Some Engine");
             var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
 
             // Make an update
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("google");
+            configureSearchEngine("google", "Google");
             searchEngineUtils.onTemplateURLServiceChanged();
             verifyPersistedSearchEngine("google");
             verifyNoSearchEngineSpecificDataInCache();
@@ -244,12 +256,12 @@
 
         {
             // To Non-Google
-            configureSearchEngine("google");
+            configureSearchEngine("google", "Google");
             var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
 
             // Make an update
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("engine");
+            configureSearchEngine("engine", "Some Engine");
             searchEngineUtils.onTemplateURLServiceChanged();
             verifyPersistedSearchEngine("engine");
             verifyNoSearchEngineSpecificDataInCache();
@@ -257,31 +269,141 @@
     }
 
     @Test
-    public void onTemplateUrlServiceChanged_newTemplateUrl_withSamePreviousEngine() {
+    @DisableFeatures(OmniboxFeatureList.OMNIBOX_MOBILE_PARITY_UPDATE)
+    public void onTemplateUrlServiceChanged_newTemplateUrl_noHintTextUpdate() {
         {
             // Google to Google
-            configureSearchEngine("google");
+            configureSearchEngine("google", "Google");
             var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
 
             // Make an update
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("google");
+            configureSearchEngine("google", "Google");
             searchEngineUtils.onTemplateURLServiceChanged();
-            verifyPersistedSearchEngine("google");
-            verifySearchEngineSpecificDataRetainedInCache();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
         }
 
         {
             // Non-Google to same non-Google.
-            configureSearchEngine("engine");
+            configureSearchEngine("engine", "Some Engine");
             var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
 
             // Make an update
             saveSearchEngineSpecificDataToCache();
-            configureSearchEngine("engine");
+            configureSearchEngine("engine", "Another Engine");
+            searchEngineUtils.onTemplateURLServiceChanged();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+
+        {
+            // Non-Google, unnamed engine
+            configureSearchEngine("engine", "Some Engine");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update
+            saveSearchEngineSpecificDataToCache();
+            configureSearchEngine("engine", null);
+            searchEngineUtils.onTemplateURLServiceChanged();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+
+        {
+            // Non-Google, unnamed engine
+            configureSearchEngine("engine", "Some Engine");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update to no engine
+            doReturn(null).when(mTemplateUrlService).getDefaultSearchEngineTemplateUrl();
+            searchEngineUtils.onTemplateURLServiceChanged();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+    }
+
+    @Test
+    public void onTemplateUrlServiceChanged_newTemplateUrl_withSamePreviousEngine() {
+        {
+            // Google to Google
+            configureSearchEngine("google", "Google");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update
+            saveSearchEngineSpecificDataToCache();
+            configureSearchEngine("google", "Google");
+            searchEngineUtils.onTemplateURLServiceChanged();
+            verifyPersistedSearchEngine("google");
+            verifySearchEngineSpecificDataRetainedInCache();
+
+            // Verify updated placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint_with_dse_name, "Google"),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+
+        {
+            // Non-Google to same non-Google.
+            configureSearchEngine("engine", "Some Engine");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update
+            saveSearchEngineSpecificDataToCache();
+            configureSearchEngine("engine", "Another Engine");
             searchEngineUtils.onTemplateURLServiceChanged();
             verifyPersistedSearchEngine("engine");
             verifySearchEngineSpecificDataRetainedInCache();
+
+            // Verify updated placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint_with_dse_name, "Another Engine"),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+
+        {
+            // Non-Google, unnamed engine
+            configureSearchEngine("engine", "Some Engine");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update
+            saveSearchEngineSpecificDataToCache();
+            configureSearchEngine("engine", null);
+            searchEngineUtils.onTemplateURLServiceChanged();
+            verifyPersistedSearchEngine("engine");
+            verifySearchEngineSpecificDataRetainedInCache();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
+        }
+
+        {
+            // Non-Google, unnamed engine
+            configureSearchEngine("engine", "Some Engine");
+            var searchEngineUtils = new SearchEngineUtils(mProfile, mFaviconHelper);
+
+            // Make an update to no engine
+            doReturn(null).when(mTemplateUrlService).getDefaultSearchEngineTemplateUrl();
+            searchEngineUtils.onTemplateURLServiceChanged();
+
+            // Verify default placeholder text.
+            assertEquals(
+                    mContext.getString(R.string.omnibox_empty_hint),
+                    searchEngineUtils.getSearchBoxHintText());
         }
     }
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
index d26f09d..e0c45f7 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
@@ -11,7 +11,6 @@
 import android.view.inputmethod.InputMethodManager;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.StringRes;
 
 import org.chromium.base.Callback;
 import org.chromium.build.annotations.NullMarked;
@@ -370,9 +369,9 @@
     }
 
     /**
-     * @see UrlBarMediator#setUrlBarHintText(int)
+     * @see UrlBarMediator#setUrlBarHintText(String)
      */
-    public void setUrlBarHintText(@StringRes int hintTextRes) {
+    public void setUrlBarHintText(String hintTextRes) {
         mMediator.setUrlBarHintText(hintTextRes);
     }
 }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
index b25deb0b..0f296ff 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
@@ -12,7 +12,6 @@
 import android.view.View;
 
 import androidx.annotation.ColorInt;
-import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
@@ -416,8 +415,8 @@
     }
 
     /** Sets the search box hint text. */
-    void setUrlBarHintText(@StringRes int hintTextRes) {
-        mModel.set(UrlBarProperties.HINT_TEXT, hintTextRes);
+    void setUrlBarHintText(String hintText) {
+        mModel.set(UrlBarProperties.HINT_TEXT, hintText);
     }
 
     void setShowOriginOnly(boolean showOriginOnly) {
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
index 6659a43..2032084 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java
@@ -46,11 +46,13 @@
     @Mock Callback<String> mAnotherUrlTextMockListener;
     @Mock Callback<Boolean> mFocusChangeCallback;
 
+    Context mContext;
     PropertyModel mModel;
     UrlBarMediator mMediator;
 
     @Before
     public void setUp() {
+        mContext = ContextUtils.getApplicationContext();
         mModel = new PropertyModel(UrlBarProperties.ALL_KEYS);
         mMediator =
                 new UrlBarMediator(
@@ -323,11 +325,10 @@
 
     @Test
     public void setUrlBarHintText() {
-        mMediator.setUrlBarHintText(R.string.hub_search_empty_hint);
-        Assert.assertEquals(R.string.hub_search_empty_hint, mModel.get(UrlBarProperties.HINT_TEXT));
-        mMediator.setUrlBarHintText(R.string.hub_search_empty_hint_incognito);
-        Assert.assertEquals(
-                R.string.hub_search_empty_hint_incognito, mModel.get(UrlBarProperties.HINT_TEXT));
+        mMediator.setUrlBarHintText("Hint 1");
+        Assert.assertEquals("Hint 1", mModel.get(UrlBarProperties.HINT_TEXT));
+        mMediator.setUrlBarHintText("Incognito Hint");
+        Assert.assertEquals("Incognito Hint", mModel.get(UrlBarProperties.HINT_TEXT));
     }
 
     @Test
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java
index deaddaf..bb72256 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java
@@ -178,8 +178,9 @@
     public static final WritableObjectPropertyKey<View.OnLongClickListener> LONG_CLICK_LISTENER =
             new WritableObjectPropertyKey<>();
 
-    /** Specifies the resource ID for the url bar hint text. */
-    public static final WritableIntPropertyKey HINT_TEXT = new WritableIntPropertyKey();
+    /** Specifies the url bar hint text. */
+    public static final WritableObjectPropertyKey<String> HINT_TEXT =
+            new WritableObjectPropertyKey<>();
 
     public static final PropertyKey[] ALL_KEYS =
             new PropertyKey[] {
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
index feb7595..3cdbed2 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
@@ -136,7 +136,7 @@
         } else if (UrlBarProperties.LONG_CLICK_LISTENER.equals(propertyKey)) {
             view.setOnLongClickListener(model.get(UrlBarProperties.LONG_CLICK_LISTENER));
         } else if (UrlBarProperties.HINT_TEXT.equals(propertyKey)) {
-            view.setHint(view.getContext().getString(model.get(UrlBarProperties.HINT_TEXT)));
+            view.setHint(model.get(UrlBarProperties.HINT_TEXT));
         }
     }
 
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinderUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinderUnitTest.java
index 8a339b9..98976e5 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinderUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinderUnitTest.java
@@ -190,11 +190,10 @@
     @Test
     @SmallTest
     public void testSetHintText() {
-        mModel.set(HINT_TEXT, R.string.hub_search_empty_hint);
-        Assert.assertEquals(mActivity.getString(R.string.hub_search_empty_hint), mUrlBar.getHint());
-        mModel.set(HINT_TEXT, R.string.hub_search_empty_hint_incognito);
-        Assert.assertEquals(
-                mActivity.getString(R.string.hub_search_empty_hint_incognito), mUrlBar.getHint());
+        mModel.set(HINT_TEXT, "Hint Text");
+        Assert.assertEquals("Hint Text", mUrlBar.getHint());
+        mModel.set(HINT_TEXT, "Different Hint Text");
+        Assert.assertEquals("Different Hint Text", mUrlBar.getHint());
     }
 
     @Test
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetView.java
index b7299a85..2b504ac 100644
--- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/account_picker/AccountPickerBottomSheetView.java
@@ -255,11 +255,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         return HeightMode.WRAP_CONTENT;
     }
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn
index 7e3257ffa..61d2aa6 100644
--- a/chrome/browser/ui/android/toolbar/BUILD.gn
+++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -234,7 +234,12 @@
   if (enable_extensions_core) {
     sources += [
       "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java",
+      "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonProperties.java",
+      "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonViewBinder.java",
+      "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java",
+      "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java",
       "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java",
+      "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java",
     ]
   }
 }
@@ -335,6 +340,7 @@
     "java/res/layout/address_bar_preference.xml",
     "java/res/layout/bottom_control_container.xml",
     "java/res/layout/control_container.xml",
+    "java/res/layout/extension_action_button.xml",
     "java/res/layout/extension_toolbar_container.xml",
     "java/res/layout/home_page_buttons_layout.xml",
     "java/res/layout/menu_button.xml",
@@ -484,4 +490,8 @@
     "//url:gurl_java",
     "//url:gurl_junit_test_support",
   ]
+
+  if (enable_extensions_core) {
+    sources += [ "java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java" ]
+  }
 }
diff --git a/chrome/browser/ui/android/toolbar/DEPS b/chrome/browser/ui/android/toolbar/DEPS
index 3e08627..d6daa04 100644
--- a/chrome/browser/ui/android/toolbar/DEPS
+++ b/chrome/browser/ui/android/toolbar/DEPS
@@ -9,4 +9,5 @@
   "+components/omnibox/browser/android",
   "+components/security_state/content/android",
   "+content/public/android",
+  "+extensions/android",
 ]
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/extension_action_button.xml b/chrome/browser/ui/android/toolbar/java/res/layout/extension_action_button.xml
new file mode 100644
index 0000000..1340a58
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/res/layout/extension_action_button.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+
+<org.chromium.ui.listmenu.ListMenuButton
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="UnusedResources"
+    style="@style/ToolbarHoverableButton"
+    app:menuMaxWidth="@dimen/extension_action_button_list_menu_width"
+    app:tint="@color/default_icon_color_tint_list" />
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/extension_toolbar_container.xml b/chrome/browser/ui/android/toolbar/java/res/layout/extension_toolbar_container.xml
index 7a7aea82..04f32ff9 100644
--- a/chrome/browser/ui/android/toolbar/java/res/layout/extension_toolbar_container.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/layout/extension_toolbar_container.xml
@@ -5,8 +5,8 @@
 found in the LICENSE file.
 -->
 
-<!-- TODO(crbug.com/385984462): Replace this with a real implementation. -->
-<FrameLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
-    android:layout_height="match_parent" />
+    android:layout_height="match_parent"
+    android:orientation="horizontal" />
diff --git a/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
index 47e45a5..64aeed5 100644
--- a/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
@@ -5,7 +5,7 @@
 found in the LICENSE file.
 -->
 
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools">
     <dimen name="toolbar_tab_count_text_size_1_digit">11dp</dimen>
     <dimen name="toolbar_tab_count_text_size_2_digit">9dp</dimen>
 
@@ -75,4 +75,8 @@
     <dimen name="optional_toolbar_tablet_button_padding_top">0dp</dimen>
     <dimen name="optional_toolbar_tablet_button_with_error_badge_padding_start">4dp</dimen>
     <dimen name="optional_toolbar_tablet_button_with_error_badge_padding_top">4dp</dimen>
+
+    <!-- Extension Action Button Menu dimensions -->
+    <dimen name="extension_action_button_list_menu_width" tools:ignore="UnusedResources">300dp</dimen>
+
 </resources>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java
index 979727d3..0766e755 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionAction.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.toolbar.extensions;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JniType;
 
@@ -20,8 +22,8 @@
     private final String mTitle;
 
     @CalledByNative
-    private ExtensionAction(
-            @JniType("std::string") String id, @JniType("std::string") String title) {
+    @VisibleForTesting
+    ExtensionAction(@JniType("std::string") String id, @JniType("std::string") String title) {
         mId = id;
         mTitle = title;
     }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonProperties.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonProperties.java
new file mode 100644
index 0000000..423f6ed
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonProperties.java
@@ -0,0 +1,43 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import android.graphics.Bitmap;
+
+import androidx.annotation.IntDef;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** A set of extension action button properties to reflect its state. */
+@NullMarked
+public class ExtensionActionButtonProperties {
+    @IntDef({ListItemType.EXTENSION_ACTION})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ListItemType {
+        int EXTENSION_ACTION = 0;
+    }
+
+    // Keep the entries sorted by name.
+
+    /** The icon of the action. */
+    public static final WritableObjectPropertyKey<Bitmap> ICON = new WritableObjectPropertyKey<>();
+
+    /** The action ID (i.e. extension ID). */
+    public static final WritableObjectPropertyKey<String> ID = new WritableObjectPropertyKey<>();
+
+    /**
+     * The title of the action. It is the name of the extension by default, but an extension can
+     * update it programmatically.
+     */
+    public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
+
+    /** The list of all keys defined here. */
+    public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {ICON, ID, TITLE};
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonViewBinder.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonViewBinder.java
new file mode 100644
index 0000000..1eef2c6
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionButtonViewBinder.java
@@ -0,0 +1,32 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import android.graphics.Bitmap;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.listmenu.ListMenuButton;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Binds changed {@link PropertyKey} in the {@link PropertyModel} to the actual view of the
+ * extension action button.
+ */
+@NullMarked
+public class ExtensionActionButtonViewBinder {
+    public static void bind(PropertyModel model, ListMenuButton button, PropertyKey key) {
+        if (key == ExtensionActionButtonProperties.TITLE) {
+            String title = model.get(ExtensionActionButtonProperties.TITLE);
+            button.setTooltipText(title);
+            button.setContentDescription(title);
+        } else if (key == ExtensionActionButtonProperties.ICON) {
+            Bitmap bitmap = model.get(ExtensionActionButtonProperties.ICON);
+            // TODO: Investigate the correct resizing method.
+            bitmap.setDensity(120);
+            button.setImageBitmap(bitmap);
+        }
+    }
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
new file mode 100644
index 0000000..4f12fd69
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
@@ -0,0 +1,64 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewStub;
+import android.widget.LinearLayout;
+
+import org.chromium.base.lifetime.Destroyable;
+import org.chromium.base.lifetime.LifetimeAssert;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.R;
+import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType;
+import org.chromium.ui.listmenu.ListMenuButton;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.ViewGroupAdapter;
+
+/**
+ * Root component for the extension action buttons. Exposes public API for external consumers to
+ * interact with the buttons and affect their states.
+ */
+@NullMarked
+public class ExtensionActionListCoordinator implements Destroyable {
+    private final ExtensionActionListMediator mMediator;
+    private final ViewGroupAdapter mAdapter;
+    @Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
+
+    public ExtensionActionListCoordinator(
+            Context context,
+            ViewStub containerStub,
+            ObservableSupplier<Profile> profileSupplier,
+            ObservableSupplier<Tab> currentTabSupplier) {
+        LinearLayout container = (LinearLayout) containerStub.inflate();
+        ModelList models = new ModelList();
+        mMediator = new ExtensionActionListMediator(models, profileSupplier, currentTabSupplier);
+        mAdapter =
+                new ViewGroupAdapter.Builder(container, models)
+                        .registerType(
+                                ListItemType.EXTENSION_ACTION,
+                                parent ->
+                                        (ListMenuButton)
+                                                LayoutInflater.from(context)
+                                                        .inflate(
+                                                                R.layout.extension_action_button,
+                                                                parent,
+                                                                /* attachToRoot= */ false),
+                                ExtensionActionButtonViewBinder::bind)
+                        .build();
+    }
+
+    @Override
+    public void destroy() {
+        mAdapter.destroy();
+        mMediator.destroy();
+        LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
+    }
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
new file mode 100644
index 0000000..10d6b87a
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
@@ -0,0 +1,197 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import android.graphics.Bitmap;
+
+import org.chromium.base.Callback;
+import org.chromium.base.lifetime.Destroyable;
+import org.chromium.base.lifetime.LifetimeAssert;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType;
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.ModelListAdapter;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Responsible for mediating external events like extension action changes and reflects all these
+ * changes on the action button model.
+ */
+@NullMarked
+class ExtensionActionListMediator implements Destroyable {
+    private final ModelList mModels;
+    private final ObservableSupplier<Profile> mProfileSupplier;
+    private final ObservableSupplier<Tab> mCurrentTabSupplier;
+    private final Callback<Profile> mProfileUpdatedCallback = this::onProfileUpdated;
+    private final Callback<Tab> mTabChangedCallback = this::onTabChanged;
+    private final ActionsObserver mActionsObserver = new ActionsObserver();
+
+    @Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
+
+    @Nullable private Profile mProfile;
+    @Nullable private ExtensionActionsBridge mExtensionActionsBridge;
+    @Nullable private Tab mCurrentTab;
+
+    public ExtensionActionListMediator(
+            ModelList models,
+            ObservableSupplier<Profile> profileSupplier,
+            ObservableSupplier<Tab> currentTabSupplier) {
+        mModels = models;
+        mProfileSupplier = profileSupplier;
+        mCurrentTabSupplier = currentTabSupplier;
+
+        mProfileSupplier.addObserver(mProfileUpdatedCallback);
+        mCurrentTabSupplier.addObserver(mTabChangedCallback);
+    }
+
+    @Override
+    public void destroy() {
+        if (mExtensionActionsBridge != null) {
+            mExtensionActionsBridge.removeObserver(mActionsObserver);
+        }
+        mCurrentTabSupplier.removeObserver(mTabChangedCallback);
+        mProfileSupplier.removeObserver(mProfileUpdatedCallback);
+
+        mCurrentTab = null;
+        mExtensionActionsBridge = null;
+        mProfile = null;
+
+        LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
+    }
+
+    private void onProfileUpdated(@Nullable Profile profile) {
+        if (profile == mProfile) {
+            return;
+        }
+
+        if (mExtensionActionsBridge != null) {
+            mExtensionActionsBridge.removeObserver(mActionsObserver);
+        }
+        mExtensionActionsBridge = null;
+        mProfile = profile;
+
+        if (mProfile != null) {
+            mExtensionActionsBridge = ExtensionActionsBridge.get(mProfile);
+            if (mExtensionActionsBridge != null) {
+                mExtensionActionsBridge.addObserver(mActionsObserver);
+            }
+        }
+
+        // Force clearing buttons even if the actions for the new profile are not available yet
+        // because switching profiles usually results in a very different set of extension actions.
+        mModels.clear();
+
+        // If the current tab belongs to a different profile, onTabChanged will be called soon, so
+        // do not update actions now to avoid duplicated updates.
+        if (mCurrentTab != null && mCurrentTab.getProfile() != mProfile) {
+            return;
+        }
+
+        maybeUpdateAllActions();
+    }
+
+    private void onTabChanged(Tab tab) {
+        if (tab == mCurrentTab) {
+            return;
+        }
+        if (tab == null) {
+            // The current tab can be null when a non-tab UI is shown (e.g. tab switcher). In this
+            // case, we do not bother refreshing actions as they're hidden anyway. We do not set
+            // mCurrentTab to null because we can skip updating actions if the current tab is set
+            // back to the previous tab.
+            return;
+        }
+
+        mCurrentTab = tab;
+
+        // If the tab belongs to a different profile, onProfileUpdated will be called soon, so
+        // do not update actions now to avoid duplicated updates.
+        if (tab.getProfile() != mProfile) {
+            return;
+        }
+
+        maybeUpdateAllActions();
+    }
+
+    private void maybeUpdateAllActions() {
+        if (mProfile == null || mExtensionActionsBridge == null || mCurrentTab == null) {
+            mModels.clear();
+            return;
+        }
+
+        if (!mExtensionActionsBridge.areActionsInitialized()) {
+            // No need to update the model as ActionsObserver will be called back soon.
+            return;
+        }
+
+        int tabId = mCurrentTab.getId();
+
+        // TODO(crbug.com/385984462): Show pinned actions only. For now, we pretend that all actions
+        // are pinned.
+        String[] actionIds = mExtensionActionsBridge.getActionIds();
+
+        List<ListItem> items = new ArrayList<>(actionIds.length);
+        for (String actionId : actionIds) {
+            ExtensionAction action = mExtensionActionsBridge.getAction(actionId, tabId);
+            assert action != null;
+            Bitmap icon = mExtensionActionsBridge.getActionIcon(actionId, tabId);
+            assert icon != null;
+            items.add(
+                    new ModelListAdapter.ListItem(
+                            ListItemType.EXTENSION_ACTION,
+                            new PropertyModel.Builder(ExtensionActionButtonProperties.ALL_KEYS)
+                                    .with(ExtensionActionButtonProperties.ID, action.getId())
+                                    .with(ExtensionActionButtonProperties.TITLE, action.getTitle())
+                                    .with(ExtensionActionButtonProperties.ICON, icon)
+                                    .build()));
+        }
+        mModels.set(items);
+    }
+
+    private class ActionsObserver implements ExtensionActionsBridge.Observer {
+        @Override
+        public void onActionAdded(String actionId) {
+            // TODO(crbug.com/385984462): Update the added action only.
+            maybeUpdateAllActions();
+        }
+
+        @Override
+        public void onActionRemoved(String actionId) {
+            // TODO(crbug.com/385984462): Update the removed action only.
+            maybeUpdateAllActions();
+        }
+
+        @Override
+        public void onActionUpdated(String actionId) {
+            // TODO(crbug.com/385984462): Update the updated action only.
+            maybeUpdateAllActions();
+        }
+
+        @Override
+        public void onActionModelInitialized() {
+            maybeUpdateAllActions();
+        }
+
+        @Override
+        public void onPinnedActionsChanged() {
+            // TODO(crbug.com/385984462): Update the pinned/unpinned actions only.
+            maybeUpdateAllActions();
+        }
+
+        @Override
+        public void onActionIconUpdated(String actionId) {
+            // TODO(crbug.com/385984462): Update the updated action only.
+            maybeUpdateAllActions();
+        }
+    }
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java
new file mode 100644
index 0000000..416e3d1e
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediatorTest.java
@@ -0,0 +1,279 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Looper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.annotation.LooperMode;
+
+import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.MockTab;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.extensions.ExtensionActionButtonProperties.ListItemType;
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+
+@RunWith(BaseRobolectricTestRunner.class)
+@LooperMode(LooperMode.Mode.PAUSED)
+public class ExtensionActionListMediatorTest {
+    private static final int TAB1_ID = 111;
+    private static final int TAB2_ID = 222;
+    private static final long ACTIONS_BRIDGE_POINTER = 10000L;
+
+    private static final Bitmap ICON_RED = createSimpleIcon(Color.RED);
+    private static final Bitmap ICON_BLUE = createSimpleIcon(Color.BLUE);
+    private static final Bitmap ICON_GREEN = createSimpleIcon(Color.GREEN);
+    private static final Bitmap ICON_CYAN = createSimpleIcon(Color.CYAN);
+    private static final Bitmap ICON_MAGENTA = createSimpleIcon(Color.MAGENTA);
+    private static final Bitmap ICON_YELLOW = createSimpleIcon(Color.YELLOW);
+    private static final Bitmap ICON_WHITE = createSimpleIcon(Color.YELLOW);
+
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock private Profile mProfile;
+    @Mock private ExtensionActionsBridge.Natives mActionsBridgeJniMock;
+
+    private ExtensionActionsBridge mActionsBridge;
+    private MockTab mTab1;
+    private MockTab mTab2;
+    private ObservableSupplierImpl<Profile> mProfileSupplier;
+    private ObservableSupplierImpl<Tab> mCurrentTabSupplier;
+    private ModelList mModels;
+    private ExtensionActionListMediator mMediator;
+
+    @Before
+    public void setUp() {
+        ExtensionActionsBridgeJni.setInstanceForTesting(mActionsBridgeJniMock);
+
+        // Provide good defaults for action queries via JNI.
+        mActionsBridge = new ExtensionActionsBridge(ACTIONS_BRIDGE_POINTER);
+        when(mActionsBridgeJniMock.get(mProfile)).thenReturn(mActionsBridge);
+        when(mActionsBridgeJniMock.areActionsInitialized(ACTIONS_BRIDGE_POINTER)).thenReturn(true);
+        when(mActionsBridgeJniMock.getActionIds(ACTIONS_BRIDGE_POINTER))
+                .thenReturn(new String[] {"a", "b"});
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "a", TAB1_ID))
+                .thenReturn(new ExtensionAction("a", "title of a"));
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "b", TAB1_ID))
+                .thenReturn(new ExtensionAction("b", "title of b"));
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "c", TAB1_ID))
+                .thenReturn(new ExtensionAction("c", "title of c"));
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "a", TAB2_ID))
+                .thenReturn(new ExtensionAction("a", "another title of a"));
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "b", TAB2_ID))
+                .thenReturn(new ExtensionAction("b", "another title of b"));
+        when(mActionsBridgeJniMock.getAction(ACTIONS_BRIDGE_POINTER, "c", TAB2_ID))
+                .thenReturn(new ExtensionAction("c", "another title of c"));
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "a", TAB1_ID))
+                .thenReturn(ICON_RED);
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "b", TAB1_ID))
+                .thenReturn(ICON_GREEN);
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "c", TAB1_ID))
+                .thenReturn(ICON_BLUE);
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "a", TAB2_ID))
+                .thenReturn(ICON_CYAN);
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "b", TAB2_ID))
+                .thenReturn(ICON_MAGENTA);
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "c", TAB2_ID))
+                .thenReturn(ICON_YELLOW);
+
+        // Initialize common objects.
+        mTab1 = new MockTab(TAB1_ID, mProfile);
+        mTab2 = new MockTab(TAB2_ID, mProfile);
+        mProfileSupplier = new ObservableSupplierImpl<>();
+        mCurrentTabSupplier = new ObservableSupplierImpl<>();
+        mModels = new ModelList();
+        mMediator = new ExtensionActionListMediator(mModels, mProfileSupplier, mCurrentTabSupplier);
+
+        // Wait for the main thread to settle.
+        shadowOf(Looper.getMainLooper()).idle();
+    }
+
+    @After
+    public void tearDown() {
+        mMediator.destroy();
+    }
+
+    @Test
+    public void testUpdateModels() {
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+    }
+
+    @Test
+    public void testUpdateModels_noProfile() {
+        // Set the tab only.
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been not updated.
+        assertTrue(mModels.isEmpty());
+        verify(mActionsBridgeJniMock, never()).get(any());
+    }
+
+    @Test
+    public void testUpdateModels_noTab() {
+        // Set the profile only.
+        mProfileSupplier.set(mProfile);
+
+        // The model should have been not updated.
+        assertTrue(mModels.isEmpty());
+        verify(mActionsBridgeJniMock, never()).getActionIds(anyLong());
+    }
+
+    @Test
+    public void testUpdateModels_actionsInitializedLater() {
+        // Actions are initially uninitialized.
+        when(mActionsBridgeJniMock.areActionsInitialized(ACTIONS_BRIDGE_POINTER)).thenReturn(false);
+
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been not updated.
+        assertTrue(mModels.isEmpty());
+        verify(mActionsBridgeJniMock, never()).getActionIds(anyLong());
+
+        // Notify that toolbar model has been initialized.
+        when(mActionsBridgeJniMock.areActionsInitialized(ACTIONS_BRIDGE_POINTER)).thenReturn(true);
+        mActionsBridge.onActionModelInitialized();
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+    }
+
+    @Test
+    public void testUpdateModels_actionsAddedAndRemoved() {
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+
+        // Update the actions.
+        when(mActionsBridgeJniMock.getActionIds(ACTIONS_BRIDGE_POINTER))
+                .thenReturn(new String[] {"b", "c"});
+        mActionsBridge.onActionAdded("c");
+        mActionsBridge.onActionRemoved("a");
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "b", "title of b", ICON_GREEN);
+        assertItemAt(1, "c", "title of c", ICON_BLUE);
+    }
+
+    @Test
+    public void testUpdateModels_tabChanged() {
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+
+        // Simulate changing the tab.
+        mCurrentTabSupplier.set(mTab2);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "another title of a", ICON_CYAN);
+        assertItemAt(1, "b", "another title of b", ICON_MAGENTA);
+    }
+
+    @Test
+    public void testUpdateModels_iconUpdated() {
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+
+        // Simulate changing the icon.
+        when(mActionsBridgeJniMock.getActionIcon(ACTIONS_BRIDGE_POINTER, "a", TAB1_ID))
+                .thenReturn(ICON_WHITE);
+        mActionsBridge.onActionIconUpdated("a");
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_WHITE);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+    }
+
+    @Test
+    public void testUpdateModels_pinnedActionUpdated() {
+        // Set the profile and the tab.
+        mProfileSupplier.set(mProfile);
+        mCurrentTabSupplier.set(mTab1);
+
+        // The model should have been updated.
+        assertEquals(2, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+
+        // Simulate changing the pinned actions.
+        when(mActionsBridgeJniMock.getActionIds(ACTIONS_BRIDGE_POINTER))
+                .thenReturn(new String[] {"a", "b", "c"});
+        mActionsBridge.onActionUpdated("a");
+
+        // The model should have been updated.
+        assertEquals(3, mModels.size());
+        assertItemAt(0, "a", "title of a", ICON_RED);
+        assertItemAt(1, "b", "title of b", ICON_GREEN);
+        assertItemAt(2, "c", "title of c", ICON_BLUE);
+    }
+
+    private static Bitmap createSimpleIcon(int color) {
+        Bitmap bitmap = Bitmap.createBitmap(12, 12, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        Paint paint = new Paint();
+        paint.setColor(color);
+        canvas.drawRect(0, 0, 12, 12, paint);
+        return bitmap;
+    }
+
+    private void assertItemAt(int index, String id, String title, Bitmap icon) {
+        ListItem item = mModels.get(index);
+        assertEquals(ListItemType.EXTENSION_ACTION, item.type);
+        assertEquals(id, item.model.get(ExtensionActionButtonProperties.ID));
+        assertEquals(title, item.model.get(ExtensionActionButtonProperties.TITLE));
+        assertTrue(icon.sameAs(item.model.get(ExtensionActionButtonProperties.ICON)));
+    }
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
index 09227f67..4e8d271 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
@@ -6,6 +6,8 @@
 
 import android.graphics.Bitmap;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JniType;
 import org.jni_zero.NativeMethods;
@@ -22,7 +24,8 @@
     private final ObserverList<Observer> mObservers = new ObserverList<>();
 
     @CalledByNative
-    private ExtensionActionsBridge(long nativeExtensionActionsBridge) {
+    @VisibleForTesting
+    ExtensionActionsBridge(long nativeExtensionActionsBridge) {
         mNativeExtensionActionsBridge = nativeExtensionActionsBridge;
     }
 
@@ -78,42 +81,48 @@
     }
 
     @CalledByNative
-    private void onActionAdded(@JniType("std::string") String actionId) {
+    @VisibleForTesting
+    void onActionAdded(@JniType("std::string") String actionId) {
         for (Observer observer : mObservers) {
             observer.onActionAdded(actionId);
         }
     }
 
     @CalledByNative
-    private void onActionRemoved(@JniType("std::string") String actionId) {
+    @VisibleForTesting
+    void onActionRemoved(@JniType("std::string") String actionId) {
         for (Observer observer : mObservers) {
             observer.onActionRemoved(actionId);
         }
     }
 
     @CalledByNative
-    private void onActionUpdated(@JniType("std::string") String actionId) {
+    @VisibleForTesting
+    void onActionUpdated(@JniType("std::string") String actionId) {
         for (Observer observer : mObservers) {
             observer.onActionUpdated(actionId);
         }
     }
 
     @CalledByNative
-    private void onActionModelInitialized() {
+    @VisibleForTesting
+    void onActionModelInitialized() {
         for (Observer observer : mObservers) {
             observer.onActionModelInitialized();
         }
     }
 
     @CalledByNative
-    private void onPinnedActionsChanged() {
+    @VisibleForTesting
+    void onPinnedActionsChanged() {
         for (Observer observer : mObservers) {
             observer.onPinnedActionsChanged();
         }
     }
 
     @CalledByNative
-    private void onActionIconUpdated(@JniType("std::string") String actionId) {
+    @VisibleForTesting
+    void onActionIconUpdated(@JniType("std::string") String actionId) {
         for (Observer observer : mObservers) {
             observer.onActionIconUpdated(actionId);
         }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
new file mode 100644
index 0000000..1c2e4782
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
@@ -0,0 +1,50 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.extensions;
+
+import android.content.Context;
+import android.view.ViewStub;
+
+import org.chromium.base.lifetime.LifetimeAssert;
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.build.annotations.ServiceImpl;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.Tab;
+
+/**
+ * Implements extension-related buttons for {@link ToolbarManager}.
+ *
+ * <p>This class is compiled only when extensions are enabled.
+ */
+@NullMarked
+@ServiceImpl(ExtensionToolbarManager.class)
+public class ExtensionToolbarManagerImpl implements ExtensionToolbarManager {
+    @Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
+    @Nullable private ExtensionActionListCoordinator mExtensionActionListCoordinator;
+
+    public ExtensionToolbarManagerImpl() {}
+
+    @Override
+    public void initialize(
+            Context context,
+            ViewStub extensionToolbarStub,
+            ObservableSupplier<Profile> profileSupplier,
+            ObservableSupplier<Tab> currentTabSupplier) {
+        mExtensionActionListCoordinator =
+                new ExtensionActionListCoordinator(
+                        context, extensionToolbarStub, profileSupplier, currentTabSupplier);
+    }
+
+    @Override
+    public void destroy() {
+        if (mExtensionActionListCoordinator != null) {
+            mExtensionActionListCoordinator.destroy();
+            mExtensionActionListCoordinator = null;
+        }
+        LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
+    }
+}
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java
index 1b5eafd..43e4272 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java
@@ -238,11 +238,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getFullHeightRatio() {
         if (mRpMode == RpMode.PASSIVE && !mIsMultipleIdps) {
             computeAndUpdateAccountListHeightForPassiveSingleIdp();
diff --git a/chrome/browser/ui/android/whats_new/java/src/org/chromium/chrome/browser/ui/android/whats_new/WhatsNewBottomSheetContent.java b/chrome/browser/ui/android/whats_new/java/src/org/chromium/chrome/browser/ui/android/whats_new/WhatsNewBottomSheetContent.java
index ae0ae14d..742a08e 100644
--- a/chrome/browser/ui/android/whats_new/java/src/org/chromium/chrome/browser/ui/android/whats_new/WhatsNewBottomSheetContent.java
+++ b/chrome/browser/ui/android/whats_new/java/src/org/chromium/chrome/browser/ui/android/whats_new/WhatsNewBottomSheetContent.java
@@ -100,11 +100,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return BottomSheetContent.HeightMode.DISABLED;
     }
diff --git a/chrome/browser/ui/tabs/tab_collection_unittest.cc b/chrome/browser/ui/tabs/tab_collection_unittest.cc
index 0221a0b9..9b74a1a4 100644
--- a/chrome/browser/ui/tabs/tab_collection_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_collection_unittest.cc
@@ -811,7 +811,9 @@
   // Remove split from pinned container
   // 0p 3p 4u 5u 6ug 7ug 8u
   std::unique_ptr<tabs::SplitTabCollection> removed_split_collection =
-      tab_strip_collection->RemoveSplit(split);
+      base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
+          tab_strip_collection->RemoveSplit(split).release()));
+
   EXPECT_EQ(2ul, pinned_collection->TabCountRecursive());
   EXPECT_FALSE(
       tab_strip_collection->GetSplitTabCollection(split->GetSplitTabId()));
@@ -827,7 +829,10 @@
   // Remove split and insert into unpinned container
   // 0p 3p 4u 1s 2s 5u 6ug 7ug 8u
 
-  removed_split_collection = tab_strip_collection->RemoveSplit(split);
+  removed_split_collection =
+      base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
+          tab_strip_collection->RemoveSplit(split).release()));
+
   tab_strip_collection->InsertSplitTabAt(std::move(removed_split_collection), 3,
                                          false, std::nullopt);
   EXPECT_EQ(7ul, unpinned_collection->TabCountRecursive());
@@ -836,7 +841,10 @@
 
   // Remove split and insert into group container
   // 0p 3p 4u 5u 6ug 1gs 2gs 7ug 8u
-  removed_split_collection = tab_strip_collection->RemoveSplit(split);
+  removed_split_collection =
+      base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
+          tab_strip_collection->RemoveSplit(split).release()));
+
   tab_strip_collection->InsertSplitTabAt(std::move(removed_split_collection), 5,
                                          false,
                                          group_collection->GetTabGroupId());
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.cc b/chrome/browser/ui/tabs/tab_strip_collection.cc
index a31ecab..6c24799b 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.cc
+++ b/chrome/browser/ui/tabs/tab_strip_collection.cc
@@ -242,12 +242,11 @@
   return unpinned_collection_->AddCollection(std::move(group), dst_index);
 }
 
-std::unique_ptr<TabGroupTabCollection> TabStripCollection::RemoveGroup(
+std::unique_ptr<TabCollection> TabStripCollection::RemoveGroup(
     TabGroupTabCollection* group) {
   CHECK(group_mapping_.contains(group->GetTabGroupId()));
   RemoveCollectionMapping(group);
-  return base::WrapUnique(static_cast<TabGroupTabCollection*>(
-      unpinned_collection_->MaybeRemoveCollection(group).release()));
+  return unpinned_collection_->MaybeRemoveCollection(group);
 }
 
 TabGroupTabCollection* TabStripCollection::GetTabGroupCollection(
@@ -404,13 +403,12 @@
   tab_collection_ptr->AddCollection(std::move(split_collection), insert_index);
 }
 
-std::unique_ptr<SplitTabCollection> TabStripCollection::RemoveSplit(
+std::unique_ptr<TabCollection> TabStripCollection::RemoveSplit(
     SplitTabCollection* split) {
   CHECK(split_mapping_.contains(split->GetSplitTabId()));
   RemoveCollectionMapping(split);
 
-  return base::WrapUnique(static_cast<SplitTabCollection*>(
-      split->GetParentCollection()->MaybeRemoveCollection(split).release()));
+  return split->GetParentCollection()->MaybeRemoveCollection(split);
 }
 
 void TabStripCollection::ValidateData() const {
@@ -460,7 +458,9 @@
 void TabStripCollection::MaybeRemoveGroupCollection(
     TabGroupTabCollection* group_collection) {
   if (group_collection && group_collection->TabCountRecursive() == 0) {
-    detached_group_collections_.push_back(RemoveGroup(group_collection));
+    detached_group_collections_.push_back(
+        base::WrapUnique(static_cast<TabGroupTabCollection*>(
+            RemoveGroup(group_collection).release())));
   }
 }
 
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.h b/chrome/browser/ui/tabs/tab_strip_collection.h
index 2a1c21c3..dd94a13c 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.h
+++ b/chrome/browser/ui/tabs/tab_strip_collection.h
@@ -86,8 +86,7 @@
   TabGroupTabCollection* AddTabGroup(
       std::unique_ptr<TabGroupTabCollection> group,
       int index);
-  std::unique_ptr<TabGroupTabCollection> RemoveGroup(
-      TabGroupTabCollection* group);
+  std::unique_ptr<TabCollection> RemoveGroup(TabGroupTabCollection* group);
   TabGroupTabCollection* GetTabGroupCollection(tab_groups::TabGroupId group_id);
 
   void MoveTabGroupTo(const tab_groups::TabGroupId& group, int to_index);
@@ -111,8 +110,7 @@
                         int index,
                         int pinned,
                         std::optional<tab_groups::TabGroupId> group);
-  std::unique_ptr<SplitTabCollection> RemoveSplit(SplitTabCollection* split);
-
+  std::unique_ptr<TabCollection> RemoveSplit(SplitTabCollection* split);
   void ValidateData() const;
 
  private:
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 255b98b0..4bb02f2 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -176,8 +176,11 @@
 DetachedTabCollection::DetachedTabCollection(
     std::variant<std::unique_ptr<tabs::TabGroupTabCollection>,
                  std::unique_ptr<tabs::SplitTabCollection>> collection,
-    std::optional<int> active_index)
-    : collection_(std::move(collection)), active_index_(active_index) {}
+    std::optional<int> active_index,
+    bool pinned)
+    : collection_(std::move(collection)),
+      active_index_(active_index),
+      pinned_(pinned) {}
 
 DetachedTabCollection::~DetachedTabCollection() = default;
 DetachedTabCollection::DetachedTabCollection(DetachedTabCollection&&) = default;
@@ -414,7 +417,117 @@
   CHECK(group_model_);
   CHECK(group_model_->ContainsTabGroup(group_id));
 
-  return DetachTabGroupImpl(group_id);
+  std::map<split_tabs::SplitTabId,
+           std::vector<std::pair<tabs::TabInterface*, int>>>
+      splits_in_group;
+
+  std::optional<int> active_index_in_collection = std::nullopt;
+  int index = 0;
+  for (tabs::TabInterface* tab :
+       *contents_data_->GetTabGroupCollection(group_id)) {
+    if (tab->IsActivated()) {
+      active_index_in_collection = index;
+    }
+    if (tab->IsSplit()) {
+      split_tabs::SplitTabId split_id = tab->GetSplit().value();
+      if (!splits_in_group.contains(split_id)) {
+        splits_in_group[split_id] = GetTabsAndIndicesInSplit(split_id);
+      }
+    }
+    index++;
+  }
+
+  std::unique_ptr<tabs::TabCollection> detached_collection =
+      DetachTabCollectionImpl(
+          contents_data_->GetTabGroupCollection(group_id),
+          base::BindOnce(&tabs::TabStripCollection::RemoveGroup,
+                         base::Unretained(contents_data_.get()),
+                         contents_data_->GetTabGroupCollection(group_id)),
+          base::BindOnce(&TabStripModel::NotifyTabGroupDetached,
+                         base::Unretained(this),
+                         contents_data_->GetTabGroupCollection(group_id),
+                         splits_in_group));
+
+  return std::make_unique<DetachedTabCollection>(
+      base::WrapUnique(static_cast<tabs::TabGroupTabCollection*>(
+          detached_collection.release())),
+      active_index_in_collection, false);
+}
+
+std::unique_ptr<DetachedTabCollection>
+TabStripModel::DetachSplitTabForInsertion(
+    const split_tabs::SplitTabId split_id) {
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
+  CHECK(base::FeatureList::IsEnabled(features::kSideBySide));
+  CHECK(GetSplitData(split_id));
+
+  std::vector<std::pair<tabs::TabInterface*, int>> tabs_in_split =
+      GetTabsAndIndicesInSplit(split_id);
+  const bool previous_pinned_state = tabs_in_split[0].first->IsPinned();
+  const std::optional<tab_groups::TabGroupId> previous_group_state =
+      tabs_in_split[0].first->GetGroup();
+
+  std::optional<int> active_index_in_collection = std::nullopt;
+  int index = 0;
+  for (tabs::TabInterface* tab :
+       *contents_data_->GetSplitTabCollection(split_id)) {
+    if (tab->IsActivated()) {
+      active_index_in_collection = index;
+      break;
+    }
+    index++;
+  }
+
+  std::unique_ptr<tabs::TabCollection> detached_collection =
+      DetachTabCollectionImpl(
+          contents_data_->GetSplitTabCollection(split_id),
+          base::BindOnce(&tabs::TabStripCollection::RemoveSplit,
+                         base::Unretained(contents_data_.get()),
+                         contents_data_->GetSplitTabCollection(split_id)),
+          base::BindOnce(&TabStripModel::NotifySplitTabDetached,
+                         base::Unretained(this),
+                         contents_data_->GetSplitTabCollection(split_id),
+                         tabs_in_split, previous_group_state));
+
+  return std::make_unique<DetachedTabCollection>(
+      base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
+          detached_collection.release())),
+      active_index_in_collection, previous_pinned_state);
+}
+
+gfx::Range TabStripModel::InsertDetachedSplitTabAt(
+    std::unique_ptr<DetachedTabCollection> split,
+    int index,
+    bool pinned,
+    std::optional<tab_groups::TabGroupId> group_id) {
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
+  CHECK(std::holds_alternative<std::unique_ptr<tabs::SplitTabCollection>>(
+      split->collection_));
+
+  std::unique_ptr<tabs::SplitTabCollection> split_collection_unique_ptr =
+      std::move(std::get<std::unique_ptr<tabs::SplitTabCollection>>(
+          split->collection_));
+
+  tabs::SplitTabCollection* split_collection =
+      split_collection_unique_ptr.get();
+
+  // Check a split with the same id is not present in the `contents_data_`.
+  CHECK(!contents_data_->GetSplitTabCollection(
+      split_collection->GetSplitTabId()));
+
+  // Notify tab is added to model.
+  for (tabs::TabInterface* tab : *split_collection) {
+    static_cast<tabs::TabModel*>(tab)->OnAddedToModel(this);
+  }
+
+  return InsertDetachedCollectionImpl(
+      split_collection, split->active_index_,
+      base::BindOnce(&tabs::TabStripCollection::InsertSplitTabAt,
+                     base::Unretained(contents_data_.get()),
+                     std::move(split_collection_unique_ptr), index, pinned,
+                     group_id),
+      base::BindOnce(&TabStripModel::NotifySplitTabAttached,
+                     base::Unretained(this), split_collection));
 }
 
 gfx::Range TabStripModel::InsertDetachedTabGroupAt(
@@ -425,9 +538,12 @@
   CHECK(std::holds_alternative<std::unique_ptr<tabs::TabGroupTabCollection>>(
       group->collection_));
 
+  std::unique_ptr<tabs::TabGroupTabCollection> group_collection_unique_ptr =
+      std::move(std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(
+          group->collection_));
+
   tabs::TabGroupTabCollection* group_collection =
-      std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(group->collection_)
-          .get();
+      group_collection_unique_ptr.get();
 
   CHECK(!group_model_->ContainsTabGroup(group_collection->GetTabGroupId()));
 
@@ -436,7 +552,13 @@
     static_cast<tabs::TabModel*>(tab)->OnAddedToModel(this);
   }
 
-  return InsertDetachedTabGroupImpl(std::move(group), index);
+  return InsertDetachedCollectionImpl(
+      group_collection, group->active_index_,
+      base::BindOnce(&TabStripModel::InsertDetachedTabGroupImpl,
+                     base::Unretained(this),
+                     std::move(group_collection_unique_ptr), index),
+      base::BindOnce(&TabStripModel::NotifyTabGroupAttached,
+                     base::Unretained(this), group_collection));
 }
 
 tabs::TabModel* TabStripModel::GetTabModelAtIndex(int index) const {
@@ -452,52 +574,19 @@
   }
 }
 
-std::unique_ptr<DetachedTabCollection> TabStripModel::DetachTabGroupImpl(
-    const tab_groups::TabGroupId& group_id) {
-  // Prepare for group to be removed.
-  const gfx::Range tabs_in_group =
-      group_model_->GetTabGroup(group_id)->ListTabs();
-
-  tabs::TabModel* active_tab_model = GetTabModelAtIndex(active_index());
-  const ui::ListSelectionModel old_selection_model = selection_model();
-
-  bool selected_tabs_removed = false;
-  bool active_tab_removed = false;
-
-  const bool closing_all_tabs =
-      static_cast<int>(tabs_in_group.length()) == GetTabCount();
+TabStripModelChange::Remove TabStripModel::ProcessTabsForDetach(
+    gfx::Range tab_indices) {
   TabStripModelChange::Remove remove;
-
-  // Calculate the next selected index before fixing openers.
-  std::optional<int> next_selected_index = DetermineNewSelectedIndex(
-      contents_data_->GetTabGroupCollection(group_id));
-
-  std::map<split_tabs::SplitTabId,
-           std::vector<std::pair<tabs::TabInterface*, int>>>
-      splits_in_group;
-
-  for (int index = static_cast<int>(tabs_in_group.end()) - 1;
-       index >= static_cast<int>(tabs_in_group.start()); --index) {
+  tabs::TabModel* active_tab_model = GetTabModelAtIndex(active_index());
+  for (int index = tab_indices.end() - 1;
+       index >= static_cast<int>(tab_indices.start()); index--) {
     tabs::TabModel* tab = GetTabModelAtIndex(index);
 
     // If the tab is active, notify it that it's going to the background:
     if (tab == active_tab_model) {
-      active_tab_removed = true;
       active_tab_model->WillEnterBackground(base::PassKey<TabStripModel>());
     }
 
-    if (tab->IsSplit()) {
-      split_tabs::SplitTabId split_id = tab->GetSplit().value();
-      if (!splits_in_group.contains(split_id)) {
-        splits_in_group[split_id] = GetTabsAndIndicesInSplit(split_id);
-      }
-    }
-
-    // Track whether any of these tabs are selected.
-    if (IsTabSelected(index)) {
-      selected_tabs_removed = true;
-    }
-
     // Tell the tab it’s being detached (inserted into another window).
     tab->WillDetach(base::PassKey<TabStripModel>(),
                     tabs::TabInterface::DetachReason::kInsertIntoOtherWindow);
@@ -517,20 +606,21 @@
         tabs::TabInterface::DetachReason::kInsertIntoOtherWindow, std::nullopt);
   }
 
-  // Remove the group collection before selection model update.
-  // This is because the selection model update includes looking into
-  // `contents_data_` for split tabs.
-  std::unique_ptr<tabs::TabGroupTabCollection> group_collection =
-      contents_data_->RemoveGroup(
-          contents_data_->GetTabGroupCollection(group_id));
+  return remove;
+}
 
-  // Selection model update should be done as a bulk operation.
-  if (closing_all_tabs) {
+void TabStripModel::UpdateSelectionModelForDetach(
+    gfx::Range tab_indices,
+    std::optional<int> next_selected_index) {
+  const bool closed_all_tabs = (GetTabCount() == 0);
+  bool active_tab_removed = tab_indices.Contains(gfx::Range(active_index()));
+
+  if (closed_all_tabs) {
     selection_model_.Clear();
   } else {
     // Remove all the selected tabs from the model.
-    for (int index = static_cast<int>(tabs_in_group.end()) - 1;
-         index >= static_cast<int>(tabs_in_group.start()); --index) {
+    for (int index = static_cast<int>(tab_indices.end()) - 1;
+         index >= static_cast<int>(tab_indices.start()); --index) {
       selection_model_.DecrementFrom(index);
     }
 
@@ -544,25 +634,51 @@
       }
     }
   }
+}
 
-  // Send group detach notification.
-  NotifyTabGroupDetached(group_collection.get());
-  group_model_->RemoveTabGroup(group_id, base::PassKey<TabStripModel>());
+std::unique_ptr<tabs::TabCollection> TabStripModel::DetachTabCollectionImpl(
+    tabs::TabCollection* collection,
+    base::OnceCallback<std::unique_ptr<tabs::TabCollection>()>
+        execute_detach_collection_operation,
+    base::OnceClosure execute_tabs_notify_observer_operation) {
+  //  Get Tabs and Indices in collection
+  std::vector<int> tabs_in_collection;
 
-  // Send possible split detach notification.
-  for (auto const& [split_id, tabs_with_indices] : splits_in_group) {
-    NotifySplitTabRemoved(
-        split_id, tabs_with_indices,
-        SplitTabChange::SplitTabRemoveReason::kDetachedToAnotherTabstrip);
-  }
+  const int collection_start_index =
+      GetIndexOfTab(collection->GetTabAtIndexRecursive(0));
+  gfx::Range tab_indices =
+      gfx::Range(collection_start_index,
+                 collection_start_index + collection->TabCountRecursive());
+  std::optional<int> next_selected_index =
+      DetermineNewSelectedIndex(collection);
+
+  tabs::TabModel* active_tab_model = GetTabModelAtIndex(active_index());
+  const ui::ListSelectionModel old_selection_model = selection_model();
+  bool selected_tabs_removed = std::any_of(
+      selection_model_.selected_indices().begin(),
+      selection_model_.selected_indices().end(),
+      [&](int sel) { return tab_indices.Contains(gfx::Range(sel)); });
+
+  // Pass the indices vector from above.
+  TabStripModelChange::Remove remove = ProcessTabsForDetach(tab_indices);
+
+  // Call the callback for detaching collection.
+  std::unique_ptr<tabs::TabCollection> detached_collection =
+      std::move(execute_detach_collection_operation).Run();
+
+  // Pass the indices vector from above.
+  UpdateSelectionModelForDetach(tab_indices, next_selected_index);
+
+  // Call the callback for collection detached.
+  std::move(execute_tabs_notify_observer_operation).Run();
 
   // Notify tab is removed from model
-  for (tabs::TabInterface* tab : *group_collection) {
+  for (tabs::TabInterface* tab : *collection) {
     static_cast<tabs::TabModel*>(tab)->OnRemovedFromModel();
   }
 
-  // Send remove notifications for tabs. There is no need to send group
-  // notifications again since tabs are part of the same group.
+  // TODO(crbug.com/418764233): Integrate with
+  // SendDetachWebContentsNotifications
   TabStripModelChange change(std::move(remove));
   TabStripSelectionChange selection(active_tab_model, old_selection_model);
   selection.new_tab = GetActiveTab();
@@ -579,98 +695,76 @@
     }
   }
 
-  std::optional<int> active_index_in_group =
-      active_tab_removed
-          ? group_collection->GetIndexOfTabRecursive(active_tab_model)
-          : std::nullopt;
-  return std::make_unique<DetachedTabCollection>(std::move(group_collection),
-                                                 active_index_in_group);
+  return detached_collection;
 }
 
-gfx::Range TabStripModel::InsertDetachedTabGroupImpl(
-    std::unique_ptr<DetachedTabCollection> detached_group,
-    int index) {
-  CHECK(std::holds_alternative<std::unique_ptr<tabs::TabGroupTabCollection>>(
-      detached_group->collection_));
-
-  std::unique_ptr<tabs::TabGroupTabCollection> group_collection =
-      std::move(std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(
-          detached_group->collection_));
-  CHECK(group_collection);
-
-  tabs::TabGroupTabCollection* group_collection_ptr = group_collection.get();
-
-  const tab_groups::TabGroupId& group_id =
-      group_collection_ptr->GetTabGroupId();
-  for (const tabs::TabInterface* tab : *group_collection_ptr) {
+gfx::Range TabStripModel::InsertDetachedCollectionImpl(
+    tabs::TabCollection* collection,
+    std::optional<int> active_index,
+    base::OnceClosure execute_insert_detached_tabs_operation,
+    base::OnceClosure execute_tabs_notify_observer_operation) {
+  for (const tabs::TabInterface* tab : *collection) {
     delegate()->WillAddWebContents(tab->GetContents());
   }
 
-  index = ConstrainInsertionIndex(index, false);
   tabs::TabInterface* old_active_tab = GetActiveTab();
   const bool tab_strip_empty_initially = empty();
 
-  // Add the group collection.
-  group_model_->AddTabGroup(std::move(group_collection_ptr->GetTabGroup()),
-                            base::PassKey<TabStripModel>());
-  contents_data_->InsertTabGroupAt(std::move(group_collection), index);
+  // Add the collection.
+  std::move(execute_insert_detached_tabs_operation).Run();
 
-  for (int i = index;
-       i < index + static_cast<int>(group_collection_ptr->TabCountRecursive());
+  int collection_insertion_index =
+      GetIndexOfTab(collection->GetTabAtIndexRecursive(0));
+  // Update selection model.
+  for (int i = collection_insertion_index;
+       i < collection_insertion_index +
+               static_cast<int>(collection->TabCountRecursive());
        i++) {
-    selection_model_.IncrementFrom(index);
+    selection_model_.IncrementFrom(collection_insertion_index);
   }
 
-  if (detached_group->active_index_.has_value()) {
+  TabStripSelectionChange selection(old_active_tab, selection_model());
+  if (active_index.has_value()) {
     SetSelectedIndex(&selection_model_,
-                     index + detached_group->active_index_.value());
+                     collection_insertion_index + active_index.value());
   } else if (tab_strip_empty_initially) {
-    SetSelectedIndex(&selection_model_, index);
+    SetSelectedIndex(&selection_model_, collection_insertion_index);
   }
 
   ValidateTabStripModel();
 
-  std::set<split_tabs::SplitTabId> splits_in_group;
-  for (tabs::TabInterface* tab : *group_collection_ptr) {
+  for (tabs::TabInterface* tab : *collection) {
     static_cast<tabs::TabModel*>(tab)->DidInsert(
         base::PassKey<TabStripModel>());
-
-    if (tab->IsSplit()) {
-      splits_in_group.insert(tab->GetSplit().value());
-    }
   }
 
   // Send add notifications for tabs.
-  TabStripSelectionChange selection(old_active_tab, selection_model());
   selection.new_model = selection_model();
   selection.new_tab = GetActiveTab();
   selection.new_contents = GetActiveWebContents();
   TabStripModelChange::Insert insert;
 
-  const gfx::Range tabs_in_group =
-      group_model_->GetTabGroup(group_id)->ListTabs();
-
-  for (int i = static_cast<int>(tabs_in_group.start());
-       i < static_cast<int>(tabs_in_group.end()); i++) {
-    insert.contents.push_back(
-        {GetTabAtIndex(i), GetTabAtIndex(i)->GetContents(), i});
+  for (tabs::TabInterface* tab : *collection) {
+    int index_of_tab = GetIndexOfTab(tab);
+    insert.contents.push_back({tab, tab->GetContents(), index_of_tab});
   }
-
   TabStripModelChange change(std::move(insert));
   OnChange(change, selection);
 
-  // Send group attach notification.
-  NotifyTabGroupAttached(group_collection_ptr);
+  // observer callback
+  std::move(execute_tabs_notify_observer_operation).Run();
 
-  // Send split attach notification
-  for (const split_tabs::SplitTabId& split_id : splits_in_group) {
-    NotifySplitTabCreated(
-        split_id, GetTabsAndIndicesInSplit(split_id),
-        SplitTabChange::SplitTabAddReason::kInsertedFromAnotherTabstrip,
-        *GetSplitData(split_id)->visual_data());
-  }
+  return gfx::Range(
+      collection_insertion_index,
+      collection_insertion_index + collection->TabCountRecursive());
+}
 
-  return tabs_in_group;
+void TabStripModel::InsertDetachedTabGroupImpl(
+    std::unique_ptr<tabs::TabGroupTabCollection> group_collection,
+    int index) {
+  group_model_->AddTabGroup(group_collection->GetTabGroup(),
+                            base::PassKey<TabStripModel>());
+  contents_data_->InsertTabGroupAt(std::move(group_collection), index);
 }
 
 std::unique_ptr<DetachedTab> TabStripModel::DetachTabImpl(
@@ -1896,7 +1990,10 @@
 }
 
 void TabStripModel::NotifyTabGroupDetached(
-    tabs::TabGroupTabCollection* group_collection) {
+    tabs::TabGroupTabCollection* group_collection,
+    std::map<split_tabs::SplitTabId,
+             std::vector<std::pair<tabs::TabInterface*, int>>>
+        splits_in_group) {
   TabGroupChange change(
       this, group_collection->GetTabGroupId(),
       TabGroupChange::CloseChange(
@@ -1905,6 +2002,15 @@
   for (auto& observer : observers_) {
     observer.OnTabGroupChanged(change);
   }
+
+  group_model_->RemoveTabGroup(group_collection->GetTabGroupId(),
+                               base::PassKey<TabStripModel>());
+
+  for (auto const& [split_id, tabs_with_indices] : splits_in_group) {
+    NotifySplitTabRemoved(
+        split_id, tabs_with_indices,
+        SplitTabChange::SplitTabRemoveReason::kDetachedToAnotherTabstrip);
+  }
 }
 
 void TabStripModel::NotifyTabGroupAttached(
@@ -1917,6 +2023,20 @@
   for (auto& observer : observers_) {
     observer.OnTabGroupChanged(change);
   }
+
+  std::set<split_tabs::SplitTabId> splits_in_group;
+  for (tabs::TabInterface* tab : *group_collection) {
+    if (tab->IsSplit()) {
+      splits_in_group.insert(tab->GetSplit().value());
+    }
+  }
+
+  for (const split_tabs::SplitTabId& split_id : splits_in_group) {
+    NotifySplitTabCreated(
+        split_id, GetTabsAndIndicesInSplit(split_id),
+        SplitTabChange::SplitTabAddReason::kInsertedFromAnotherTabstrip,
+        *GetSplitData(split_id)->visual_data());
+  }
 }
 
 void TabStripModel::NotifySplitTabCreated(
@@ -1970,6 +2090,44 @@
   }
 }
 
+void TabStripModel::NotifySplitTabDetached(
+    tabs::SplitTabCollection* split_collection,
+    std::vector<std::pair<tabs::TabInterface*, int>> tabs_in_split,
+    std::optional<tab_groups::TabGroupId> previous_group_state) {
+  // Send possible group notification of removal of grouped tabs.
+  if (group_model_ && previous_group_state) {
+    for (auto [tab, index] : tabs_in_split) {
+      TabGroupStateChanged(index, tab, previous_group_state, std::nullopt);
+    }
+  }
+
+  // Send split tab notification of removal.
+  NotifySplitTabRemoved(
+      split_collection->GetSplitTabId(), tabs_in_split,
+      SplitTabChange::SplitTabRemoveReason::kDetachedToAnotherTabstrip);
+}
+
+void TabStripModel::NotifySplitTabAttached(
+    tabs::SplitTabCollection* split_collection) {
+  std::optional<tab_groups::TabGroupId> group_id =
+      split_collection->GetTabAtIndexRecursive(0)->GetGroup();
+  const split_tabs::SplitTabId& split_id = split_collection->GetSplitTabId();
+  std::vector<std::pair<tabs::TabInterface*, int>> tabs_in_split =
+      GetTabsAndIndicesInSplit(split_id);
+
+  if (group_model_ && group_id.has_value()) {
+    for (auto [tab, i] : tabs_in_split) {
+      TabGroupStateChanged(i, tab, std::nullopt, group_id);
+    }
+  }
+
+  // Send split attach notification
+  NotifySplitTabCreated(
+      split_id, tabs_in_split,
+      SplitTabChange::SplitTabAddReason::kInsertedFromAnotherTabstrip,
+      *GetSplitData(split_id)->visual_data());
+}
+
 std::u16string TabStripModel::GetTitleAt(int index) const {
   return TabUIHelper::FromWebContents(GetWebContentsAt(index))->GetTitle();
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 51d03e5b..e192270 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -79,7 +79,8 @@
   DetachedTabCollection(
       std::variant<std::unique_ptr<tabs::TabGroupTabCollection>,
                    std::unique_ptr<tabs::SplitTabCollection>> collection,
-      std::optional<int> active_index);
+      std::optional<int> active_index,
+      bool pinned_);
   DetachedTabCollection(const DetachedTabCollection&) = delete;
   DetachedTabCollection& operator=(const DetachedTabCollection&) = delete;
   ~DetachedTabCollection();
@@ -89,6 +90,7 @@
       collection_;
   // Store the index of tab that was active in the detached group.
   std::optional<int> active_index_ = std::nullopt;
+  bool pinned_ = false;
 };
 
 // Holds state for a tab that has been detached from the tab strip.
@@ -289,6 +291,21 @@
       std::unique_ptr<DetachedTabCollection> group,
       int index);
 
+  // Removes the split collection from the collection hierarchy and passes it to
+  // the client. The client can re-insert into another tabstrip using
+  // `InsertDetachedSplitTabAt` without destroying the split.
+  std::unique_ptr<DetachedTabCollection> DetachSplitTabForInsertion(
+      const split_tabs::SplitTabId split_id);
+
+  // Inserts a detached split tab into the tabstrip starting at `index`.
+  // `pinned` and `group` information are used to insert it in the right place
+  // in the collection hierarchy.
+  gfx::Range InsertDetachedSplitTabAt(
+      std::unique_ptr<DetachedTabCollection> split,
+      int index,
+      bool pinned,
+      std::optional<tab_groups::TabGroupId> group_id = std::nullopt);
+
   // Closes the WebContents at the specified index. This causes the
   // WebContents to be destroyed, but it may not happen immediately.
   // |close_types| is a bitmask of CloseTypes.
@@ -825,10 +842,16 @@
   // Notify observers that `group` is moved.
   void NotifyTabGroupMoved(const tab_groups::TabGroupId& group);
 
-  // Notify observers that `group` is detached from the model.
-  void NotifyTabGroupDetached(tabs::TabGroupTabCollection* group_collection);
+  // Notify observers that `group` is detached from the model. This also sends
+  // split related observations within the group.
+  void NotifyTabGroupDetached(
+      tabs::TabGroupTabCollection* group_collection,
+      std::map<split_tabs::SplitTabId,
+               std::vector<std::pair<tabs::TabInterface*, int>>>
+          splits_in_group);
 
-  // Notify observers that `group` is attached to the model.
+  // Notify observers that `group` is attached to the model. This also sends
+  // split related observations within the group.
   void NotifyTabGroupAttached(tabs::TabGroupTabCollection* group_collection);
 
   // Notify observers that split with `split_id` has been created.
@@ -856,6 +879,17 @@
       const std::vector<std::pair<tabs::TabInterface*, int>>& tabs_with_indices,
       SplitTabChange::SplitTabRemoveReason reason);
 
+  // Notify observers that a split was detached from this tabstrip model.
+  // This also sends any group related notification.
+  void NotifySplitTabDetached(
+      tabs::SplitTabCollection* split_collection,
+      std::vector<std::pair<tabs::TabInterface*, int>> tabs_in_split,
+      std::optional<tab_groups::TabGroupId> previous_group_state);
+
+  // Notify observers that a split was attached to this tabstrip model.
+  // This also sends any group related notification.
+  void NotifySplitTabAttached(tabs::SplitTabCollection* split_collection);
+
   // Detaches the tab at the specified `index` from this strip.
   // `web_contents_remove_reason` is used to indicate to observers what is going
   // to happen to the WebContents (i.e. deleted or reinserted into another tab
@@ -879,11 +913,44 @@
       TabStripModelChange::RemoveReason web_contents_remove_reason,
       tabs::TabInterface::DetachReason tab_detach_reason);
 
-  std::unique_ptr<DetachedTabCollection> DetachTabGroupImpl(
-      const tab_groups::TabGroupId& group);
+  // Removes a tab collection from `contents_data_` using
+  // `execute_detach_collection_operation`. Also sends collection specific
+  // observation using `execute_tabs_notify_observer_operation` like group and
+  // split related observation calls. `TabStripModelChange` and
+  // `TabStripSelectionChange` observation calls are handled as common code.
+  std::unique_ptr<tabs::TabCollection> DetachTabCollectionImpl(
+      tabs::TabCollection* collection,
+      base::OnceCallback<std::unique_ptr<tabs::TabCollection>()>
+          execute_detach_collection_operation,
+      base::OnceClosure execute_tabs_notify_observer_operation);
 
-  gfx::Range InsertDetachedTabGroupImpl(
-      std::unique_ptr<DetachedTabCollection> detached_group,
+  // Helper method performing tasks like notification, fixing opener and
+  // returning back a Remove struct before actually detaching the set of
+  // tab_indices.
+  TabStripModelChange::Remove ProcessTabsForDetach(gfx::Range tab_indices);
+
+  // Helper method for updating the selection model after detaching a collection
+  // from `contents_data_`.
+  void UpdateSelectionModelForDetach(gfx::Range tab_indices,
+                                     std::optional<int> next_selected_index);
+
+  // Attaches a tab collection to `contents_data_` using
+  // `execute_insert_detached_tabs_operation`. Also sends collection specific
+  // observation using `execute_tabs_notify_observer_operation` like group and
+  // split related observation calls. `TabStripModelChange` and
+  // `TabStripSelectionChange` observation calls are handled as common code.
+  gfx::Range InsertDetachedCollectionImpl(
+      tabs::TabCollection* collection,
+      std::optional<int> active_index,
+      base::OnceClosure execute_insert_detached_tabs_operation,
+      base::OnceClosure execute_tabs_notify_observer_operation);
+
+  // This is the callback used as `execute_insert_detached_tabs_operation` in
+  // `InsertDetachedCollectionImpl` when a group is inserted into a tabstrip. It
+  // updates the `group_model_` and inserts the `group_collection` into
+  // `contents_data_`.
+  void InsertDetachedTabGroupImpl(
+      std::unique_ptr<tabs::TabGroupTabCollection> group_collection,
       int index);
 
   // We batch send notifications. This has two benefits:
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 1bbeeadc..4863e5b 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -895,6 +895,26 @@
   delegate()->SetBrowserWindowInterface(nullptr);
 }
 
+TEST_F(TabStripModelTest, TestDetachSplitInGroupNewSelection) {
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(1), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(2), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(3), true);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(4), true);
+
+  EXPECT_EQ(tabstrip()->count(), 4);
+
+  tabstrip()->AddToNewGroup(std::vector<int>{1, 2, 3});
+  tabstrip()->ActivateTabAt(
+      2, TabStripUserGestureDetails(
+             TabStripUserGestureDetails::GestureType::kOther));
+  split_tabs::SplitTabId split_id = tabstrip()->AddToNewSplit(
+      std::vector<int>{3}, split_tabs::SplitTabLayout::kHorizontal);
+  tabstrip()->ForgetAllOpeners();
+
+  tabstrip()->DetachSplitTabForInsertion(split_id);
+  EXPECT_EQ(tabstrip()->active_index(), 1);
+}
+
 TEST_F(TabStripModelTest, TestDetachTabInGroupNewSelection) {
   tabstrip()->AppendWebContents(CreateWebContentsWithID(1), false);
   tabstrip()->AppendWebContents(CreateWebContentsWithID(2), false);
@@ -931,6 +951,45 @@
   EXPECT_EQ(tabstrip()->active_index(), 1);
 }
 
+TEST_F(TabStripModelTest, TestDetachSplitForInsertion) {
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(1), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(2), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(3), true);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(4), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(5), false);
+  tabstrip()->AppendWebContents(CreateWebContentsWithID(6), true);
+
+  tabstrip()->ActivateTabAt(
+      2, TabStripUserGestureDetails(
+             TabStripUserGestureDetails::GestureType::kOther));
+
+  split_tabs::SplitTabId split_id =
+      tabstrip()->AddToNewSplit({3}, split_tabs::SplitTabLayout::kVertical);
+
+  tabstrip()->ForgetAllOpeners();
+
+  std::unique_ptr<DetachedTabCollection> detached_split =
+      tabstrip()->DetachSplitTabForInsertion(split_id);
+
+  tabs::SplitTabCollection* split_collection =
+      std::get<std::unique_ptr<tabs::SplitTabCollection>>(
+          detached_split->collection_)
+          .get();
+
+  EXPECT_EQ(split_collection->TabCountRecursive(), 2u);
+  EXPECT_FALSE(tabstrip()->ContainsSplit(split_id));
+  EXPECT_EQ(tabstrip()->count(), 4);
+  EXPECT_EQ(tabstrip()->active_index(), 2);
+  // Reinsert the detached group.
+  tabstrip()->InsertDetachedSplitTabAt(std::move(detached_split), 0, false);
+
+  EXPECT_TRUE(tabstrip()->ContainsSplit(split_id));
+  EXPECT_EQ(tabstrip()->GetSplitData(split_id)->ListTabs().size(), 2u);
+  EXPECT_EQ(tabstrip()->GetTabAtIndex(0)->GetSplit().value(), split_id);
+  EXPECT_EQ(tabstrip()->GetTabAtIndex(1)->GetSplit().value(), split_id);
+  EXPECT_EQ(tabstrip()->count(), 6);
+}
+
 TEST_F(TabStripModelTest, TestDetachGroupForInsertion) {
   tabstrip()->AppendWebContents(CreateWebContentsWithID(1), false);
   tabstrip()->AppendWebContents(CreateWebContentsWithID(2), false);
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
index 8e267520..bac0984d 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
@@ -1170,7 +1170,7 @@
     std::unique_ptr<TabDragController> controller,
     std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
                              std::unique_ptr<DetachedTabCollection>>>
-        owned_tabs_and_groups) {
+        owned_tabs_and_collections) {
   // We should already have detached by the time we get here.
   CHECK(!attached_context_);
   attached_context_ = attached_context;
@@ -1204,9 +1204,9 @@
       },
       attached_context_->GetTabStripModel());
 
-  for (auto& tab_or_group : owned_tabs_and_groups) {
+  for (auto& tab_or_collection : owned_tabs_and_collections) {
     if (auto* tab =
-            std::get_if<std::unique_ptr<tabs::TabModel>>(&tab_or_group)) {
+            std::get_if<std::unique_ptr<tabs::TabModel>>(&tab_or_collection)) {
       const tabs::TabInterface* tab_ptr = tab->get();
       // If it's a tab - we add it to the tabstrip.
       int add_types = AddTabTypes::ADD_NONE;
@@ -1226,19 +1226,29 @@
       update_sad_tab.Run(index);
       index++;
     } else {
-      auto group = std::move(
-          *std::get_if<std::unique_ptr<DetachedTabCollection>>(&tab_or_group));
-      // If it's a group - we add it to the tabstrip. This will add all the
-      // tabs.
-      const gfx::Range group_indices =
-          attached_context_->GetTabStripModel()->InsertDetachedTabGroupAt(
-              std::move(group), index);
+      gfx::Range collection_indices;
+      auto* detached_tab_collection =
+          std::get_if<std::unique_ptr<DetachedTabCollection>>(
+              &tab_or_collection);
 
-      CHECK_EQ(group_indices.start(), index);
-      index += group_indices.length();
+      const bool pinned = detached_tab_collection->get()->pinned_;
 
-      for (size_t sad_index = group_indices.start();
-           sad_index < group_indices.end(); sad_index++) {
+      if (std::holds_alternative<std::unique_ptr<tabs::TabGroupTabCollection>>(
+              detached_tab_collection->get()->collection_)) {
+        collection_indices =
+            attached_context_->GetTabStripModel()->InsertDetachedTabGroupAt(
+                std::move(*detached_tab_collection), index);
+      } else {
+        collection_indices =
+            attached_context_->GetTabStripModel()->InsertDetachedSplitTabAt(
+                std::move(*detached_tab_collection), index, pinned);
+      }
+
+      CHECK_EQ(collection_indices.start(), index);
+      index += collection_indices.length();
+
+      for (size_t sad_index = collection_indices.start();
+           sad_index < collection_indices.end(); sad_index++) {
         update_sad_tab.Run(sad_index);
       }
     }
@@ -1327,7 +1337,7 @@
 
   std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
                            std::unique_ptr<DetachedTabCollection>>>
-      owned_tabs_and_groups;
+      owned_tabs_and_collections;
   for (TabDragData& tab_drag_datum : drag_data_.tab_drag_data_) {
     const int index =
         attached_model->GetIndexOfWebContents(tab_drag_datum.contents);
@@ -1342,10 +1352,14 @@
         attached_model->GetTabGroupForTab(index);
     if (std::find(groups_to_move.begin(), groups_to_move.end(), group) !=
         groups_to_move.end()) {
-      owned_tabs_and_groups.emplace_back(
+      owned_tabs_and_collections.emplace_back(
           attached_model->DetachTabGroupForInsertion(group.value()));
+    } else if (attached_model->GetTabAtIndex(index)->IsSplit()) {
+      owned_tabs_and_collections.emplace_back(
+          attached_model->DetachSplitTabForInsertion(
+              attached_model->GetTabAtIndex(index)->GetSplit().value()));
     } else {
-      owned_tabs_and_groups.emplace_back(
+      owned_tabs_and_collections.emplace_back(
           attached_model->DetachTabAtForInsertion(index));
     }
   }
@@ -1368,7 +1382,7 @@
   attached_context_->DraggedTabsDetached();
   attached_context_ = nullptr;
 
-  return std::make_tuple(std::move(me), std::move(owned_tabs_and_groups));
+  return std::make_tuple(std::move(me), std::move(owned_tabs_and_collections));
 }
 
 TabDragController::Liveness
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
index d7b8af8..d4c5f0e 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
@@ -353,7 +353,7 @@
       std::unique_ptr<TabDragController> controller,
       std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
                                std::unique_ptr<DetachedTabCollection>>>
-          owned_tabs_and_groups);
+          owned_tabs_and_collections);
 
   // Sets up dragging in `attached_context_`. The dragged tabs must already
   // be present.
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
index 19ad42a4..b873145 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller_interactive_uitest.cc
@@ -70,6 +70,7 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/split_tab_data.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
@@ -686,7 +687,8 @@
           testing::tuple<bool, bool, const char*>> {
  public:
   DetachToBrowserTabDragControllerTest() {
-    std::vector<base::test::FeatureRef> enabled_features = {};
+    std::vector<base::test::FeatureRef> enabled_features = {
+        features::kSideBySide};
     std::vector<base::test::FeatureRef> disabled_features = {
         features::kWebUITabStrip};
 
@@ -2707,7 +2709,8 @@
   DragPinnedAndUnpinnedToSeparateWindow
 #endif
 
-// Creates two browsers, then drags a group from one to the other.
+// Creates two browsers, then drags a combination of pinned and unpinned tabs
+// from one to the other.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_DragPinnedAndUnpinnedToSeparateWindow) {
   ASSERT_TRUE(browser()->tab_strip_model()->SupportsTabGroups());
@@ -2746,6 +2749,50 @@
   EXPECT_FALSE(browser2->tab_strip_model()->IsTabPinned(1));
 }
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+// Flaky on Mac10.14 and Linux: https://crbug.com/1213345
+#define MAYBE_DragSplitTabToSeparateWindow DISABLED_DragSplitTabToSeparateWindow
+#else
+#define MAYBE_DragSplitTabToSeparateWindow DragSplitTabToSeparateWindow
+#endif
+
+// Creates two browsers, then drags a combination of pinned and unpinned tabs
+// from one to the other.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       MAYBE_DragSplitTabToSeparateWindow) {
+  ASSERT_TRUE(browser()->tab_strip_model()->SupportsTabGroups());
+
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+  AddTabsAndResetBrowser(browser(), 1);
+  browser()->tab_strip_model()->ActivateTabAt(0);
+  split_tabs::SplitTabId split_id = browser()->tab_strip_model()->AddToNewSplit(
+      {1}, split_tabs::SplitTabLayout::kHorizontal);
+  StopAnimating(tab_strip);
+
+  // Create another browser.
+  Browser* browser2 = CreateAnotherBrowserAndResize();
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStripModel* model2 = browser2->tab_strip_model();
+  AddTabsAndResetBrowser(browser2, 1);
+  ResetIDs(model2, 100);
+  StopAnimating(tab_strip2);
+
+  DragTabAndNotify(tab_strip, base::BindOnce(&DragAllToSeparateWindowStep2,
+                                             this, tab_strip, tab_strip2));
+
+  // Drag to the trailing end of the tabstrip to ensure we're in a
+  // predictable spot within the strip.
+  StopAnimating(tab_strip2);
+  ASSERT_TRUE(DragInputToCenter(tab_strip2->tab_at(3)));
+  // Release mouse or touch, stopping the drag session.
+  ASSERT_TRUE(ReleaseInput());
+
+  EXPECT_EQ("100 101 0 1", IDString(model2));
+  EXPECT_EQ(
+      browser2->tab_strip_model()->GetSplitData(split_id)->ListTabs().size(),
+      2u);
+}
+
 // Flaky. http://crbug.com/1128774
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 // Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345
@@ -3004,13 +3051,55 @@
 
   // Expect the group to be in browser2, but with a new tab_groups::TabGroupId.
   EXPECT_EQ("100 0 1", IDString(model2));
-  std::vector<tab_groups::TabGroupId> groups2 =
-      model2->group_model()->ListTabGroups();
-  EXPECT_EQ(1u, groups2.size());
-  EXPECT_EQ(model2->group_model()->GetTabGroup(groups2[0])->ListTabs(),
+  EXPECT_EQ(model2->group_model()->GetTabGroup(group)->ListTabs(),
             gfx::Range(1, 3));
-  EXPECT_EQ(groups2[0], group);
-  EXPECT_EQ(tab_strip2->GetGroupColorId(groups2[0]), group_color);
+  EXPECT_EQ(tab_strip2->GetGroupColorId(group), group_color);
+}
+
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+// Bulk-disabled for arm64 bot stabilization: https://crbug.com/1154345
+// Flaky on Mac10.14 and Linux: https://crbug.com/1213345
+#define MAYBE_DragGroupHeaderWithSplitToSeparateWindow \
+  DISABLED_DragGroupHeaderWithSplitToSeparateWindow
+#else
+#define MAYBE_DragGroupHeaderWithSplitToSeparateWindow \
+  DragGroupHeaderWithSplitToSeparateWindow
+#endif
+
+// Creates two browsers, then drags a group from one to the other.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       MAYBE_DragGroupHeaderWithSplitToSeparateWindow) {
+  ASSERT_TRUE(browser()->tab_strip_model()->SupportsTabGroups());
+
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+  TabStripModel* model = browser()->tab_strip_model();
+  AddTabsAndResetBrowser(browser(), 1);
+  tab_groups::TabGroupId group = model->AddToNewGroup({0, 1});
+
+  model->ActivateTabAt(0);
+  model->AddToNewSplit({1}, split_tabs::SplitTabLayout::kHorizontal);
+
+  tab_groups::TabGroupColorId group_color = tab_strip->GetGroupColorId(group);
+  StopAnimating(tab_strip);
+
+  // Create another browser.
+  Browser* browser2 = CreateAnotherBrowserAndResize();
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStripModel* model2 = browser2->tab_strip_model();
+  StopAnimating(tab_strip2);
+
+  // Drag the group by its header into the second browser.
+  DragToDetachGroupAndNotify(tab_strip,
+                             base::BindOnce(&DragAllToSeparateWindowStep2, this,
+                                            tab_strip, tab_strip2),
+                             group);
+  ASSERT_TRUE(ReleaseInput());
+
+  // Expect the group to be in browser2.
+  EXPECT_EQ("100 0 1", IDString(model2));
+  EXPECT_EQ(model2->group_model()->GetTabGroup(group)->ListTabs(),
+            gfx::Range(1, 3));
+  EXPECT_EQ(tab_strip2->GetGroupColorId(group), group_color);
 }
 
 // Drags a tab group by the header to a new position toward the right and
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index c34a8256..9306471e 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -343,8 +343,7 @@
       MaybeAdjustLeftForPinnedTab(&favicon_bounds, gfx::kFaviconSize);
     }
     icon_->EnlargeDiscardIndicatorRadius(
-        controller()->GetInactiveTabWidth() -
-                    2 * tab_style()->GetBottomCornerRadius() >=
+        width() - 2 * tab_style()->GetBottomCornerRadius() >=
                 gfx::kFaviconSize + 2 * kIncreasedDiscardIndicatorRadiusDp
             ? kIncreasedDiscardIndicatorRadiusDp
             : 0);
diff --git a/chrome/browser/ui/views/tabs/tab_icon.cc b/chrome/browser/ui/views/tabs/tab_icon.cc
index 58d404db..6c2a8a4f 100644
--- a/chrome/browser/ui/views/tabs/tab_icon.cc
+++ b/chrome/browser/ui/views/tabs/tab_icon.cc
@@ -243,6 +243,10 @@
   }
 }
 
+views::PaintInfo::ScaleType TabIcon::GetPaintScaleType() const {
+  return views::PaintInfo::ScaleType::kUniformScaling;
+}
+
 void TabIcon::OnThemeChanged() {
   views::View::OnThemeChanged();
   crashed_icon_ = gfx::ImageSkia();  // Force recomputation if crashed.
diff --git a/chrome/browser/ui/views/tabs/tab_icon.h b/chrome/browser/ui/views/tabs/tab_icon.h
index ddd9b5101..4a13b51 100644
--- a/chrome/browser/ui/views/tabs/tab_icon.h
+++ b/chrome/browser/ui/views/tabs/tab_icon.h
@@ -93,6 +93,7 @@
 
   // views::View:
   void OnPaint(gfx::Canvas* canvas) override;
+  views::PaintInfo::ScaleType GetPaintScaleType() const override;
   void OnThemeChanged() override;
 
   // views::AnimationDelegateViews:
diff --git a/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/AuthenticatorIncognitoConfirmationBottomsheet.java b/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/AuthenticatorIncognitoConfirmationBottomsheet.java
index a4ff5c05..7ec7cc6 100644
--- a/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/AuthenticatorIncognitoConfirmationBottomsheet.java
+++ b/chrome/browser/webauthn/android/java/src/org/chromium/chrome/browser/webauthn/AuthenticatorIncognitoConfirmationBottomsheet.java
@@ -99,11 +99,6 @@
                 }
 
                 @Override
-                public int getPeekHeight() {
-                    return HeightMode.DISABLED;
-                }
-
-                @Override
                 public boolean swipeToDismissEnabled() {
                     return false;
                 }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 9b9a4f1..0ad2eaa 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1747677396-4148cab5f17c38e0fd516f6ebf4b9a6b70261420-55031cf373b345a10a079f07cca33880566e8303.profdata
+chrome-linux-main-1747698011-7654f82c8290232e534db00b8e35f7952b18755b-3b9180ccbc5c7a525a46ae4f81f7209025954583.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index e3cc8104..818049b 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1747684627-aeabbbab465b882667a9f6338898010c2f73026f-63f7712f8e7f82874af0f042314dcbe01c0785c4.profdata
+chrome-mac-arm-main-1747706336-342ae52532b82d226477a67df84ce31c38795e1f-d29271b3bd04f264ba092e5dcc2e2579f7712701.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 05533ad..0d04649e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1747677396-15fb6c21eb0be4656ce133e20054978b293128da-55031cf373b345a10a079f07cca33880566e8303.profdata
+chrome-mac-main-1747698011-62d683e15a9a8383d02a76dc83fd4f3d900d0918-3b9180ccbc5c7a525a46ae4f81f7209025954583.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index eda2e8d..0fd3cac 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1747677396-a29e2d1f5d1738dc2f45e63e25f685a3d19d73c5-55031cf373b345a10a079f07cca33880566e8303.profdata
+chrome-win-arm64-main-1747698011-43268f6a546662e2c8a657382f4023b0d0b29aed-3b9180ccbc5c7a525a46ae4f81f7209025954583.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d0ae847d..69c1bf7 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1747645140-308ae3c7f9cfeed24225cdfe30b08a37139557af-64a8eaad724a6c9dac1f93063b00452a4c2766e5.profdata
+chrome-win32-main-1747677396-f26d0858b187abcb1c2eab628d4942713919a140-55031cf373b345a10a079f07cca33880566e8303.profdata
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 7a46135..7b03616 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -319,17 +319,6 @@
     "gjjabgpgjpampikjhjpfhneeoapjbjaf";
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
 
-// What causes an extension to be installed? Used in histograms, so don't
-// change existing values.
-enum CrxInstallCause {
-  INSTALL_CAUSE_UNSET = 0,
-  INSTALL_CAUSE_USER_DOWNLOAD,
-  INSTALL_CAUSE_UPDATE,
-  INSTALL_CAUSE_EXTERNAL_FILE,
-  INSTALL_CAUSE_AUTOMATION,
-  NUM_INSTALL_CAUSES
-};
-
 // The states that an app can be in, as reported by chrome.app.installState
 // and chrome.app.runningState.
 inline constexpr char kAppStateNotInstalled[] = "not_installed";
diff --git a/chrome/installer/mac/internal b/chrome/installer/mac/internal
index 6460c6c..f6030c4 160000
--- a/chrome/installer/mac/internal
+++ b/chrome/installer/mac/internal
@@ -1 +1 @@
-Subproject commit 6460c6c38734ceabe0bb49c02640b6c2040b1e63
+Subproject commit f6030c49cc22768ce47357e5a35e872cec925a65
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9dc89f6..f3800a1 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3263,7 +3263,6 @@
       "../browser/predictors/loading_predictor_browsertest.cc",
       "../browser/prefetch/prefetch_browsertest.cc",
       "../browser/prefs/tracked/pref_hash_browsertest.cc",
-      "../browser/preloading/latency_ablation_browsertest.cc",
       "../browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc",
       "../browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc",
       "../browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.h",
diff --git a/chrome/test/data/pdf/ink2_text_box_test.ts b/chrome/test/data/pdf/ink2_text_box_test.ts
index 904fb9c5..d6b8466 100644
--- a/chrome/test/data/pdf/ink2_text_box_test.ts
+++ b/chrome/test/data/pdf/ink2_text_box_test.ts
@@ -113,7 +113,7 @@
     // Initial state
     chrome.test.assertEq('12px', textboxStyles.getPropertyValue('font-size'));
     chrome.test.assertEq(
-        'sans-serif', textboxStyles.getPropertyValue('font-family'));
+        'Arial, sans-serif', textboxStyles.getPropertyValue('font-family'));
     chrome.test.assertEq('400', textboxStyles.getPropertyValue('font-weight'));
     chrome.test.assertEq(
         'normal', textboxStyles.getPropertyValue('font-style'));
@@ -130,7 +130,7 @@
     manager.setTextTypeface(TextTypeface.SERIF);
     await microtasksFinished();
     chrome.test.assertEq(
-        'serif', textboxStyles.getPropertyValue('font-family'));
+        'Times, serif', textboxStyles.getPropertyValue('font-family'));
 
     // Size
     manager.setTextSize(20);
diff --git a/clank b/clank
index e899bd8..de8849c 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit e899bd830b7f2571c4f3054290353a35f85ed0f6
+Subproject commit de8849c98f8b6f841b915b569f38ac6c7e3cbf77
diff --git a/components/autofill/core/common/field_data_manager.cc b/components/autofill/core/common/field_data_manager.cc
index d53f371..4c1775e 100644
--- a/components/autofill/core/common/field_data_manager.cc
+++ b/components/autofill/core/common/field_data_manager.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill/core/common/field_data_manager.h"
 
+#include <utility>
+
 #include "base/check.h"
 #include "base/i18n/case_conversion.h"
 
@@ -49,16 +51,17 @@
 }
 
 void FieldDataManager::UpdateFieldDataMap(FieldRendererId id,
-                                          std::u16string_view value,
+                                          std::u16string value,
                                           FieldPropertiesMask mask) {
+  const bool is_empty = value.empty();
   if (HasFieldData(id)) {
-    field_value_and_properties_map_[id].first = std::u16string(value);
+    field_value_and_properties_map_[id].first = std::move(value);
     field_value_and_properties_map_[id].second |= mask;
   } else {
-    field_value_and_properties_map_[id] = {std::u16string(value), mask};
+    field_value_and_properties_map_[id] = {std::move(value), mask};
   }
   // Reset kUserTyped and kAutofilled flags if the value is empty.
-  if (value.empty()) {
+  if (is_empty) {
     field_value_and_properties_map_[id].second &=
         ~(FieldPropertiesFlags::kUserTyped | FieldPropertiesFlags::kAutofilled);
   }
diff --git a/components/autofill/core/common/field_data_manager.h b/components/autofill/core/common/field_data_manager.h
index 6410ccf..acaeedb 100644
--- a/components/autofill/core/common/field_data_manager.h
+++ b/components/autofill/core/common/field_data_manager.h
@@ -31,8 +31,10 @@
   // |field_value_and_properties_map_|.
   // Flags in |mask| are added with bitwise OR operation.
   // If |value| is empty, kUserTyped and kAutofilled should be cleared.
+  // `value` is neither a const reference nor a u16string_view for move
+  // capability.
   void UpdateFieldDataMap(FieldRendererId id,
-                          std::u16string_view value,
+                          std::u16string value,
                           FieldPropertiesMask mask);
   // Only update FieldPropertiesMask when value is null.
   void UpdateFieldDataMapWithNullValue(FieldRendererId id,
diff --git a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
index 1195c5f..95f87a4 100644
--- a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
+++ b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
@@ -95,18 +95,23 @@
      */
     void destroy();
 
-    /** @return The priority of this content. */
+    /**
+     * @return The priority of this content.
+     */
     @ContentPriority
     int getPriority();
 
-    /** @return Whether swiping the sheet down hard enough will cause the sheet to be dismissed. */
+    /**
+     * @return Whether swiping the sheet down hard enough will cause the sheet to be dismissed.
+     */
     boolean swipeToDismissEnabled();
 
-    /** @return Whether the sheet will always skip the half state once it was fully extended. */
+    /**
+     * @return Whether the sheet will always skip the half state once it was fully extended.
+     */
     default boolean skipHalfStateOnScrollingDown() {
         return true;
     }
-    ;
 
     /**
      * @return Whether this content owns its lifecycle. If false, the content will be dismissed
@@ -135,13 +140,17 @@
     }
 
     /**
-     * @return The height of the peeking state for the content in px or one of the values in
-     *         {@link HeightMode}. If {@link HeightMode#DEFAULT}, the system expects
-     *         {@link #getToolbarView} to be non-null, where it will then use its height as the
-     *         peeking height. This method cannot return {@link HeightMode#WRAP_CONTENT}.
+     * The height of bottom sheet in PEEK mode. The sheet content that wants to show content as PEEK
+     * can override this method and provide a non-negative height. This interface by default
+     * supplies {@link HeightMode#DISABLED}.
+     *
+     * @return The height of the peeking state for the content in px or one of the values in {@link
+     *     HeightMode}. If {@link HeightMode#DEFAULT}, the system expects {@link #getToolbarView} to
+     *     be non-null, where it will then use its height as the peeking height. This method cannot
+     *     return {@link HeightMode#WRAP_CONTENT}.
      */
     default int getPeekHeight() {
-        return HeightMode.DEFAULT;
+        return HeightMode.DISABLED;
     }
 
     /**
diff --git a/components/collaboration/internal/collaboration_controller.cc b/components/collaboration/internal/collaboration_controller.cc
index 65f540ec..933fc5f 100644
--- a/components/collaboration/internal/collaboration_controller.cc
+++ b/components/collaboration/internal/collaboration_controller.cc
@@ -696,14 +696,28 @@
 
   void ProcessOutcome(Outcome outcome) override {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    if (Outcome::kCancel == outcome) {
-      CHECK_EQ(controller_->flow().type, FlowType::kJoin)
-          << "Only the join flow can transition into the AddingUserToGroup "
-             "state.";
-      RecordJoinEvent(GetLogger(), CollaborationServiceJoinEvent::kCanceled);
+    CHECK_EQ(controller_->flow().type, FlowType::kJoin)
+        << "Only the join flow can transition into the AddingUserToGroup "
+           "state.";
+
+    switch (outcome) {
+      case Outcome::kSuccess:
+        RecordJoinEvent(GetLogger(),
+                        CollaborationServiceJoinEvent::kAddedUserToGroup);
+        break;
+      case Outcome::kFailure:
+        RecordJoinEvent(
+            GetLogger(),
+            CollaborationServiceJoinEvent::kFailedAddingUserToGroup);
+
+        break;
+      case Outcome::kCancel:
+        RecordJoinEvent(GetLogger(), CollaborationServiceJoinEvent::kCanceled);
+        break;
+      case Outcome::kGroupLeftOrDeleted:
+        NOTREACHED() << "kGroupLeftOrDeleted should not happen in "
+                        "AddingUserToGroupState";
     }
-    RecordJoinEvent(GetLogger(),
-                    CollaborationServiceJoinEvent::kAddedUserToGroup);
 
     ControllerState::ProcessOutcome(outcome);
   }
diff --git a/components/collaboration/internal/collaboration_controller_unittest.cc b/components/collaboration/internal/collaboration_controller_unittest.cc
index 1b9c44c..180c40c 100644
--- a/components/collaboration/internal/collaboration_controller_unittest.cc
+++ b/components/collaboration/internal/collaboration_controller_unittest.cc
@@ -269,6 +269,9 @@
   histogram_tester.ExpectBucketCount(
       "CollaborationService.JoinFlow",
       metrics::CollaborationServiceJoinEvent::kOpenedNewGroup, 1);
+  histogram_tester.ExpectBucketCount(
+      "CollaborationService.JoinFlow",
+      metrics::CollaborationServiceJoinEvent::kAddedUserToGroup, 1);
   histogram_tester.ExpectTimeBucketCount(
       "CollaborationService.Latency.AuthenticationInitToSuccess",
       authentication_time, 1);
@@ -614,6 +617,44 @@
       metrics::CollaborationServiceJoinEvent::kCanceled, 1);
 }
 
+TEST_F(CollaborationControllerTest, SimulateFailureToAddUserToGroup) {
+  base::HistogramTester histogram_tester;
+
+  RunLoop run_loop;
+
+  // Start Join flow.
+  InitializeJoinController(run_loop.QuitClosure());
+  SetUpJoinRequirements();
+
+  // Simulate getting to the Adding User To Group state.
+  base::OnceCallback<void(Outcome)> join_ui_callback;
+  EXPECT_CALL(*delegate_, ShowJoinDialog(_, _, IsNotNullCallback()))
+      .WillOnce(MoveArg<2>(&join_ui_callback));
+
+  base::OnceCallback<void(Outcome)> error_ui_callback;
+  EXPECT_CALL(*delegate_, ShowError(ErrorInfo(ErrorInfo::Type::kGenericError),
+                                    IsNotNullCallback()))
+      .WillOnce(MoveArg<1>(&error_ui_callback));
+  controller_->SetStateForTesting(StateId::kAddingUserToGroup);
+
+  // Show group preview screen.
+  data_sharing::SharedDataPreview preview;
+  preview.shared_tab_group_preview = data_sharing::SharedTabGroupPreview();
+  std::move(preview_callback_).Run(preview);
+  std::move(group_data_callback_).Run(GroupData());
+
+  // Simulate failure on the join flow.
+  EXPECT_CALL(*delegate_, OnFlowFinished);
+  std::move(join_ui_callback).Run(Outcome::kFailure);
+  std::move(error_ui_callback).Run(Outcome::kSuccess);
+
+  run_loop.Run();
+
+  histogram_tester.ExpectBucketCount(
+      "CollaborationService.JoinFlow",
+      metrics::CollaborationServiceJoinEvent::kFailedAddingUserToGroup, 1);
+}
+
 TEST_F(CollaborationControllerTest, AuthenticationError) {
   RunLoop run_loop;
   // Start Join flow with authenticating screens.
diff --git a/components/collaboration/internal/metrics.cc b/components/collaboration/internal/metrics.cc
index 5a8c354..b5b3469 100644
--- a/components/collaboration/internal/metrics.cc
+++ b/components/collaboration/internal/metrics.cc
@@ -90,6 +90,8 @@
       return "AccountInfoNotReadyOnSignin";
     case CollaborationServiceJoinEvent::kReadNewGroupUserIsAlreadyMember:
       return "ReadNewGroupUserIsAlreadyMember";
+    case CollaborationServiceJoinEvent::kFailedAddingUserToGroup:
+      return "FailedAddingUserToGroup";
   }
 }
 
diff --git a/components/collaboration/internal/metrics.h b/components/collaboration/internal/metrics.h
index 9ee32aa8..a615251a 100644
--- a/components/collaboration/internal/metrics.h
+++ b/components/collaboration/internal/metrics.h
@@ -54,7 +54,8 @@
   kManagedAccountSignin = 31,
   kAccountInfoNotReadyOnSignin = 32,
   kReadNewGroupUserIsAlreadyMember = 33,
-  kMaxValue = kReadNewGroupUserIsAlreadyMember,
+  kFailedAddingUserToGroup = 34,
+  kMaxValue = kFailedAddingUserToGroup,
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/collaboration_service/enums.xml:CollaborationServiceJoinEvent)
 
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 8018ed6..66e70da4 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -125,7 +125,7 @@
     SYNC_ERROR_INFOBAR_DELEGATE_IOS = 58,
     UPGRADE_INFOBAR_DELEGATE_IOS = 59,
     // Removed: WINDOW_ERROR_INFOBAR_DELEGATE_ANDROID = 60,
-    DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID = 61,
+    // Removed: DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID = 61,
     // Removed: DESKTOP_SEARCH_REDIRECTION_INFOBAR_DELEGATE = 62,
     // Removed: UPDATE_PASSWORD_INFOBAR_DELEGATE_MOBILE = 63,
     // Removed: DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID = 64,
@@ -190,7 +190,7 @@
     PDF_INFOBAR_DELEGATE = 123,
     INSTALLER_DOWNLOADER_INFOBAR_DELEGATE = 124,
   };
-  // LINT.ThenChange(//metrics/histograms/metadata/browser/enums.xml)
+  // LINT.ThenChange(//tools/metrics/histograms/metadata/browser/enums.xml:InfoBarIdentifier)
 
   // Describes navigation events, used to decide whether infobars should be
   // dismissed.
diff --git a/components/omnibox/OWNERS b/components/omnibox/OWNERS
index 62f11ba..cf94dad 100644
--- a/components/omnibox/OWNERS
+++ b/components/omnibox/OWNERS
@@ -10,7 +10,6 @@
 mpearson@chromium.org
 orinj@chromium.org
 pnoland@chromium.org
-yoangela@chromium.org
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index f438a73..ad53538 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -56,6 +56,7 @@
 #include "third_party/omnibox_proto/answer_type.pb.h"
 #include "third_party/omnibox_proto/entity_info.pb.h"
 #include "third_party/omnibox_proto/groups.pb.h"
+#include "third_party/omnibox_proto/suggest_template_info.pb.h"
 #include "ui/base/device_form_factor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/vector_icon_types.h"
@@ -539,6 +540,28 @@
 const gfx::VectorIcon& AutocompleteMatch::GetVectorIcon(
     bool is_bookmark,
     const TemplateURL* turl) const {
+  if (suggest_template.has_value() && suggest_template->has_type_icon()) {
+    // Update this assertion and the switch below whenever values are added.
+    static_assert(omnibox::SuggestTemplateInfo::IconType_MAX ==
+                  omnibox::SuggestTemplateInfo::TRENDING);
+    switch (suggest_template->type_icon()) {
+      case omnibox::SuggestTemplateInfo::ICON_TYPE_UNSPECIFIED:
+        // When not specified, fall back on regular match icon logic below.
+        break;
+      case omnibox::SuggestTemplateInfo::HISTORY:
+        return vector_icons::kHistoryChromeRefreshIcon;
+      case omnibox::SuggestTemplateInfo::SEARCH_LOOP:
+        return vector_icons::kSearchChromeRefreshIcon;
+      case omnibox::SuggestTemplateInfo::SEARCH_LOOP_WITH_SPARKLE:
+        return omnibox::kSearchSparkIcon;
+      case omnibox::SuggestTemplateInfo::TRENDING:
+        return omnibox::kTrendingUpChromeRefreshIcon;
+      default:
+        // Out of range value defaults to search loupe.
+        return vector_icons::kSearchChromeRefreshIcon;
+    }
+  }
+
   // If the user bookmarks 'chrome://history/q=query', a/ corresponding answer
   // match shouldn't show the bookmark star.
   if (is_bookmark && type != Type::HISTORY_EMBEDDINGS_ANSWER)
diff --git a/components/omnibox/browser/autocomplete_match_unittest.cc b/components/omnibox/browser/autocomplete_match_unittest.cc
index 91968f3..9d69ffc 100644
--- a/components/omnibox/browser/autocomplete_match_unittest.cc
+++ b/components/omnibox/browser/autocomplete_match_unittest.cc
@@ -29,6 +29,7 @@
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "third_party/metrics_proto/omnibox_scoring_signals.pb.h"
 #include "third_party/omnibox_proto/entity_info.pb.h"
+#include "third_party/omnibox_proto/suggest_template_info.pb.h"
 #include "ui/gfx/vector_icon_types.h"
 #include "url/gurl.h"
 
@@ -1134,6 +1135,16 @@
       EXPECT_FALSE(match.GetVectorIcon(/*is_bookmark=*/false).is_empty());
     }
   }
+
+  // When the match has a SuggestTemplateInfo, its icon should be set.
+  // This checks the full range to ensure any new additions get mapped.
+  match.suggest_template = omnibox::SuggestTemplateInfo();
+  for (int i = omnibox::SuggestTemplateInfo::IconType_MIN;
+       i <= omnibox::SuggestTemplateInfo::IconType_MAX; i++) {
+    match.suggest_template->set_type_icon(
+        static_cast<omnibox::SuggestTemplateInfo::IconType>(i));
+    EXPECT_FALSE(match.GetVectorIcon(false).is_empty());
+  }
 }
 #endif
 
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 8adcf3e..e1594a35 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -67,6 +67,9 @@
     <message name="IDS_OMNIBOX_EMPTY_HINT" desc="The text displayed in the omnibox when it is empty." formatter_data="android_java">
       Search or type URL
     </message>
+    <message name="IDS_OMNIBOX_EMPTY_HINT_WITH_DSE_NAME" desc="The text displayed in the omnibox when it is empty. Includes Default Search Engine name." formatter_data="android_java">
+      Search <ph name="ENGINE_NAME">%1$s<ex>Yahoo</ex></ph> or type URL
+    </message>
   </if>
   <if expr="is_android">
     <message name="IDS_OMNIBOX_ON_CCT_EMPTY_HINT" desc="Hint text shown in the Omnibox on a Custom Tab." formatter_data="android_java">
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_EMPTY_HINT_WITH_DSE_NAME.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_EMPTY_HINT_WITH_DSE_NAME.png.sha1
new file mode 100644
index 0000000..2bea957
--- /dev/null
+++ b/components/omnibox_strings_grdp/IDS_OMNIBOX_EMPTY_HINT_WITH_DSE_NAME.png.sha1
@@ -0,0 +1 @@
+fc813e34cc2cd86b020fea0af85b8f850c9e4ad7
\ No newline at end of file
diff --git a/components/optimization_guide/core/model_execution/on_device_model_access_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_access_controller.cc
index 9bb4260..75da7f89 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_access_controller.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_access_controller.cc
@@ -101,6 +101,8 @@
 
 base::Time OnDeviceModelAccessController::OnDisconnectedFromRemote() {
   int crash_count = pref_service_->GetInteger(kOnDeviceModelCrashCount) + 1;
+  base::UmaHistogramCounts100(
+      "OptimizationGuide.ModelExecution.OnDeviceModelCrashCount", crash_count);
   pref_service_->SetInteger(kOnDeviceModelCrashCount, crash_count);
   // If the model will be disabled because of crash count, use exponential
   // backoff to re-enable.
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 82e0304..7062789 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 82e030463d0f2a06bc82506a047a6a075ba69263
+Subproject commit 7062789227d77cf3b9d99e973da9b0ecc29056c9
diff --git a/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationAuthnController.java b/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationAuthnController.java
index a3d0efe6..62f70bd 100644
--- a/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationAuthnController.java
+++ b/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationAuthnController.java
@@ -144,11 +144,6 @@
                 }
 
                 @Override
-                public int getPeekHeight() {
-                    return HeightMode.DISABLED;
-                }
-
-                @Override
                 public boolean swipeToDismissEnabled() {
                     return false;
                 }
diff --git a/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationNoMatchingCredController.java b/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationNoMatchingCredController.java
index 602f59f4..836b02c9 100644
--- a/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationNoMatchingCredController.java
+++ b/components/payments/content/android/spc/java/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationNoMatchingCredController.java
@@ -96,11 +96,6 @@
                 }
 
                 @Override
-                public int getPeekHeight() {
-                    return HeightMode.DISABLED;
-                }
-
-                @Override
                 public boolean swipeToDismissEnabled() {
                     return false;
                 }
diff --git a/components/pdf_strings.grdp b/components/pdf_strings.grdp
index ac864e4d..fac29e5 100644
--- a/components/pdf_strings.grdp
+++ b/components/pdf_strings.grdp
@@ -240,7 +240,7 @@
         Expand
       </message>
 
-      <message name="IDS_PDF_ANNOTATION_COLOR_BLACK" desc="Button tooltip for selecting the Black color for drawing on top of the PDF document">
+      <message name="IDS_PDF_ANNOTATION_COLOR_BLACK" desc="Button tooltip for selecting the Black color for drawing on top of the PDF document or for text color for adding text annotations to the document">
         Black
       </message>
       <message name="IDS_PDF_ANNOTATION_COLOR_RED" desc="Button tooltip for selecting the Red color for drawing on top of the PDF document">
@@ -261,7 +261,7 @@
       <message name="IDS_PDF_ANNOTATION_COLOR_BROWN" desc="Button tooltip for selecting the Brown color for drawing on top of the PDF document">
         Brown
       </message>
-      <message name="IDS_PDF_ANNOTATION_COLOR_WHITE" desc="Button tooltip for selecting the White color for drawing on top of the PDF document">
+      <message name="IDS_PDF_ANNOTATION_COLOR_WHITE" desc="Button tooltip for selecting the White color for drawing on top of the PDF document or for text color for adding text annotations to the document.">
         White
       </message>
       <message name="IDS_PDF_ANNOTATION_COLOR_CRIMSON" desc="Button tooltip for selecting the Crimson color for drawing on top of the PDF document">
@@ -303,7 +303,7 @@
       <message name="IDS_PDF_ANNOTATION_COLOR_TEAL" desc="Button tooltip for selecting the Teal color for drawing on top of the PDF document">
         Teal
       </message>
-      <message name="IDS_PDF_ANNOTATION_COLOR_LIGHT_GREY" desc="Button tooltip for selecting the Light Grey color for drawing on top of the PDF document">
+      <message name="IDS_PDF_ANNOTATION_COLOR_LIGHT_GREY" desc="Button tooltip for selecting the Light Grey color for drawing on top of the PDF document or for text color for adding text annotations to the document">
         Light Grey
       </message>
       <message name="IDS_PDF_ANNOTATION_COLOR_LIGHT_PINK" desc="Button tooltip for selecting the Light Pink color for drawing on top of the PDF document">
@@ -385,57 +385,108 @@
       <message name="IDS_PDF_INK2_ANNOTATION_COLOR_LIGHT_YELLOW" desc="The button label for selecting the 'light yellow' brush color for drawing strokes in the PDF viewer.">
         Light Yellow
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_DARK_GREY_1" desc="The button label for selecting the 'dark grey 1' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_DARK_GREY_1" desc="The button label for selecting the 'dark grey 1' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Dark Grey 1
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_DARK_GREY_2" desc="The button label for selecting the 'dark grey 2' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_DARK_GREY_2" desc="The button label for selecting the 'dark grey 2' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Dark Grey 2
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_1" desc="The button label for selecting the 'red 1' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_1" desc="The button label for selecting the 'red 1' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Red 1
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_1" desc="The button label for selecting the 'yellow 1' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_1" desc="The button label for selecting the 'yellow 1' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Yellow 1
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_1" desc="The button label for selecting the 'green 1' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_1" desc="The button label for selecting the 'green 1' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Green 1
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_1" desc="The button label for selecting the 'blue 1' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_1" desc="The button label for selecting the 'cyan 1' color for adding annotation text in the PDF viewer.">
+        Cyan 1
+      </message>
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_1" desc="The button label for selecting the 'blue 1' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Blue 1
       </message>
       <message name="IDS_PDF_INK2_ANNOTATION_COLOR_TAN_1" desc="The button label for selecting the 'tan 1' brush color for drawing strokes in the PDF viewer.">
         Tan 1
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_2" desc="The button label for selecting the 'red 2' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_2" desc="The button label for selecting the 'red 2' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Red 2
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_2" desc="The button label for selecting the 'yellow 2' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_2" desc="The button label for selecting the 'yellow 2' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Yellow 2
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_2" desc="The button label for selecting the 'green 2' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_2" desc="The button label for selecting the 'green 2' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Green 2
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_2" desc="The button label for selecting the 'blue 2' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_2" desc="The button label for selecting the 'cyan 2' color for adding annotation text in the PDF viewer.">
+        Cyan 2
+      </message>
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_2" desc="The button label for selecting the 'blue 2' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Blue 2
       </message>
       <message name="IDS_PDF_INK2_ANNOTATION_COLOR_TAN_2" desc="The button label for selecting the 'tan 2' brush color for drawing strokes in the PDF viewer.">
         Tan 2
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_3" desc="The button label for selecting the 'red 3' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_RED_3" desc="The button label for selecting the 'red 3' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Red 3
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_3" desc="The button label for selecting the 'yellow 3' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_YELLOW_3" desc="The button label for selecting the 'yellow 3' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Yellow 3
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_3" desc="The button label for selecting the 'green 3' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_GREEN_3" desc="The button label for selecting the 'green 3' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Green 3
       </message>
-      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_3" desc="The button label for selecting the 'blue 3' brush color for drawing strokes in the PDF viewer.">
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_3" desc="The button label for selecting the 'cyan 3' color for adding annotation text in the PDF viewer.">
+        Cyan 3
+      </message>
+      <message name="IDS_PDF_INK2_ANNOTATION_COLOR_BLUE_3" desc="The button label for selecting the 'blue 3' color for drawing strokes or for adding annotation text in the PDF viewer.">
         Blue 3
       </message>
       <message name="IDS_PDF_INK2_ANNOTATION_COLOR_TAN_3" desc="The button label for selecting the 'tan 3' brush color for drawing strokes in the PDF viewer.">
         Tan 3
       </message>
+      <message name="IDS_PDF_INK2_TEXT_ANNOTATION" desc="The button label for entering 'text annotation mode' in the PDF viewer, which allows for adding and editing text annotations.">
+        Add text
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_FONT" desc="The dropdown menu and section header text label for selecting the font to be used in a text annotation in the PDF viewer.">
+        Font
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_FONT_SANS_SERIF" desc="The dropdown menu option for using sans serif font in a text annotation in the PDF Viewer.">
+        Sans Serif
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_FONT_SERIF" desc="The dropdown menu option for using serif font in a text annotation in the PDF Viewer.">
+        Serif
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_FONT_MONOSPACE" desc="The dropdown menu option for using monospace font in a text annotation in the PDF Viewer.">
+        Monospace
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_FONT_SIZE" desc="The accessible label for the dropdown menu for selecting font size for a text annotation in the PDF viewer.">
+        Font size
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_STYLES" desc="The section header text for selecting font styles and alignment for a text annotation in the PDF viewer.">
+        Styles
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_STYLE_BOLD" desc="The button label for the toggle button to apply bold font styling to a text annotation in the PDF viewer.">
+        Bold
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_STYLE_ITALIC" desc="The button label for the toggle button to apply bold italic styling to a text annotation in the PDF viewer.">
+        Italic
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_ALIGNMENT" desc="The accessibility label for the group of text alignment options for a text annotation in the PDF viewer. The user can pick one option from the group.">
+        Text alignment
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_ALIGN_LEFT" desc="The button label for the button to align text on the left in a text annotation in the PDF viewer.">
+        Left
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_ALIGN_CENTER" desc="The button label for the button to align text in the center in a text annotation in the PDF viewer.">
+        Center
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_ALIGN_RIGHT" desc="The button label for the button to align text on the right in a text annotation in the PDF viewer.">
+        Right
+      </message>
+      <message name="IDS_PDF_INK2_TEXT_COLOR" desc="The section header and accessibility label for the group of options for selecting a text color for a text annotation in the PDF Viewer.">
+        Text color
+      </message>
     </if>
 
     <message name="IDS_AX_ROLE_DESCRIPTION_PDF_HIGHLIGHT" desc="Accessibility role description for PDF highlight">
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_1.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_1.png.sha1
new file mode 100644
index 0000000..dd41303
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_1.png.sha1
@@ -0,0 +1 @@
+4b7562f69834d2ce056ed0ef0ca7dd804744dbc7
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_2.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_2.png.sha1
new file mode 100644
index 0000000..df667d47
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_2.png.sha1
@@ -0,0 +1 @@
+dbe46671b861eab1ce0aa1e191004b0b71da27bd
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_3.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_3.png.sha1
new file mode 100644
index 0000000..28b3966
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_ANNOTATION_COLOR_CYAN_3.png.sha1
@@ -0,0 +1 @@
+e011298e03e42831513444af3702a15ba1cdfd95
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGNMENT.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGNMENT.png.sha1
new file mode 100644
index 0000000..faab6e8
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGNMENT.png.sha1
@@ -0,0 +1 @@
+0552c068a066a9224110289fa09987885e1f4aa9
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_CENTER.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_CENTER.png.sha1
new file mode 100644
index 0000000..0d5c96c8
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_CENTER.png.sha1
@@ -0,0 +1 @@
+cc118c302598b1c41f3c693f540c8c59851e8e20
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_LEFT.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_LEFT.png.sha1
new file mode 100644
index 0000000..f558072
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_LEFT.png.sha1
@@ -0,0 +1 @@
+48cc813c66aab9d76c04d392ced26f1b3e4e6efc
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_RIGHT.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_RIGHT.png.sha1
new file mode 100644
index 0000000..7143dd2
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ALIGN_RIGHT.png.sha1
@@ -0,0 +1 @@
+2f4ed89ee605d8719e06b22e2fa93d3766a0e6b7
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ANNOTATION.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ANNOTATION.png.sha1
new file mode 100644
index 0000000..190c61a
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_ANNOTATION.png.sha1
@@ -0,0 +1 @@
+9634846a86a2fad66d0f8820189ccc4781f17c5f
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_COLOR.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_COLOR.png.sha1
new file mode 100644
index 0000000..73c1cf0
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_COLOR.png.sha1
@@ -0,0 +1 @@
+53761e178f066ae81710c82409302be7e943618b
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT.png.sha1
new file mode 100644
index 0000000..42080041
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT.png.sha1
@@ -0,0 +1 @@
+37b0857f8d26e63ae3791292fce2f1096ae9fe9c
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_MONOSPACE.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_MONOSPACE.png.sha1
new file mode 100644
index 0000000..665092f
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_MONOSPACE.png.sha1
@@ -0,0 +1 @@
+608fed2a8ca5854fee64294927d85162072ed59e
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SANS_SERIF.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SANS_SERIF.png.sha1
new file mode 100644
index 0000000..1b7e49f
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SANS_SERIF.png.sha1
@@ -0,0 +1 @@
+24d8428cc6669f84a4073c5725064cd0594b3655
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SERIF.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SERIF.png.sha1
new file mode 100644
index 0000000..db91593
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SERIF.png.sha1
@@ -0,0 +1 @@
+3e10dd99bc0c00885c1cf99c4e6e70ee7b1f6654
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SIZE.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SIZE.png.sha1
new file mode 100644
index 0000000..18dfada
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_FONT_SIZE.png.sha1
@@ -0,0 +1 @@
+d8b69ecf75723c0ef415dfb4c10777d033b0e2ae
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLES.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLES.png.sha1
new file mode 100644
index 0000000..7f8b7a74
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLES.png.sha1
@@ -0,0 +1 @@
+8907ae00c00659a76e69f46d27a047eed0888b28
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_BOLD.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_BOLD.png.sha1
new file mode 100644
index 0000000..419427128
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_BOLD.png.sha1
@@ -0,0 +1 @@
+62a3d2014196013144f933e4426376e4f3ffedd5
\ No newline at end of file
diff --git a/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_ITALIC.png.sha1 b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_ITALIC.png.sha1
new file mode 100644
index 0000000..c27ee41
--- /dev/null
+++ b/components/pdf_strings_grdp/IDS_PDF_INK2_TEXT_STYLE_ITALIC.png.sha1
@@ -0,0 +1 @@
+744e61900bb9cd34bbc1dfcdeb1afc18460a5de1
\ No newline at end of file
diff --git a/components/services/storage/BUILD.gn b/components/services/storage/BUILD.gn
index 0a718c1..54cec0b 100644
--- a/components/services/storage/BUILD.gn
+++ b/components/services/storage/BUILD.gn
@@ -57,8 +57,6 @@
     "indexed_db/transactional_leveldb/transactional_leveldb_iterator.h",
     "indexed_db/transactional_leveldb/transactional_leveldb_transaction.cc",
     "indexed_db/transactional_leveldb/transactional_leveldb_transaction.h",
-    "origin_context_impl.cc",
-    "origin_context_impl.h",
     "partition_impl.cc",
     "partition_impl.h",
     "sandboxed_vfs_delegate.cc",
@@ -192,7 +190,6 @@
     "indexed_db/scopes/varint_coding_unittest.cc",
     "indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc",
     "indexed_db/transactional_leveldb/transactional_leveldb_unittest.cc",
-    "partition_impl_unittest.cc",
     "privileged/mojom/bucket_client_info_mojom_traits_unittest.cc",
     "service_worker/service_worker_database_unittest.cc",
     "service_worker/service_worker_disk_cache_unittest.cc",
diff --git a/components/services/storage/origin_context_impl.cc b/components/services/storage/origin_context_impl.cc
deleted file mode 100644
index f061fb6..0000000
--- a/components/services/storage/origin_context_impl.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/services/storage/origin_context_impl.h"
-
-#include "components/services/storage/partition_impl.h"
-
-namespace storage {
-
-OriginContextImpl::OriginContextImpl(PartitionImpl* partition,
-                                     const url::Origin& origin)
-    : partition_(partition), origin_(origin) {
-  receivers_.set_disconnect_handler(base::BindRepeating(
-      &OriginContextImpl::OnDisconnect, base::Unretained(this)));
-}
-
-OriginContextImpl::~OriginContextImpl() = default;
-
-void OriginContextImpl::BindReceiver(
-    mojo::PendingReceiver<mojom::OriginContext> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
-void OriginContextImpl::OnDisconnect() {
-  if (receivers_.empty()) {
-    // Deletes |this|.
-    partition_->RemoveOriginContext(origin_);
-  }
-}
-
-}  // namespace storage
diff --git a/components/services/storage/origin_context_impl.h b/components/services/storage/origin_context_impl.h
deleted file mode 100644
index 50ea4ddf..0000000
--- a/components/services/storage/origin_context_impl.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SERVICES_STORAGE_ORIGIN_CONTEXT_IMPL_H_
-#define COMPONENTS_SERVICES_STORAGE_ORIGIN_CONTEXT_IMPL_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/services/storage/public/mojom/origin_context.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "url/origin.h"
-
-namespace storage {
-
-class PartitionImpl;
-
-class OriginContextImpl : public mojom::OriginContext {
- public:
-  OriginContextImpl(PartitionImpl* partition, const url::Origin& origin);
-
-  OriginContextImpl(const OriginContextImpl&) = delete;
-  OriginContextImpl& operator=(const OriginContextImpl&) = delete;
-
-  ~OriginContextImpl() override;
-
-  const mojo::ReceiverSet<mojom::OriginContext>& receivers() const {
-    return receivers_;
-  }
-
-  void BindReceiver(mojo::PendingReceiver<mojom::OriginContext> receiver);
-
- private:
-  void OnDisconnect();
-
-  const raw_ptr<PartitionImpl> partition_;
-  const url::Origin origin_;
-  mojo::ReceiverSet<mojom::OriginContext> receivers_;
-};
-
-}  // namespace storage
-
-#endif  // COMPONENTS_SERVICES_STORAGE_ORIGIN_CONTEXT_IMPL_H_
diff --git a/components/services/storage/partition_impl.cc b/components/services/storage/partition_impl.cc
index 764189a..a30aff5 100644
--- a/components/services/storage/partition_impl.cc
+++ b/components/services/storage/partition_impl.cc
@@ -8,13 +8,11 @@
 #include <utility>
 
 #include "base/functional/bind.h"
-#include "base/synchronization/waitable_event.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "build/build_config.h"
 #include "components/services/storage/dom_storage/local_storage_impl.h"
 #include "components/services/storage/dom_storage/session_storage_impl.h"
-#include "components/services/storage/service_worker/service_worker_storage_control_impl.h"
 #include "components/services/storage/storage_service_impl.h"
 
 namespace storage {
@@ -65,19 +63,6 @@
   receivers_.Add(this, std::move(receiver));
 }
 
-void PartitionImpl::BindOriginContext(
-    const url::Origin& origin,
-    mojo::PendingReceiver<mojom::OriginContext> receiver) {
-  auto iter = origin_contexts_.find(origin);
-  if (iter == origin_contexts_.end()) {
-    auto result = origin_contexts_.emplace(
-        origin, std::make_unique<OriginContextImpl>(this, origin));
-    iter = result.first;
-  }
-
-  iter->second->BindReceiver(std::move(receiver));
-}
-
 void PartitionImpl::BindSessionStorageControl(
     mojo::PendingReceiver<mojom::SessionStorageControl> receiver) {
   session_storage_ = std::make_unique<SessionStorageImpl>(
@@ -105,13 +90,6 @@
       base::SequencedTaskRunner::GetCurrentDefault(), std::move(receiver));
 }
 
-void PartitionImpl::BindServiceWorkerStorageControl(
-    mojo::PendingReceiver<mojom::ServiceWorkerStorageControl> receiver) {
-  service_worker_storage_ = std::make_unique<ServiceWorkerStorageControlImpl>(
-      path_.value_or(base::FilePath()),
-      std::move(receiver));
-}
-
 void PartitionImpl::OnDisconnect() {
   if (receivers_.empty()) {
     // Deletes |this|.
@@ -119,8 +97,4 @@
   }
 }
 
-void PartitionImpl::RemoveOriginContext(const url::Origin& origin) {
-  origin_contexts_.erase(origin);
-}
-
 }  // namespace storage
diff --git a/components/services/storage/partition_impl.h b/components/services/storage/partition_impl.h
index 0de2215e..6f3443e2 100644
--- a/components/services/storage/partition_impl.h
+++ b/components/services/storage/partition_impl.h
@@ -10,16 +10,13 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/raw_ptr.h"
-#include "components/services/storage/origin_context_impl.h"
 #include "components/services/storage/public/mojom/partition.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
-#include "url/origin.h"
 
 namespace storage {
 
 class LocalStorageImpl;
-class ServiceWorkerStorageControlImpl;
 class SessionStorageImpl;
 class StorageServiceImpl;
 
@@ -43,37 +40,24 @@
     return receivers_;
   }
 
-  const auto& origin_contexts() const { return origin_contexts_; }
-
   // Binds a new client endpoint to this partition.
   void BindReceiver(mojo::PendingReceiver<mojom::Partition> receiver);
 
   // mojom::Partition:
-  void BindOriginContext(
-      const url::Origin& origin,
-      mojo::PendingReceiver<mojom::OriginContext> receiver) override;
   void BindSessionStorageControl(
       mojo::PendingReceiver<mojom::SessionStorageControl> receiver) override;
   void BindLocalStorageControl(
       mojo::PendingReceiver<mojom::LocalStorageControl> receiver) override;
-  void BindServiceWorkerStorageControl(
-      mojo::PendingReceiver<mojom::ServiceWorkerStorageControl> receiver)
-      override;
 
  private:
-  friend class OriginContextImpl;
-
   void OnDisconnect();
-  void RemoveOriginContext(const url::Origin& origin);
 
   const raw_ptr<StorageServiceImpl> service_;
   const std::optional<base::FilePath> path_;
   mojo::ReceiverSet<mojom::Partition> receivers_;
-  std::map<url::Origin, std::unique_ptr<OriginContextImpl>> origin_contexts_;
 
   std::unique_ptr<SessionStorageImpl> session_storage_;
   std::unique_ptr<LocalStorageImpl> local_storage_;
-  std::unique_ptr<ServiceWorkerStorageControlImpl> service_worker_storage_;
 };
 
 }  // namespace storage
diff --git a/components/services/storage/partition_impl_unittest.cc b/components/services/storage/partition_impl_unittest.cc
deleted file mode 100644
index 70eabef..0000000
--- a/components/services/storage/partition_impl_unittest.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/raw_ptr.h"
-#include "components/services/storage/storage_service_impl.h"
-
-#include "base/containers/contains.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "components/services/storage/partition_impl.h"
-#include "components/services/storage/public/mojom/partition.mojom.h"
-#include "components/services/storage/public/mojom/storage_service.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace storage {
-
-class StorageServicePartitionImplTest : public testing::Test {
- public:
-  StorageServicePartitionImplTest() = default;
-
-  StorageServicePartitionImplTest(const StorageServicePartitionImplTest&) =
-      delete;
-  StorageServicePartitionImplTest& operator=(
-      const StorageServicePartitionImplTest&) = delete;
-
-  ~StorageServicePartitionImplTest() override = default;
-
-  void SetUp() override {
-    remote_service_->BindPartition(
-        std::nullopt, remote_test_partition_.BindNewPipeAndPassReceiver());
-    remote_test_partition_.FlushForTesting();
-
-    ASSERT_EQ(1u, service_.partitions().size());
-    test_partition_impl_ = service_.partitions().begin()->get();
-  }
-
- protected:
-  mojom::Partition* remote_test_partition() {
-    return remote_test_partition_.get();
-  }
-  PartitionImpl* test_partition_impl() { return test_partition_impl_; }
-
- private:
-  base::test::TaskEnvironment task_environment_;
-  mojo::Remote<mojom::StorageService> remote_service_;
-  StorageServiceImpl service_{remote_service_.BindNewPipeAndPassReceiver(),
-                              /*io_task_runner=*/nullptr};
-  mojo::Remote<mojom::Partition> remote_test_partition_;
-  raw_ptr<PartitionImpl> test_partition_impl_ = nullptr;
-};
-
-TEST_F(StorageServicePartitionImplTest, IndependentOriginContexts) {
-  // Verifies that clients for unique origins get bound to unique OriginContext
-  // backends.
-
-  const url::Origin kTestOrigin1 =
-      url::Origin::Create(GURL("http://example.com"));
-  mojo::Remote<mojom::OriginContext> context1;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin1, context1.BindNewPipeAndPassReceiver());
-  context1.FlushForTesting();
-  EXPECT_EQ(1u, test_partition_impl()->origin_contexts().size());
-
-  const url::Origin kTestOrigin2 =
-      url::Origin::Create(GURL("https://google.com"));
-  mojo::Remote<mojom::OriginContext> context2;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin2, context2.BindNewPipeAndPassReceiver());
-  context2.FlushForTesting();
-  EXPECT_EQ(2u, test_partition_impl()->origin_contexts().size());
-
-  EXPECT_TRUE(context1.is_connected());
-  EXPECT_TRUE(context2.is_connected());
-
-  // Verify that |context1| was connected to the backend for |kTestOrigin1| by
-  // disconnecting |context1| and waiting for the backend to be destroyed.
-  context1.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(
-      base::Contains(test_partition_impl()->origin_contexts(), kTestOrigin2));
-  EXPECT_FALSE(
-      base::Contains(test_partition_impl()->origin_contexts(), kTestOrigin1));
-
-  // Same for |context2|.
-  context2.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(
-      base::Contains(test_partition_impl()->origin_contexts(), kTestOrigin2));
-}
-
-TEST_F(StorageServicePartitionImplTest, SingleOriginMultipleClients) {
-  // Verifies that multiple clients can bind a connection to the same
-  // OriginContext within a Partition.
-
-  const url::Origin kTestOrigin =
-      url::Origin::Create(GURL("http://example.com"));
-  mojo::Remote<mojom::OriginContext> context1;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin, context1.BindNewPipeAndPassReceiver());
-  context1.FlushForTesting();
-  EXPECT_EQ(1u, test_partition_impl()->origin_contexts().size());
-
-  mojo::Remote<mojom::OriginContext> context2;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin, context2.BindNewPipeAndPassReceiver());
-  context2.FlushForTesting();
-  EXPECT_EQ(1u, test_partition_impl()->origin_contexts().size());
-
-  EXPECT_TRUE(context1.is_connected());
-  EXPECT_TRUE(context2.is_connected());
-}
-
-TEST_F(StorageServicePartitionImplTest,
-       OriginContextDestroyedOnLastClientDisconnect) {
-  const url::Origin kTestOrigin =
-      url::Origin::Create(GURL("http://example.com"));
-  mojo::Remote<mojom::OriginContext> context1;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin, context1.BindNewPipeAndPassReceiver());
-  context1.FlushForTesting();
-
-  mojo::Remote<mojom::OriginContext> context2;
-  remote_test_partition()->BindOriginContext(
-      kTestOrigin, context2.BindNewPipeAndPassReceiver());
-  context2.FlushForTesting();
-
-  EXPECT_EQ(1u, test_partition_impl()->origin_contexts().size());
-
-  context1.reset();
-  context2.reset();
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(0u, test_partition_impl()->origin_contexts().size());
-}
-
-}  // namespace storage
diff --git a/components/services/storage/public/mojom/BUILD.gn b/components/services/storage/public/mojom/BUILD.gn
index 5ddaf56a..3e4f243 100644
--- a/components/services/storage/public/mojom/BUILD.gn
+++ b/components/services/storage/public/mojom/BUILD.gn
@@ -16,7 +16,6 @@
     "cache_storage_control.mojom",
     "file_system_access_context.mojom",
     "local_storage_control.mojom",
-    "origin_context.mojom",
     "partition.mojom",
     "quota_client.mojom",
     "service_worker_database.mojom",
diff --git a/components/services/storage/public/mojom/origin_context.mojom b/components/services/storage/public/mojom/origin_context.mojom
deleted file mode 100644
index 5847e2a7..0000000
--- a/components/services/storage/public/mojom/origin_context.mojom
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module storage.mojom;
-
-// An OriginContext exposes various storage backend interfaces scoped to a
-// single security origin and a single Partition. See
-// |Partition.BindOriginContext()|.
-//
-// It is safe for the browser to broker OriginContext endpoints to the Storage
-// Service if the renderer is known to be rendering content from the relevant
-// origin.
-interface OriginContext {};
diff --git a/components/services/storage/public/mojom/partition.mojom b/components/services/storage/public/mojom/partition.mojom
index 41cb79f..f6d650f 100644
--- a/components/services/storage/public/mojom/partition.mojom
+++ b/components/services/storage/public/mojom/partition.mojom
@@ -5,26 +5,14 @@
 module storage.mojom;
 
 import "components/services/storage/public/mojom/local_storage_control.mojom";
-import "components/services/storage/public/mojom/origin_context.mojom";
-import "components/services/storage/public/mojom/service_worker_storage_control.mojom";
 import "components/services/storage/public/mojom/session_storage_control.mojom";
-import "url/mojom/origin.mojom";
 
 // Partition controls an isolated storage partition owned by the Storage
 // Service. This is analogous to the browser's own storage partition concept.
 interface Partition {
-  // Binds a new OriginContext scoped to |origin| within this Partition.
-  BindOriginContext(url.mojom.Origin origin,
-                    pending_receiver<OriginContext> receiver);
-
   // Binds the main control interface for Session Storage in this partition.
   BindSessionStorageControl(pending_receiver<SessionStorageControl> receiver);
 
   // Binds the main control interface for Local Storage in this partition.
   BindLocalStorageControl(pending_receiver<LocalStorageControl> receiver);
-
-  // Binds the main control interface for Service Worker Storage in this
-  // partition.
-  BindServiceWorkerStorageControl(
-      pending_receiver<ServiceWorkerStorageControl> receiver);
 };
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc
index 7244133d..f2ad524 100644
--- a/components/viz/service/layers/layer_context_impl.cc
+++ b/components/viz/service/layers/layer_context_impl.cc
@@ -255,6 +255,15 @@
   }
   node.blend_mode = static_cast<SkBlendMode>(wire.blend_mode);
   node.target_id = wire.target_id;
+  node.view_transition_target_id = wire.view_transition_target_id;
+  node.closest_ancestor_with_cached_render_surface_id =
+      wire.closest_ancestor_with_cached_render_surface_id;
+  node.closest_ancestor_with_copy_request_id =
+      wire.closest_ancestor_with_copy_request_id;
+  node.closest_ancestor_being_captured_id =
+      wire.closest_ancestor_being_captured_id;
+  node.closest_ancestor_with_shared_element_id =
+      wire.closest_ancestor_with_shared_element_id;
   node.view_transition_element_resource_id =
       wire.view_transition_element_resource_id;
   node.filters = wire.filters;
@@ -676,6 +685,8 @@
     if (!layer) {
       layer = CreateLayer(host_impl, layers, *wire);
     }
+    // TODO(crbug.com/418022040): Make sure we support re-creating Layers with
+    // a previously used Id.
     RETURN_IF_ERROR(UpdateLayer(*wire, *layer));
   }
   for (auto id : *layer_order) {
diff --git a/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_restore_ui/PwaRestoreBottomSheetContent.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_restore_ui/PwaRestoreBottomSheetContent.java
index cbfd9a6..56c51e14 100644
--- a/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_restore_ui/PwaRestoreBottomSheetContent.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_restore_ui/PwaRestoreBottomSheetContent.java
@@ -56,11 +56,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return BottomSheetContent.HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return BottomSheetContent.HeightMode.DISABLED;
     }
diff --git a/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_universal_install/PwaUniversalInstallBottomSheetContent.java b/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_universal_install/PwaUniversalInstallBottomSheetContent.java
index 988b640..0c22333 100644
--- a/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_universal_install/PwaUniversalInstallBottomSheetContent.java
+++ b/components/webapps/browser/android/java/src/org/chromium/components/webapps/pwa_universal_install/PwaUniversalInstallBottomSheetContent.java
@@ -57,11 +57,6 @@
     }
 
     @Override
-    public int getPeekHeight() {
-        return HeightMode.DISABLED;
-    }
-
-    @Override
     public float getHalfHeightRatio() {
         return HeightMode.DISABLED;
     }
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc
index 3459186a..30e3fe9e 100644
--- a/content/browser/child_process_launcher_helper_android.cc
+++ b/content/browser/child_process_launcher_helper_android.cc
@@ -249,19 +249,11 @@
 static jboolean
 JNI_ChildProcessLauncherHelperImpl_ServiceGroupImportanceEnabled(JNIEnv* env) {
   // Not this is called on the launcher thread, not UI thread.
-  //
-  // Note that service grouping is mandatory for site isolation on pre-U devices
-  // to avoid cached process limit. By service grouping, cached chrome renderer
-  // processes in a group are counted as one. On pre-U devices the cached
-  // process limit is usually 32 or such. U+ devices has a larger limit 1024 or
-  // such.
   return (SiteIsolationPolicy::AreIsolatedOriginsEnabled() ||
           SiteIsolationPolicy::UseDedicatedProcessesForAllSites() ||
           SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled() ||
           SiteIsolationPolicy::ArePreloadedIsolatedOriginsEnabled()) &&
-         (base::android::android_info::sdk_int() <
-              base::android::android_info::SDK_VERSION_U ||
-          base::FeatureList::IsEnabled(kServiceGroupImportance));
+         base::FeatureList::IsEnabled(kServiceGroupImportance);
 }
 
 // static
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 6e0a9f8d..db53193 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -593,6 +593,33 @@
   controller_->PendingEntryRefDeleted(this);
 }
 
+// NavigationControllerImpl::ScopedPendingEntryReentrancyGuard------------------
+
+NavigationControllerImpl::ScopedPendingEntryReentrancyGuard::
+    ScopedPendingEntryReentrancyGuard(
+        base::SafeRef<NavigationControllerImpl> controller)
+    : controller_(controller) {
+  // Navigations that involve pending entries do not support re-entrancy.
+  // Encountering this CHECK failure means the caller is attempting to start
+  // another navigation while a navigation to an existing pending entry is on
+  // the stack. In most cases, the new navigation should be done from a posted
+  // task instead. See http://crbug.com/40353566 for context.
+  CHECK(!controller->in_navigate_to_pending_entry_);
+
+  controller->in_navigate_to_pending_entry_ = true;
+  controller->CheckPotentialNavigationReentrancy();
+
+  // It must not be possible to delete the pending NavigationEntry while
+  // navigating to it. Grab a reference to delay potential deletion until
+  // this scoped object is deleted at the end of the relevant function call.
+  pending_entry_ref_ = controller->ReferencePendingEntry();
+}
+
+NavigationControllerImpl::ScopedPendingEntryReentrancyGuard::
+    ~ScopedPendingEntryReentrancyGuard() {
+  controller_->in_navigate_to_pending_entry_ = false;
+}
+
 // NavigationControllerImpl ----------------------------------------------------
 
 const size_t kMaxEntryCountForTestingNotSet = static_cast<size_t>(-1);
@@ -3344,13 +3371,16 @@
       CHECK_EQ(different_document_loads.size(), 1u);
       CHECK(same_document_loads.empty());
       request = different_document_loads.at(0)->GetWeakPtr();
-      // Extend the life time of the pending NavigationEntry since the following
-      // Navigator::Navigate() might clear the pending NavigationEntry, and hit
-      // the CHECK_EQ() in the bottom of Navigator::Navigate().
-      std::unique_ptr<PendingEntryRef> pending_entry_ref =
-          ReferencePendingEntry();
+
+      // Ensure that no re-entrant calls or discards of the pending entry occur
+      // while calling `Navigator::Navigate` for a pending entry.
+      ScopedPendingEntryReentrancyGuard reentrancy_guard(
+          weak_factory_.GetSafeRef());
+
       root->navigator().Navigate(std::move(different_document_loads.at(0)),
                                  ReloadType::NONE);
+
+      // `reentrancy_guard` deleted here.
     } else {
       // The legacy approach creates a new NavigationRequest for the entry and
       // discards any previously created NavigationRequests, even though the new
@@ -3440,10 +3470,10 @@
   SCOPED_CRASH_KEY_NUMBER("nav_reentrancy", "pending_reload_type",
                           (int)pending_reload_);
 
-  // This call does not support re-entrancy.  See http://crbug.com/347742.
-  CHECK(!in_navigate_to_pending_entry_);
-  in_navigate_to_pending_entry_ = true;
-  CheckPotentialNavigationReentrancy();
+  // Ensure that no re-entrant calls or discards of the pending entry occur
+  // while calling `Navigator::Navigate` for a pending entry.
+  ScopedPendingEntryReentrancyGuard reentrancy_guard(
+      weak_factory_.GetSafeRef());
 
   // If the navigation-reentrancy is caused by calling
   // NavigateToExistingPendingEntry twice, this will note the previous call's
@@ -3451,11 +3481,6 @@
   SCOPED_CRASH_KEY_NUMBER("nav_reentrancy", "prev_pending_entry_id",
                           pending_entry_ ? pending_entry_->GetUniqueID() : -1);
 
-  // It is not possible to delete the pending NavigationEntry while navigating
-  // to it. Grab a reference to delay potential deletion until the end of this
-  // function.
-  std::unique_ptr<PendingEntryRef> pending_entry_ref = ReferencePendingEntry();
-
   // If there is a main-frame same-document history navigation, we may defer
   // the subframe history navigations in order to give JS in the main frame the
   // opportunity to cancel the entire traverse via the navigate event. In that
@@ -3520,9 +3545,8 @@
     }
   }
 
-  in_navigate_to_pending_entry_ = false;
-
   return all_requests;
+  // `reentrancy_guard` deleted here.
 }
 
 NavigationControllerImpl::HistoryNavigationAction
@@ -3853,22 +3877,17 @@
   ValidateRequestMatchesEntry(request.get(), pending_entry_);
 #endif
 
-  // This call does not support re-entrancy.  See http://crbug.com/347742.
-  CHECK(!in_navigate_to_pending_entry_);
-  in_navigate_to_pending_entry_ = true;
-  CheckPotentialNavigationReentrancy();
-
-  // It is not possible to delete the pending NavigationEntry while navigating
-  // to it. Grab a reference to delay potential deletion until the end of this
-  // function.
-  std::unique_ptr<PendingEntryRef> pending_entry_ref = ReferencePendingEntry();
+  // Ensure that no re-entrant calls or discards of the pending entry occur
+  // while calling `Navigator::Navigate` for a pending entry.
+  ScopedPendingEntryReentrancyGuard reentrancy_guard(
+      weak_factory_.GetSafeRef());
 
   base::WeakPtr<NavigationHandle> created_navigation_handle(
       request->GetWeakPtr());
   node->navigator().Navigate(std::move(request), reload_type);
 
-  in_navigate_to_pending_entry_ = false;
   return created_navigation_handle;
+  // `reentrancy_guard` deleted here.
 }
 
 FrameTreeNode* NavigationControllerImpl::GetTargetFrameTreeNodeForNavigation(
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 38de957..5fc7c654 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -594,6 +594,24 @@
     const bool was_disallowed_;
   };
 
+  // Navigations to pending entries do not support re-entrancy due to a risk of
+  // use-after-free, and the pending entry itself should not be deleted during
+  // such a navigation. Create one of these scoped objects around calls to
+  // `Navigator::Navigate` when a pending entry is used, to safely crash rather
+  // than risk memory errors if re-entrancy or an unexpected deletion occurs.
+  // See https://crbug.com/40353566 for details.
+  class ScopedPendingEntryReentrancyGuard {
+   public:
+    explicit ScopedPendingEntryReentrancyGuard(
+        base::SafeRef<NavigationControllerImpl> controller);
+    ~ScopedPendingEntryReentrancyGuard();
+
+   private:
+    base::SafeRef<NavigationControllerImpl> controller_;
+    std::unique_ptr<NavigationControllerImpl::PendingEntryRef>
+        pending_entry_ref_;
+  };
+
   // Records which navigation API keys are associated with live frames.
   // On destruction, does a final pass to filter out any keys that are still
   // present in |entries_|, then sends the removed navigation API keys to the
diff --git a/content/common/service_worker/race_network_request_simple_buffer_manager.cc b/content/common/service_worker/race_network_request_simple_buffer_manager.cc
index df5b7f9e..238ac0ee 100644
--- a/content/common/service_worker/race_network_request_simple_buffer_manager.cc
+++ b/content/common/service_worker/race_network_request_simple_buffer_manager.cc
@@ -35,7 +35,7 @@
 
 void RaceNetworkRequestSimpleBufferManager::Clone(
     mojo::ScopedDataPipeProducerHandle producer_handle,
-    base::OnceClosure callback) {
+    base::OnceCallback<void(bool)> callback) {
   CHECK(!producer_handle_.is_valid());
   producer_handle_ = std::move(producer_handle);
   producer_handle_watcher_ = std::make_unique<mojo::SimpleWatcher>(
@@ -59,11 +59,11 @@
   MaybeWriteData();
 }
 
-void RaceNetworkRequestSimpleBufferManager::Finish() {
+void RaceNetworkRequestSimpleBufferManager::Finish(bool success) {
   write_position_ = 0;
   producer_handle_.reset();
   producer_handle_watcher_.reset();
-  std::move(clone_complete_callback_).Run();
+  std::move(clone_complete_callback_).Run(success);
 }
 
 void RaceNetworkRequestSimpleBufferManager::MaybeWriteData() {
@@ -71,7 +71,7 @@
     std::string_view data = GetDataFromBuffer();
     if (data.empty()) {
       if (write_position_ == buffered_body_.size() && drain_complete_) {
-        Finish();
+        Finish(/*success=*/true);
       }
       break;
     }
@@ -89,6 +89,7 @@
         return;
       default:
         // ERROR, disconnect
+        Finish(/*success=*/false);
         return;
     }
   }
diff --git a/content/common/service_worker/race_network_request_simple_buffer_manager.h b/content/common/service_worker/race_network_request_simple_buffer_manager.h
index 052e4b9..b9eda1a 100644
--- a/content/common/service_worker/race_network_request_simple_buffer_manager.h
+++ b/content/common/service_worker/race_network_request_simple_buffer_manager.h
@@ -38,13 +38,13 @@
   // Starts writing the buffered data into `producer_handle`. Run the `callback`
   // after all buffered data is written.
   void Clone(mojo::ScopedDataPipeProducerHandle producer_handle,
-             base::OnceClosure callback);
+             base::OnceCallback<void(bool)> callback);
 
  private:
   void OnWriteAvailable(MojoResult result,
                         const mojo::HandleSignalsState& state);
   void MaybeWriteData();
-  void Finish();
+  void Finish(bool success);
   std::string_view GetDataFromBuffer();
   std::unique_ptr<mojo::DataPipeDrainer> drainer_;
   std::string buffered_body_;
@@ -53,7 +53,7 @@
 
   mojo::ScopedDataPipeProducerHandle producer_handle_;
   std::unique_ptr<mojo::SimpleWatcher> producer_handle_watcher_;
-  base::OnceClosure clone_complete_callback_;
+  base::OnceCallback<void(bool)> clone_complete_callback_;
 
   base::WeakPtrFactory<RaceNetworkRequestSimpleBufferManager> weak_factory_{
       this};
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index b3603592..e2eea4d 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -694,7 +694,13 @@
       std::nullopt);
 }
 
-void ServiceWorkerRaceNetworkRequestURLLoaderClient::OnCloneCompleted() {
+void ServiceWorkerRaceNetworkRequestURLLoaderClient::OnCloneCompleted(
+    bool success) {
+  if (!success) {
+    TransitionState(State::kAborted);
+    Abort();
+    return;
+  }
   if (state_ == State::kCompleted) {
     //  `kCompleted` indicates the network request and data processing to
     //  `owner_` are finished. With
@@ -721,7 +727,7 @@
 }
 
 void ServiceWorkerRaceNetworkRequestURLLoaderClient::
-    OnCloneCompletedForFetchHandler() {
+    OnCloneCompletedForFetchHandler(bool success) {
   clone_response_for_fetch_handler_completed_ = true;
   if (completion_status_.has_value()) {
     // If `completion_status_` already exists, which means the resource load was
diff --git a/content/common/service_worker/race_network_request_url_loader_client.h b/content/common/service_worker/race_network_request_url_loader_client.h
index d21fa0a..6b01febb 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.h
+++ b/content/common/service_worker/race_network_request_url_loader_client.h
@@ -221,8 +221,8 @@
 
   void CloneResponse();
   void CloneResponseForFetchHandler();
-  void OnCloneCompleted();
-  void OnCloneCompletedForFetchHandler();
+  void OnCloneCompleted(bool success);
+  void OnCloneCompletedForFetchHandler(bool success);
 
   State state_ = State::kWaitForBody;
   mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this};
diff --git a/content/common/service_worker/race_network_request_url_loader_client_unittest.cc b/content/common/service_worker/race_network_request_url_loader_client_unittest.cc
index d622448..33ef876a 100644
--- a/content/common/service_worker/race_network_request_url_loader_client_unittest.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client_unittest.cc
@@ -145,7 +145,9 @@
 
   std::string ConsumeChunk() {
     const std::string chunk = chunk_;
-    EXPECT_EQ(body_->EndReadData(chunk_.size()), MOJO_RESULT_OK);
+    MojoResult result = body_->EndReadData(chunk_.size());
+    EXPECT_TRUE(result == MOJO_RESULT_OK ||
+                result == MOJO_RESULT_FAILED_PRECONDITION);
     chunk_ = "";
 
     return chunk;
@@ -290,32 +292,20 @@
   SetUpURLLoaderClient(network::GetDataPipeDefaultAllocationSize());
 
   const std::string kExpectedBody = "abc";
-  WriteData(kExpectedBody);
 
-  base::RunLoop run_loop;
   SetOnCommitResponseCallback(base::BindOnce(
-      [](std::string expected_body,
-         const network::mojom::URLResponseHeadPtr& response_head,
-         mojo::ScopedDataPipeConsumerHandle body) {
-        base::span<const uint8_t> buffer;
-        MojoResult result =
-            body->BeginReadData(MOJO_BEGIN_READ_DATA_FLAG_NONE, buffer);
-        ASSERT_EQ(result, MOJO_RESULT_OK);
-        EXPECT_EQ(base::as_string_view(buffer), expected_body);
-        result = body->EndReadData(buffer.size());
-        ASSERT_EQ(result, MOJO_RESULT_OK);
-      },
-      kExpectedBody));
-  SetOnCompletedCallback(base::BindOnce(
-      [](base::OnceClosure done,
-         scoped_refptr<base::SequencedTaskRunner> task_runner, int error_code,
-         const char* reason) {
-        EXPECT_EQ(error_code, net::OK);
-        task_runner->PostTask(FROM_HERE, std::move(done));
-      },
-      run_loop.QuitClosure(), base::SequencedTaskRunner::GetCurrentDefault()));
+      &ServiceWorkerRaceNetworkRequestURLLoaderClientTest::WatchResponseBody,
+      base::Unretained(this)));
+  SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
+    EXPECT_EQ(error_code, net::OK);
+  }));
+
+  WriteData(kExpectedBody);
   CompleteResponse(net::OK);
-  run_loop.Run();
+
+  RunUntilStateChange(/*resume_state=*/false);
+  EXPECT_EQ(state(), State::kChunkReceived);
+  EXPECT_EQ(ConsumeChunk(), kExpectedBody);
 
   // Check the response for fetch handler
   client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/false);
@@ -330,7 +320,6 @@
   // Expected input size should be larger than the data pipe size.
   const std::string kExpectedBody = "abcdefghijklmnop";
   ASSERT_GT(kExpectedBody.size(), data_pipe_capacity_num_bytes);
-  WriteData(kExpectedBody);
 
   // Set the callback for OnCommitResponse. This callback start watching the
   // response body data pipe.
@@ -342,6 +331,8 @@
   SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
     EXPECT_EQ(error_code, net::OK);
   }));
+
+  WriteData(kExpectedBody);
   CompleteResponse(net::OK);
 
   // Waiting for the first data chunk is received. The first chunk is the
@@ -376,14 +367,13 @@
 }
 
 TEST_F(ServiceWorkerRaceNetworkRequestURLLoaderClientTest,
-       LargeDataOverBufferSize_SlowConsuming) {
+       LargeDataOverBufferSize_ConsumingOrder) {
   const uint32_t data_pipe_capacity_num_bytes = 4;
   SetUpURLLoaderClient(data_pipe_capacity_num_bytes);
 
   // Expected input size should be larger than the data pipe size.
-  const std::string kExpectedBody = "abcdefghijklmnop";
+  const std::string kExpectedBody = "abcdef";
   ASSERT_GT(kExpectedBody.size(), data_pipe_capacity_num_bytes);
-  WriteData(kExpectedBody);
 
   // Set the callback for OnCommitResponse. This callback start watching the
   // response body data pipe.
@@ -395,6 +385,8 @@
   SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
     EXPECT_EQ(error_code, net::OK);
   }));
+
+  WriteData(kExpectedBody);
   CompleteResponse(net::OK);
 
   // Waiting for the first data chunk is received. The first chunk is the
@@ -403,16 +395,11 @@
       kExpectedBody.substr(0, data_pipe_capacity_num_bytes);
   RunUntilStateChange(/*resume_state=*/false);
   EXPECT_EQ(state(), State::kChunkReceived);
-  client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/false);
-  EXPECT_EQ(client_for_fetch_handler()->state(), State::kChunkReceived);
-
-  // Consume the chunk in the data pipe for the fetch handler first to let
-  // ServiceWorkerRaceNetworkRequestURLLoaderClient retry writing to data pipes
-  // by getting |MOJO_RESULT_SHOULD_WAIT|.
-  EXPECT_EQ(client_for_fetch_handler()->ConsumeChunk(), first_chunk);
-  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(ConsumeChunk(), first_chunk);
 
+  // The client for the fetch handler is not ready yet.
+  EXPECT_EQ(client_for_fetch_handler()->state(), State::kWaiting);
+
   // Consume the second chunk.
   const std::string second_chunk = kExpectedBody.substr(
       data_pipe_capacity_num_bytes, data_pipe_capacity_num_bytes);
@@ -420,8 +407,12 @@
   EXPECT_EQ(state(), State::kChunkReceived);
   EXPECT_EQ(ConsumeChunk(), second_chunk);
   base::RunLoop().RunUntilIdle();
-  client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/true);
-  EXPECT_EQ(client_for_fetch_handler()->ConsumeChunk(), second_chunk);
+
+  // After the whole data is processed, the client for the fetch handler will be
+  // ready.
+  client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/false);
+  EXPECT_EQ(client_for_fetch_handler()->state(), State::kChunkReceived);
+  EXPECT_EQ(client_for_fetch_handler()->ConsumeChunk(), first_chunk);
 }
 
 TEST_F(ServiceWorkerRaceNetworkRequestURLLoaderClientTest,
@@ -432,7 +423,6 @@
   // Expected input size should be larger than the data pipe size.
   const std::string kExpectedBody = "abcdefghijklmnopqrstu";
   ASSERT_GT(kExpectedBody.size(), data_pipe_capacity_num_bytes);
-  WriteData(kExpectedBody);
 
   // Set the callback for OnCommitResponse. This callback start watching the
   // response body data pipe.
@@ -444,22 +434,23 @@
   SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
     EXPECT_EQ(error_code, net::OK);
   }));
+
+  WriteData(kExpectedBody);
   CompleteResponse(net::OK);
 
   // Waiting for the first data chunk is received.
   RunUntilStateChange(/*resume_state=*/false);
   EXPECT_EQ(state(), State::kChunkReceived);
-  client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/false);
-  EXPECT_EQ(client_for_fetch_handler()->state(), State::kChunkReceived);
 
   // Abort the consumer handle after the first data chunk has arrived.
+  ConsumeChunk();
   AbortBodyConsumerHandle();
+  base::RunLoop().RunUntilIdle();
 
   // Once the data pipe for RaceNetworkRequest is closed, the fetch handler side
   // data pipe is also closed.
-  client_for_fetch_handler()->ConsumeChunk();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(client_for_fetch_handler()->IsDisconnected());
+  EXPECT_EQ(client_state(),
+            ServiceWorkerRaceNetworkRequestURLLoaderClient::State::kAborted);
 }
 
 TEST_F(ServiceWorkerRaceNetworkRequestURLLoaderClientTest,
@@ -467,10 +458,7 @@
   const uint32_t data_pipe_capacity_num_bytes = 8;
   SetUpURLLoaderClient(data_pipe_capacity_num_bytes);
 
-  // Expected input size should be larger than the data pipe size.
-  const std::string kExpectedBody = "abcdefghijklmnopqrstu";
-  ASSERT_GT(kExpectedBody.size(), data_pipe_capacity_num_bytes);
-  WriteData(kExpectedBody);
+  const std::string kExpectedBody = "abcde";
 
   // Set the callback for OnCommitResponse. This callback start watching the
   // response body data pipe.
@@ -482,21 +470,27 @@
   SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
     EXPECT_EQ(error_code, net::OK);
   }));
+
+  WriteData(kExpectedBody);
   CompleteResponse(net::OK);
 
+  // Consume the whole data for the network request.
+  RunUntilStateChange(/*resume_state=*/false);
+  EXPECT_EQ(state(), State::kChunkReceived);
+  ConsumeChunk();
+
   // Waiting for the first data chunk is received.
   client_for_fetch_handler()->RunUntilStateChange(/*resume_state=*/false);
   EXPECT_EQ(client_for_fetch_handler()->state(), State::kChunkReceived);
-  RunUntilStateChange(/*resume_state=*/false);
-  EXPECT_EQ(state(), State::kChunkReceived);
 
   // Abort the consumer handle after the first data chunk has arrived.
   client_for_fetch_handler()->AbortBodyConsumerHandle();
+  base::RunLoop().RunUntilIdle();
 
-  // Once the data pipe for RaceNetworkRequest is closed, the fetch handler side
-  // data pipe is also closed.
-  ConsumeChunk();
-  EXPECT_TRUE(IsDisconnected());
+  // Since the network request is finished successfully, the state is already
+  // set as completed.
+  EXPECT_EQ(client_state(),
+            ServiceWorkerRaceNetworkRequestURLLoaderClient::State::kCompleted);
 }
 
 TEST_F(ServiceWorkerRaceNetworkRequestURLLoaderClientTest,
@@ -507,11 +501,20 @@
   const std::string kExpectedBody = "abcdefghijklmnopqrstu";
   ASSERT_GT(kExpectedBody.size(), data_pipe_capacity_num_bytes);
 
+  SetOnCommitResponseCallback(base::BindOnce(
+      &ServiceWorkerRaceNetworkRequestURLLoaderClientTest::WatchResponseBody,
+      base::Unretained(this)));
+
   // Set the callback for the commit completion.
   SetOnCompletedCallback(base::BindOnce([](int error_code, const char* reason) {
     EXPECT_EQ(error_code, net::ERR_FAILED);
   }));
 
+  // Set kWithoutServiceWorker. This imitates the fetch handler fallback case.
+  owner()->SetCommitResponsibility(
+      ServiceWorkerRaceNetworkRequestURLLoaderClient::FetchResponseFrom::
+          kWithoutServiceWorker);
+
   // |client_| receives the response and expect |state_| is changed to
   // kResponseReceived.
   WriteData(kExpectedBody);
@@ -519,11 +522,6 @@
       client_state(),
       ServiceWorkerRaceNetworkRequestURLLoaderClient::State::kResponseReceived);
 
-  // Set kWithoutServiceWorker. This imitates the fetch handler fallback case.
-  owner()->SetCommitResponsibility(
-      ServiceWorkerRaceNetworkRequestURLLoaderClient::FetchResponseFrom::
-          kWithoutServiceWorker);
-
   // |client_| suddenly receives the network error, and expect |state_| is
   // changed to kCompleted directly from kResponseReceived.
   CompleteResponse(net::ERR_FAILED);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index b666d39..581513f 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -943,7 +943,7 @@
 BASE_FEATURE(
     kServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement,
     "ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement",
-    base::FEATURE_DISABLED_BY_DEFAULT);
+    base::FEATURE_ENABLED_BY_DEFAULT);
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 // Run video capture service in the Browser process as opposed to a dedicated
diff --git a/device/gamepad/xbox_hid_controller.cc b/device/gamepad/xbox_hid_controller.cc
index fb7be7b..fc688b5 100644
--- a/device/gamepad/xbox_hid_controller.cc
+++ b/device/gamepad/xbox_hid_controller.cc
@@ -44,9 +44,9 @@
   control_report[0] = 0x03;  // report ID
   control_report[1] = 0x0f;  // enable rumble motors, enable trigger haptics
   control_report[2] =
-      static_cast<uint8_t>(params->right_trigger * kRumbleMagnitudeMax);
-  control_report[3] =
       static_cast<uint8_t>(params->left_trigger * kRumbleMagnitudeMax);
+  control_report[3] =
+      static_cast<uint8_t>(params->right_trigger * kRumbleMagnitudeMax);
   control_report[4] =
       static_cast<uint8_t>(params->strong_magnitude * kRumbleMagnitudeMax);
   control_report[5] =
diff --git a/device/gamepad/xbox_hid_controller_unittest.cc b/device/gamepad/xbox_hid_controller_unittest.cc
index 5147a31..f9610d0 100644
--- a/device/gamepad/xbox_hid_controller_unittest.cc
+++ b/device/gamepad/xbox_hid_controller_unittest.cc
@@ -36,8 +36,8 @@
 
 constexpr uint8_t kStartVibration[] = {0x03,  // report ID
                                        0x0f,
-                                       0x7f,  // left trigger
-                                       0xff,  // right trigger
+                                       0xff,  // left trigger
+                                       0x7f,  // right trigger
                                        0xff,  // strong magnitude
                                        0x7f,  // weak magnitude
                                        0xff, 0x00, 0x01};
diff --git a/extensions/OWNERS b/extensions/OWNERS
index 495ad63..3170678 100644
--- a/extensions/OWNERS
+++ b/extensions/OWNERS
@@ -15,6 +15,7 @@
 dbertoni@chromium.org
 emiliapaz@chromium.org
 finnur@chromium.org
+jamescook@chromium.org
 reillyg@chromium.org
 
 # Translation artifacts:
diff --git a/extensions/browser/api/declarative/rules_registry_service.cc b/extensions/browser/api/declarative/rules_registry_service.cc
index f715565..df5dc12f 100644
--- a/extensions/browser/api/declarative/rules_registry_service.cc
+++ b/extensions/browser/api/declarative/rules_registry_service.cc
@@ -49,18 +49,8 @@
     registry->OnShutdown();
   }
 
-  // Release the references to all registries, and remove the default registry
-  // from ExtensionWebRequestEventRouter.
+  // Release the references to all registries.
   rule_registries_.clear();
-  // TODO(crbug.com/40264286): This could be moved to
-  // WebRequestEventRouter::Shutdown when the new per-BrowserContext event
-  // router is the only implementation. Or we might just remove it completely,
-  // since that instance will be destroyed when this RulesRegistryService
-  // instance is.
-  WebRequestEventRouter::Get(browser_context_)
-      ->RegisterRulesRegistry(browser_context_,
-                              rules_registry_ids::kDefaultRulesRegistryID,
-                              nullptr);
 }
 
 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService>>::
diff --git a/extensions/browser/service_worker/service_worker_state.cc b/extensions/browser/service_worker/service_worker_state.cc
index e5df22c..2118c99b 100644
--- a/extensions/browser/service_worker/service_worker_state.cc
+++ b/extensions/browser/service_worker/service_worker_state.cc
@@ -4,21 +4,21 @@
 
 #include "extensions/browser/service_worker/service_worker_state.h"
 
+#include "base/metrics/histogram_macros.h"
 #include "extensions/browser/process_manager.h"
 
 namespace extensions {
 
+namespace {
+
+// Prevent check on multiple workers per extension for testing purposes.
+bool g_allow_multiple_workers_per_extension = false;
+
+}  // namespace
+
 ServiceWorkerState::ServiceWorkerState() = default;
 ServiceWorkerState::~ServiceWorkerState() = default;
 
-void ServiceWorkerState::SetWorkerId(const WorkerId& worker_id) {
-  if (worker_id_ && *worker_id_ != worker_id) {
-    // Clear stale renderer state if there's any.
-    renderer_state_ = RendererState::kNotActive;
-  }
-  worker_id_ = worker_id;
-}
-
 void ServiceWorkerState::SetBrowserState(BrowserState browser_state) {
   browser_state_ = browser_state;
 }
@@ -38,4 +38,53 @@
          renderer_state_ == RendererState::kActive && worker_id_.has_value();
 }
 
+void ServiceWorkerState::SetWorkerId(const WorkerId& worker_id,
+                                     const ProcessManager* process_manager) {
+  if (worker_id_ && *worker_id_ != worker_id) {
+    // Sanity check that the old worker is gone.
+    // TODO(crbug.com/40936639): remove
+    // `g_allow_multiple_workers_per_extension` once bug is fixed so that this
+    // DCHECK() will be default behavior everywhere. Also upgrade to a CHECK
+    // once the bug is completely fixed.
+    DCHECK(!process_manager->HasServiceWorker(*worker_id_) ||
+           g_allow_multiple_workers_per_extension);
+
+    // Clear stale renderer state if there's any.
+    renderer_state_ = RendererState::kNotActive;
+  }
+
+  worker_id_ = worker_id;
+}
+
+void ServiceWorkerState::DidStartServiceWorkerContext(
+    const WorkerId& worker_id,
+    const ProcessManager* process_manager) {
+  DCHECK_NE(RendererState::kActive, renderer_state())
+      << "Worker already started";
+  SetWorkerId(worker_id, process_manager);
+  SetRendererState(RendererState::kActive);
+}
+
+void ServiceWorkerState::DidStartWorkerForScope(
+    const WorkerId& worker_id,
+    base::Time start_time,
+    const ProcessManager* process_manager) {
+  UMA_HISTOGRAM_BOOLEAN("Extensions.ServiceWorkerBackground.StartWorkerStatus",
+                        true);
+  UMA_HISTOGRAM_TIMES("Extensions.ServiceWorkerBackground.StartWorkerTime",
+                      base::Time::Now() - start_time);
+
+  DCHECK_NE(BrowserState::kStarted, browser_state())
+      << "Worker was already loaded";
+
+  SetWorkerId(worker_id, process_manager);
+  SetBrowserState(BrowserState::kStarted);
+}
+
+// static
+base::AutoReset<bool>
+ServiceWorkerState::AllowMultipleWorkersPerExtensionForTesting() {
+  return base::AutoReset<bool>(&g_allow_multiple_workers_per_extension, true);
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/service_worker/service_worker_state.h b/extensions/browser/service_worker/service_worker_state.h
index 5203beb..2eaed445 100644
--- a/extensions/browser/service_worker/service_worker_state.h
+++ b/extensions/browser/service_worker/service_worker_state.h
@@ -7,9 +7,12 @@
 
 #include <optional>
 
+#include "base/auto_reset.h"
+#include "base/time/time.h"
 #include "extensions/browser/service_worker/worker_id.h"
 
 namespace extensions {
+class ProcessManager;
 
 // The current worker related state of an activated extension.
 class ServiceWorkerState {
@@ -41,18 +44,36 @@
   ServiceWorkerState(const ServiceWorkerState&) = delete;
   ServiceWorkerState& operator=(const ServiceWorkerState&) = delete;
 
-  void SetWorkerId(const WorkerId& worker_id);
   void SetBrowserState(BrowserState browser_state);
   void SetRendererState(RendererState renderer_state);
   void Reset();
 
   bool IsReady() const;
 
+  // Called when a service worker renderer process is running, has executed its
+  // global JavaScript scope, and all its global event listeners have been
+  // registered with the //extensions layer. It is considered the
+  // "renderer-side" signal that the worker is ready.
+  void DidStartServiceWorkerContext(const WorkerId& worker_id,
+                                    const ProcessManager* process_manager);
+
+  // Called when the worker was requested to start and it verified that a worker
+  // registration exists at the //content layer. It is considered the
+  // "browser-side" signal that the worker is ready.
+  void DidStartWorkerForScope(const WorkerId& worker_id,
+                              base::Time start_time,
+                              const ProcessManager* process_manager);
+
   BrowserState browser_state() const { return browser_state_; }
   RendererState renderer_state() const { return renderer_state_; }
   const std::optional<WorkerId>& worker_id() const { return worker_id_; }
 
+  static base::AutoReset<bool> AllowMultipleWorkersPerExtensionForTesting();
+
  private:
+  void SetWorkerId(const WorkerId& worker_id,
+                   const ProcessManager* process_manager);
+
   BrowserState browser_state_ = BrowserState::kNotStarted;
   RendererState renderer_state_ = RendererState::kNotActive;
 
diff --git a/extensions/browser/service_worker/service_worker_task_queue.cc b/extensions/browser/service_worker/service_worker_task_queue.cc
index 1c06521..834a792 100644
--- a/extensions/browser/service_worker/service_worker_task_queue.cc
+++ b/extensions/browser/service_worker/service_worker_task_queue.cc
@@ -66,26 +66,6 @@
 
 ServiceWorkerTaskQueue::TestObserver* g_test_observer = nullptr;
 
-// Prevent check on multiple workers per extension for testing purposes.
-bool g_allow_multiple_workers_per_extension = false;
-
-// Wrapper around `ServiceWorkerState->SetWorkerId` with additional check
-// against `g_allow_multiple_workers_per_extension`. See crbug.com/40936639.
-void SetWorkerId(ServiceWorkerState* worker_state,
-                 const WorkerId& worker_id,
-                 const ProcessManager* process_manager) {
-  if (worker_state->worker_id() && *worker_state->worker_id() != worker_id) {
-    // Sanity check that the old worker is gone.
-    // TODO(crbug.com/40936639): remove
-    // `g_allow_multiple_workers_per_extension` once bug is fixed so that this
-    // DCHECK() will be default behavior everywhere. Also upgrade to a CHECK
-    // once the bug is completely fixed.
-    DCHECK(!process_manager->HasServiceWorker(*worker_state->worker_id()) ||
-           g_allow_multiple_workers_per_extension);
-  }
-  worker_state->SetWorkerId(worker_id);
-}
-
 }  // namespace
 
 ServiceWorkerTaskQueue::ServiceWorkerTaskQueue(BrowserContext* browser_context)
@@ -141,15 +121,6 @@
     return;
   }
 
-  UMA_HISTOGRAM_BOOLEAN("Extensions.ServiceWorkerBackground.StartWorkerStatus",
-                        true);
-  UMA_HISTOGRAM_TIMES("Extensions.ServiceWorkerBackground.StartWorkerTime",
-                      base::Time::Now() - start_time);
-
-  ServiceWorkerState* worker_state = GetWorkerState(context_id);
-  DCHECK(worker_state);
-  const WorkerId worker_id = {extension_id, process_id, version_id, thread_id};
-
   // Note: If the worker has already stopped on worker thread
   // (DidStopServiceWorkerContext) before we got here (i.e. the browser has
   // finished starting the worker), then |worker_state_map_| will hold the
@@ -158,12 +129,11 @@
   // renderer before we execute tasks in the browser process. This will also
   // avoid holding the worker in |worker_state_map_| until deactivation as noted
   // above.
-  DCHECK_NE(ServiceWorkerState::BrowserState::kStarted,
-            worker_state->browser_state())
-      << "Worker was already loaded";
-  SetWorkerId(worker_state, worker_id, ProcessManager::Get(browser_context_));
-  worker_state->SetBrowserState(ServiceWorkerState::BrowserState::kStarted);
-
+  const WorkerId worker_id = {extension_id, process_id, version_id, thread_id};
+  ServiceWorkerState* worker_state = GetWorkerState(context_id);
+  DCHECK(worker_state);
+  worker_state->DidStartWorkerForScope(worker_id, start_time,
+                                       ProcessManager::Get(browser_context_));
   RunPendingTasksIfWorkerReady(context_id);
 }
 
@@ -275,18 +245,13 @@
 
   const SequencedContextId context_id = {
       extension_id, browser_context_->UniqueId(), activation_token};
-
   const WorkerId worker_id = {extension_id, render_process_id,
                               service_worker_version_id, thread_id};
   ServiceWorkerState* worker_state = GetWorkerState(context_id);
   DCHECK(worker_state);
-  DCHECK_NE(ServiceWorkerState::RendererState::kActive,
-            worker_state->renderer_state())
-      << "Worker already started";
 
-  SetWorkerId(worker_state, worker_id, ProcessManager::Get(browser_context_));
-  worker_state->SetRendererState(ServiceWorkerState::RendererState::kActive);
-
+  worker_state->DidStartServiceWorkerContext(
+      worker_id, ProcessManager::Get(browser_context_));
   RunPendingTasksIfWorkerReady(context_id);
 }
 
@@ -1145,12 +1110,6 @@
   return tasks ? tasks->size() : 0;
 }
 
-// static
-base::AutoReset<bool>
-ServiceWorkerTaskQueue::AllowMultipleWorkersPerExtensionForTesting() {
-  return base::AutoReset<bool>(&g_allow_multiple_workers_per_extension, true);
-}
-
 const ServiceWorkerState* ServiceWorkerTaskQueue::GetWorkerState(
     const SequencedContextId& context_id) const {
   return base::FindOrNull(worker_state_map_, context_id);
diff --git a/extensions/browser/service_worker/service_worker_task_queue.h b/extensions/browser/service_worker/service_worker_task_queue.h
index f25a9725..9e9df774 100644
--- a/extensions/browser/service_worker/service_worker_task_queue.h
+++ b/extensions/browser/service_worker/service_worker_task_queue.h
@@ -10,7 +10,6 @@
 #include <string>
 #include <vector>
 
-#include "base/auto_reset.h"
 #include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -374,8 +373,6 @@
     return GetWorkerState(context_id);
   }
 
-  static base::AutoReset<bool> AllowMultipleWorkersPerExtensionForTesting();
-
  private:
   enum class RegistrationReason {
     REGISTER_ON_EXTENSION_LOAD,
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
index e3b8b11..a56739d1 100644
--- a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
@@ -9,6 +9,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.android_browsertests.filter",
           "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
@@ -59,6 +60,7 @@
         "args": [
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gtest_filter=-org.chromium.chrome.browser.ui.appmenu.AppMenuTest.testShowAppMenu_AnchorTop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -113,6 +115,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
@@ -159,6 +162,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.unit_tests.filter",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
index b8d1860..e3a063de 100644
--- a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
@@ -4,6 +4,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.android_browsertests.filter",
           "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
@@ -54,6 +55,7 @@
         "args": [
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gtest_filter=-org.chromium.chrome.browser.ui.appmenu.AppMenuTest.testShowAppMenu_AnchorTop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -108,6 +110,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
@@ -154,6 +157,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.unit_tests.filter",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
index e3b8b11..a56739d1 100644
--- a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
@@ -9,6 +9,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.android_browsertests.filter",
           "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
@@ -59,6 +60,7 @@
         "args": [
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gtest_filter=-org.chromium.chrome.browser.ui.appmenu.AppMenuTest.testShowAppMenu_AnchorTop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -113,6 +115,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
@@ -159,6 +162,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.unit_tests.filter",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
index e3b8b11..a56739d1 100644
--- a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
@@ -9,6 +9,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.android_browsertests.filter",
           "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
@@ -59,6 +60,7 @@
         "args": [
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gtest_filter=-org.chromium.chrome.browser.ui.appmenu.AppMenuTest.testShowAppMenu_AnchorTop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -113,6 +115,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
@@ -159,6 +162,7 @@
       {
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_tablet_x64_tablet_landscape.textpb",
+          "--force-android-desktop",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.desktop.emulator_15.unit_tests.filter",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index e0f5e68..c2835559e 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -632,6 +632,7 @@
   * [`//third_party/ruy/.+`](https://cs.chromium.org/chromium/src/third_party/ruy/)
   * [`//third_party/tflite/.+`](https://cs.chromium.org/chromium/src/third_party/tflite/)
   * [`//third_party/xnnpack/.+`](https://cs.chromium.org/chromium/src/third_party/xnnpack/)
+  * [`//third_party/protobuf/src/.+`](https://cs.chromium.org/chromium/src/third_party/protobuf/src/)
 
 * [linux_chromium_dbg_ng](https://ci.chromium.org/p/chromium/builders/try/linux_chromium_dbg_ng) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux_chromium_dbg_ng""))
 
diff --git a/infra/config/generated/cq-usage/full.cfg b/infra/config/generated/cq-usage/full.cfg
index 13849dc..954a232 100644
--- a/infra/config/generated/cq-usage/full.cfg
+++ b/infra/config/generated/cq-usage/full.cfg
@@ -3549,6 +3549,12 @@
           gerrit_host_regexp: ".*"
           gerrit_project_regexp: ".*"
           gerrit_ref_regexp: ".*"
+          path_regexp: "third_party/protobuf/src/.+"
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          gerrit_ref_regexp: ".*"
           path_regexp: "infra/config/.+"
           exclude: true
         }
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 3111638..fd59fd3 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -5867,6 +5867,12 @@
           gerrit_host_regexp: ".*"
           gerrit_project_regexp: ".*"
           gerrit_ref_regexp: ".*"
+          path_regexp: "third_party/protobuf/src/.+"
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          gerrit_ref_regexp: ".*"
           path_regexp: "infra/config/.+"
           exclude: true
         }
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.desktop.star b/infra/config/subprojects/chromium/ci/chromium.android.desktop.star
index fb2baf0..7a2964f 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.desktop.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.desktop.star
@@ -264,6 +264,7 @@
                 mixins = [
                     "15-desktop-x64-emulator",
                     "emulator-8-cores",
+                    "force-android-desktop",
                 ],
             ),
         ],
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index f70002d..cbc4b99 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -759,6 +759,9 @@
             "third_party/ruy/.+",
             "third_party/tflite/.+",
             "third_party/xnnpack/.+",
+            # Diectories that have caused breakages in the past due to the
+            # protobuf roll.
+            "third_party/protobuf/src/.+",
         ],
     ),
 )
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star
index 4186c50..32081af6 100644
--- a/infra/config/targets/mixins.star
+++ b/infra/config/targets/mixins.star
@@ -752,6 +752,14 @@
 )
 
 targets.mixin(
+    name = "force-android-desktop",
+    generate_pyl_entry = False,
+    args = [
+        "--force-android-desktop",
+    ],
+)
+
+targets.mixin(
     name = "fuchsia-code-coverage",
     generate_pyl_entry = False,
     args = [
diff --git a/internal b/internal
index ceb7c2b..4611c08 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit ceb7c2b2a31d272f5dae507665b9a1f891f8676d
+Subproject commit 4611c0803480dede3396370ade3f85c313348f8a
diff --git a/media/gpu/windows/supported_profile_helpers.cc b/media/gpu/windows/supported_profile_helpers.cc
index 1814b07..1fd9877 100644
--- a/media/gpu/windows/supported_profile_helpers.cc
+++ b/media/gpu/windows/supported_profile_helpers.cc
@@ -347,8 +347,9 @@
         // is 12-bit. However we don't know the bit depth or pixel format until
         // too late. In these cases we'll end up initializing the decoder and
         // failing on the first decode (which will trigger software fallback).
-        supported_resolutions[AV1PROFILE_PROFILE_PRO] = GetResolutionsForGUID(
-            video_device_wrapper, profile_id, kModernResolutions);
+        supported_resolutions[AV1PROFILE_PROFILE_PRO] =
+            GetResolutionsForGUID(video_device_wrapper, profile_id,
+                                  kModernResolutions, DXGI_FORMAT_YUY2);
         continue;
       }
     }
@@ -380,6 +381,12 @@
       if (profile_id == D3D11_DECODER_PROFILE_HEVC_VLD_MAIN) {
         auto supported_resolution = GetResolutionsForGUID(
             video_device_wrapper, profile_id, kModernResolutions);
+
+        if (supported_resolution.max_landscape_resolution.IsEmpty()) {
+          supported_resolution = GetResolutionsForGUID(
+              video_device_wrapper, profile_id, {gfx::Size(1920, 1080)});
+        }
+
         supported_resolutions[HEVCPROFILE_MAIN] = supported_resolution;
         supported_resolutions[HEVCPROFILE_MAIN_STILL_PICTURE] =
             supported_resolution;
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 6adc737..a3722eb5 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -1527,6 +1527,7 @@
 void AudioRendererImpl::EnableSpeechRecognition() {
 #if !BUILDFLAG(IS_ANDROID)
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  MEDIA_LOG(INFO, media_log_) << "Enabling transcription.";
   transcribe_audio_callback_ = base::BindRepeating(
       &AudioRendererImpl::TranscribeAudio, weak_factory_.GetWeakPtr());
 #endif
diff --git a/net/cert/ct_log_verifier_unittest.cc b/net/cert/ct_log_verifier_unittest.cc
index 3f49082..4d436e0 100644
--- a/net/cert/ct_log_verifier_unittest.cc
+++ b/net/cert/ct_log_verifier_unittest.cc
@@ -13,6 +13,7 @@
 
 #include <algorithm>
 #include <array>
+#include <bit>
 #include <memory>
 #include <string>
 #include <vector>
@@ -33,18 +34,6 @@
 
 namespace {
 
-// Calculate the power of two nearest to, but less than, |n|.
-// |n| must be at least 2.
-size_t CalculateNearestPowerOfTwo(size_t n) {
-  DCHECK_GT(n, 1u);
-
-  size_t ret = size_t(1) << (sizeof(size_t) * 8 - 1);
-  while (ret >= n)
-    ret >>= 1;
-
-  return ret;
-}
-
 // All test data replicated from
 // https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc
 
@@ -615,7 +604,7 @@
     return HashLeaf(leaves[0]);
 
   // Find the index of the last leaf in the left sub-tree.
-  const size_t split = CalculateNearestPowerOfTwo(tree_size);
+  const size_t split = std::bit_floor(tree_size - 1);
 
   // Hash the left and right sub-trees, then hash the results.
   return ct::internal::HashNodes(HashTree(leaves, split),
@@ -636,7 +625,7 @@
     return proof;
 
   // Find the index of the first leaf in the right sub-tree.
-  const size_t split = CalculateNearestPowerOfTwo(tree_size);
+  const size_t split = std::bit_floor(tree_size - 1);
 
   // Recurse down the correct branch of the tree (left or right) to reach the
   // leaf with |leaf_index|. Add the hash of the branch not taken at each step
@@ -677,7 +666,7 @@
   }
 
   // Find the index of the last leaf in the left sub-tree.
-  const size_t split = CalculateNearestPowerOfTwo(new_tree_size);
+  const size_t split = std::bit_floor(new_tree_size - 1);
 
   if (old_tree_size <= split) {
     // Root of the old tree is in the left subtree of the new tree.
diff --git a/net/cert/known_roots_unittest.cc b/net/cert/known_roots_unittest.cc
index cfec6f0b3..70274580 100644
--- a/net/cert/known_roots_unittest.cc
+++ b/net/cert/known_roots_unittest.cc
@@ -2,17 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "net/cert/known_roots.h"
 
-#include <string.h>
-
 #include <algorithm>
+#include <iterator>
 
+#include "base/containers/span.h"
 #include "net/base/hash_value.h"
 #include "net/cert/root_cert_list_generated.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,7 +20,10 @@
   EXPECT_TRUE(std::is_sorted(
       std::begin(kRootCerts), std::end(kRootCerts),
       [](const RootCertData& lhs, const RootCertData& rhs) {
-        return memcmp(lhs.sha256_spki_hash, rhs.sha256_spki_hash, 32) < 0;
+        auto lhs_span = base::as_byte_span(lhs.sha256_spki_hash);
+        auto rhs_span = base::as_byte_span(rhs.sha256_spki_hash);
+        return std::lexicographical_compare(lhs_span.begin(), lhs_span.end(),
+                                            rhs_span.begin(), rhs_span.end());
       }));
 }
 
diff --git a/net/cert/merkle_tree_leaf_unittest.cc b/net/cert/merkle_tree_leaf_unittest.cc
index 078391b..d17529b 100644
--- a/net/cert/merkle_tree_leaf_unittest.cc
+++ b/net/cert/merkle_tree_leaf_unittest.cc
@@ -2,17 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "net/cert/merkle_tree_leaf.h"
 
-#include <string.h>
-
+#include <algorithm>
 #include <string>
+#include <vector>
 
+#include "base/containers/span.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
@@ -44,7 +41,8 @@
 
   // Print hex string (easier to read than default GTest representation)
   *result_listener << "a.k.a. 0x" << base::HexEncode(arg.data(), arg.size());
-  return memcmp(arg.data(), bytes.data(), bytes.size()) == 0;
+  return std::ranges::equal(base::as_byte_span(arg),
+                            base::span<const uint8_t>(bytes));
 }
 
 class MerkleTreeLeafTest : public ::testing::Test {
diff --git a/net/cert/signed_tree_head.cc b/net/cert/signed_tree_head.cc
index db0931b..1d725f5 100644
--- a/net/cert/signed_tree_head.cc
+++ b/net/cert/signed_tree_head.cc
@@ -2,35 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "net/cert/signed_tree_head.h"
 
-#include <string.h>
-
+#include <algorithm>
 #include <ostream>
+#include <string>
+#include <tuple>
 
+#include "base/containers/span.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
 
 namespace net::ct {
 
 SignedTreeHead::SignedTreeHead() = default;
 
-SignedTreeHead::SignedTreeHead(Version version,
-                               const base::Time& timestamp,
-                               uint64_t tree_size,
-                               const char sha256_root_hash[kSthRootHashLength],
-                               const DigitallySigned& signature,
-                               const std::string& log_id)
+SignedTreeHead::SignedTreeHead(
+    Version version,
+    const base::Time& timestamp,
+    uint64_t tree_size,
+    base::span<const uint8_t, kSthRootHashLength> sha256_root_hash,
+    const DigitallySigned& signature,
+    const std::string& log_id)
     : version(version),
       timestamp(timestamp),
       tree_size(tree_size),
       signature(signature),
       log_id(log_id) {
-  memcpy(this->sha256_root_hash, sha256_root_hash, kSthRootHashLength);
+  base::as_writable_byte_span(this->sha256_root_hash)
+      .copy_from(sha256_root_hash);
 }
 
 SignedTreeHead::SignedTreeHead(const SignedTreeHead& other) = default;
@@ -51,15 +51,11 @@
 bool operator==(const SignedTreeHead& lhs, const SignedTreeHead& rhs) {
   return std::tie(lhs.version, lhs.timestamp, lhs.tree_size, lhs.log_id) ==
              std::tie(rhs.version, rhs.timestamp, rhs.tree_size, rhs.log_id) &&
-         memcmp(lhs.sha256_root_hash, rhs.sha256_root_hash,
-                kSthRootHashLength) == 0 &&
+         std::ranges::equal(base::as_byte_span(lhs.sha256_root_hash),
+                            base::as_byte_span(rhs.sha256_root_hash)) &&
          lhs.signature.SignatureParametersMatch(
              rhs.signature.hash_algorithm, rhs.signature.signature_algorithm) &&
          lhs.signature.signature_data == rhs.signature.signature_data;
 }
 
-bool operator!=(const SignedTreeHead& lhs, const SignedTreeHead& rhs) {
-  return !(lhs == rhs);
-}
-
 }  // namespace net::ct
diff --git a/net/cert/signed_tree_head.h b/net/cert/signed_tree_head.h
index 9897841..d8fcc28 100644
--- a/net/cert/signed_tree_head.h
+++ b/net/cert/signed_tree_head.h
@@ -7,10 +7,9 @@
 
 #include <stdint.h>
 
-#include <iosfwd>
 #include <string>
-#include <vector>
 
+#include "base/containers/span.h"
 #include "base/time/time.h"
 #include "net/base/hash_value.h"
 #include "net/base/net_export.h"
@@ -18,7 +17,7 @@
 
 namespace net::ct {
 
-static const uint8_t kSthRootHashLength = 32;
+static constexpr uint8_t kSthRootHashLength = 32;
 
 // Signed Tree Head as defined in section 3.5. of RFC6962
 struct NET_EXPORT SignedTreeHead {
@@ -31,7 +30,7 @@
   SignedTreeHead(Version version,
                  const base::Time& timestamp,
                  uint64_t tree_size,
-                 const char sha256_root_hash[kSthRootHashLength],
+                 base::span<const uint8_t, kSthRootHashLength> sha256_root_hash,
                  const DigitallySigned& signature,
                  const std::string& log_id);
   SignedTreeHead(const SignedTreeHead& other);
@@ -52,8 +51,6 @@
 
 NET_EXPORT bool operator==(const SignedTreeHead& lhs,
                            const SignedTreeHead& rhs);
-NET_EXPORT bool operator!=(const SignedTreeHead& lhs,
-                           const SignedTreeHead& rhs);
 
 }  // namespace net::ct
 
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 30ca549..6c7b85d3 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -349,6 +349,8 @@
     "corp_heartbeat_service_client.h",
     "corp_host_status_logger.cc",
     "corp_host_status_logger.h",
+    "corp_register_support_host_request.cc",
+    "corp_register_support_host_request.h",
     "crash_process.cc",
     "crash_process.h",
     "create_desktop_interaction_strategy_factory.cc",
diff --git a/remoting/host/corp_register_support_host_request.cc b/remoting/host/corp_register_support_host_request.cc
new file mode 100644
index 0000000..c8676048
--- /dev/null
+++ b/remoting/host/corp_register_support_host_request.cc
@@ -0,0 +1,119 @@
+// 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 "remoting/host/corp_register_support_host_request.h"
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/time/time.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "remoting/base/http_status.h"
+#include "remoting/base/internal_headers.h"
+#include "remoting/base/oauth_token_getter.h"
+#include "remoting/base/protobuf_http_client.h"
+#include "remoting/base/protobuf_http_request.h"
+#include "remoting/base/protobuf_http_request_config.h"
+#include "remoting/base/service_urls.h"
+#include "remoting/proto/remote_support_service.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace remoting {
+
+namespace {
+
+constexpr base::TimeDelta kSupportIdLifetime = base::Minutes(5);
+
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("corp_register_support_host_request",
+                                        R"(
+        semantics {
+          sender: "Chrome Remote Desktop"
+          description:
+            "Request used by Chrome Remote Desktop for a corp user to register "
+            "a new remote support host."
+          trigger:
+            "Corp user requests for remote assistance using Chrome Remote "
+            "Desktop."
+          user_data {
+            type: CREDENTIALS
+            type: ACCESS_TOKEN
+          }
+          data:
+            "The user's OAuth token for Chrome Remote Desktop (CRD) and CRD "
+            "host information such as CRD host public key, host version, and "
+            "OS version."
+          destination: GOOGLE_OWNED_SERVICE
+          internal {
+            contacts { owners: "//remoting/OWNERS" }
+          }
+          last_reviewed: "2025-05-14"
+        }
+        policy {
+          cookies_allowed: NO
+          setting:
+            "This request cannot be stopped in settings, but will not be sent "
+            "if the user does not use Chrome Remote Desktop, or the user is "
+            "not a corp user (specified by the isCorpUser flag)."
+          chrome_policy {
+            RemoteAccessHostAllowRemoteSupportConnections {
+              RemoteAccessHostAllowRemoteSupportConnections: false
+            }
+            RemoteAccessHostAllowEnterpriseRemoteSupportConnections {
+              RemoteAccessHostAllowEnterpriseRemoteSupportConnections: false
+            }
+          }
+        })");
+
+}  // namespace
+
+CorpRegisterSupportHostRequest::CorpRegisterSupportHostRequest(
+    std::unique_ptr<OAuthTokenGetter> token_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : token_getter_(std::move(token_getter)),
+      url_loader_factory_(url_loader_factory) {}
+
+CorpRegisterSupportHostRequest::~CorpRegisterSupportHostRequest() = default;
+
+void CorpRegisterSupportHostRequest::Initialize(
+    std::unique_ptr<net::ClientCertStore> client_cert_store) {
+  http_client_ = std::make_unique<ProtobufHttpClient>(
+      ServiceUrls::GetInstance()->remoting_corp_endpoint(), token_getter_.get(),
+      url_loader_factory_, std::move(client_cert_store));
+}
+
+void CorpRegisterSupportHostRequest::RegisterHost(
+    const internal::RemoteSupportHostStruct& host,
+    const std::optional<ChromeOsEnterpriseParams>& enterprise_params,
+    RegisterHostCallback callback) {
+  auto request_config =
+      std::make_unique<ProtobufHttpRequestConfig>(kTrafficAnnotation);
+  request_config->path = internal::GetCreateRemoteSupportHostRequestPath();
+  request_config->api_key = internal::GetRemotingCorpApiKey();
+  request_config->provide_certificate = true;
+  request_config->request_message = internal::GetRemoteSupportHost(host);
+  auto http_request =
+      std::make_unique<ProtobufHttpRequest>(std::move(request_config));
+  http_request->SetResponseCallback(base::BindOnce(
+      [](RegisterHostCallback callback, const HttpStatus& status,
+         std::unique_ptr<internal::RemoteSupportHost> response) {
+        if (response) {
+          std::move(callback).Run(status, internal::GetSupportId(*response),
+                                  kSupportIdLifetime);
+        } else {
+          std::move(callback).Run(status, {}, {});
+        }
+      },
+      std::move(callback)));
+  http_client_->ExecuteRequest(std::move(http_request));
+}
+
+void CorpRegisterSupportHostRequest::CancelPendingRequests() {
+  http_client_->CancelPendingRequests();
+}
+
+}  // namespace remoting
diff --git a/remoting/host/corp_register_support_host_request.h b/remoting/host/corp_register_support_host_request.h
new file mode 100644
index 0000000..361eafa4
--- /dev/null
+++ b/remoting/host/corp_register_support_host_request.h
@@ -0,0 +1,53 @@
+// 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 REMOTING_HOST_CORP_REGISTER_SUPPORT_HOST_REQUEST_H_
+#define REMOTING_HOST_CORP_REGISTER_SUPPORT_HOST_REQUEST_H_
+
+#include "remoting/host/register_support_host_request_base.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace remoting {
+
+class OAuthTokenGetter;
+class ProtobufHttpClient;
+
+// Corp implementation of RegisterSupportHostRequest that registers a remote
+// support host by calling the corp internal CreateRemoteSupportHost API.
+class CorpRegisterSupportHostRequest final
+    : public RegisterSupportHostRequestBase {
+ public:
+  CorpRegisterSupportHostRequest(
+      std::unique_ptr<OAuthTokenGetter> token_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+  CorpRegisterSupportHostRequest(const CorpRegisterSupportHostRequest&) =
+      delete;
+  CorpRegisterSupportHostRequest& operator=(
+      const CorpRegisterSupportHostRequest&) = delete;
+
+  ~CorpRegisterSupportHostRequest() override;
+
+ private:
+  void Initialize(
+      std::unique_ptr<net::ClientCertStore> client_cert_store) override;
+  void RegisterHost(
+      const internal::RemoteSupportHostStruct& host,
+      const std::optional<ChromeOsEnterpriseParams>& enterprise_params,
+      RegisterHostCallback callback) override;
+  void CancelPendingRequests() override;
+
+  std::unique_ptr<OAuthTokenGetter> token_getter_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+  // This is constructed when Initialize() is called.
+  std::unique_ptr<ProtobufHttpClient> http_client_;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_HOST_CORP_REGISTER_SUPPORT_HOST_REQUEST_H_
diff --git a/remoting/host/it2me/it2me_constants.cc b/remoting/host/it2me/it2me_constants.cc
index 2d7a565..d65c554 100644
--- a/remoting/host/it2me/it2me_constants.cc
+++ b/remoting/host/it2me/it2me_constants.cc
@@ -24,6 +24,7 @@
 const char kIceConfig[] = "iceConfig";
 const char kAuthorizedHelper[] = "authorizedHelper";
 const char kUseCorpSessionAuthz[] = "useCorpSessionAuthz";
+const char kIsCorpUser[] = "isCorpUser";
 const char kConnectResponse[] = "connectResponse";
 
 const char kHostStateChangedMessage[] = "hostStateChanged";
diff --git a/remoting/host/it2me/it2me_constants.h b/remoting/host/it2me/it2me_constants.h
index 12f1e12..e2b2c82 100644
--- a/remoting/host/it2me/it2me_constants.h
+++ b/remoting/host/it2me/it2me_constants.h
@@ -49,6 +49,7 @@
 extern const char kIceConfig[];
 extern const char kAuthorizedHelper[];
 extern const char kUseCorpSessionAuthz[];
+extern const char kIsCorpUser[];
 // Response sent back to the client after the Connect message has been handled.
 extern const char kConnectResponse[];
 
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 7789e5a..874ed61 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -318,7 +318,8 @@
     }
   }
 
-  if (connection_context->use_corp_session_authz) {
+  if (connection_context->is_corp_user ||
+      connection_context->use_corp_session_authz) {
     use_corp_session_authz_ = true;
   }
 
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index c1745a6..8598a1b 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -81,7 +81,14 @@
     std::string ftl_device_id;
 
     // Use corp SessionAuthz auth instead of shared secret auth.
+    // DEPRECATED: use `is_corp_user` instead.
+    // TODO: crbug.com/417567187 - remove once corp IT2ME directory API is
+    // rolled out.
     bool use_corp_session_authz = false;
+
+    // Indicates whether the user is a corp user and corp flows need to be used
+    // instead of the external ones.
+    bool is_corp_user = false;
   };
 
   using CreateDeferredConnectContext =
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index a3ce622..a9f7e41 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -41,6 +41,7 @@
 #include "remoting/host/base/host_exit_codes.h"
 #include "remoting/host/chromeos/chromeos_enterprise_params.h"
 #include "remoting/host/chromoting_host_context.h"
+#include "remoting/host/corp_register_support_host_request.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
 #include "remoting/host/it2me/it2me_constants.h"
 #include "remoting/host/it2me/it2me_helpers.h"
@@ -128,12 +129,14 @@
     base::WeakPtr<OAuthTokenGetter> api_token_getter,
     const std::string& ftl_device_id,
     bool use_corp_session_authz,
+    bool is_corp_user,
     ChromotingHostContext* host_context) {
   std::string device_id =
       ftl_device_id.empty() ? base::Uuid::GenerateRandomV4().AsLowercaseString()
                             : ftl_device_id;
   auto connection_context =
       std::make_unique<It2MeHost::DeferredConnectContext>();
+  connection_context->is_corp_user = is_corp_user;
   connection_context->use_corp_session_authz = use_corp_session_authz;
   connection_context->use_ftl_signaling = true;
   connection_context->signal_strategy = std::make_unique<FtlSignalStrategy>(
@@ -142,11 +145,19 @@
       host_context->url_loader_factory(),
       std::make_unique<FtlSupportHostDeviceIdProvider>(device_id));
   connection_context->ftl_device_id = std::move(device_id);
-  connection_context->register_request =
-      std::make_unique<RemotingRegisterSupportHostRequest>(
-          std::make_unique<OAuthTokenGetterProxy>(
-              api_token_getter, oauth_token_getter_task_runner),
-          host_context->url_loader_factory());
+  if (is_corp_user) {
+    connection_context->register_request =
+        std::make_unique<CorpRegisterSupportHostRequest>(
+            std::make_unique<OAuthTokenGetterProxy>(
+                api_token_getter, oauth_token_getter_task_runner),
+            host_context->url_loader_factory());
+  } else {
+    connection_context->register_request =
+        std::make_unique<RemotingRegisterSupportHostRequest>(
+            std::make_unique<OAuthTokenGetterProxy>(
+                api_token_getter, oauth_token_getter_task_runner),
+            host_context->url_loader_factory());
+  }
   connection_context->log_to_server = std::make_unique<RemotingLogToServer>(
       ServerLogEntry::IT2ME,
       std::make_unique<OAuthTokenGetterProxy>(api_token_getter,
@@ -386,10 +397,11 @@
       }
       bool use_corp_session_authz =
           message.FindBool(kUseCorpSessionAuthz).value_or(false);
+      bool is_corp_user = message.FindBool(kIsCorpUser).value_or(false);
       create_connection_context = base::BindOnce(
           &CreateNativeSignalingDeferredConnectContext, task_runner(),
           signaling_token_getter_.GetWeakPtr(), api_token_getter_.GetWeakPtr(),
-          ftl_device_id, use_corp_session_authz);
+          ftl_device_id, use_corp_session_authz, is_corp_user);
     } else {
       LOG(ERROR) << kUserName << " not found in request.";
     }
diff --git a/remoting/internal b/remoting/internal
index 4a463f3..e2527ee 160000
--- a/remoting/internal
+++ b/remoting/internal
@@ -1 +1 @@
-Subproject commit 4a463f330397bebbca3b05702e27f7a8450cada3
+Subproject commit e2527eef826745f968d1e26247d7ba5d5b289012
diff --git a/remoting/proto/internal_stubs.cc b/remoting/proto/internal_stubs.cc
index 706f56c..0e8661b 100644
--- a/remoting/proto/internal_stubs.cc
+++ b/remoting/proto/internal_stubs.cc
@@ -204,9 +204,9 @@
   return {};
 }
 
-std::unique_ptr<CreateRemoteSupportHostRequest>
-GetCreateRemoteSupportHostRequest(const RemoteSupportHostStruct&) {
-  return std::make_unique<CreateRemoteSupportHostRequest>();
+std::unique_ptr<RemoteSupportHost> GetRemoteSupportHost(
+    const RemoteSupportHostStruct& request_struct) {
+  return std::make_unique<RemoteSupportHost>();
 }
 
 std::string_view GetSupportId(const RemoteSupportHost&) {
diff --git a/remoting/proto/internal_stubs.h b/remoting/proto/internal_stubs.h
index ccece52..eeca300 100644
--- a/remoting/proto/internal_stubs.h
+++ b/remoting/proto/internal_stubs.h
@@ -138,12 +138,10 @@
 // RemoteSupportService helpers
 // ============================
 
-using CreateRemoteSupportHostRequest = DoNothingProto;
-extern std::string_view GetCreateRemoteSupportHostRequestPath();
-extern std::unique_ptr<CreateRemoteSupportHostRequest>
-GetCreateRemoteSupportHostRequest(const RemoteSupportHostStruct&);
-
 using RemoteSupportHost = DoNothingProto;
+extern std::string_view GetCreateRemoteSupportHostRequestPath();
+extern std::unique_ptr<RemoteSupportHost> GetRemoteSupportHost(
+    const RemoteSupportHostStruct& request_struct);
 extern std::string_view GetSupportId(const RemoteSupportHost&);
 
 }  // namespace remoting::internal
diff --git a/services/viz/public/mojom/compositing/layer.mojom b/services/viz/public/mojom/compositing/layer.mojom
index f737d0c..5a46870 100644
--- a/services/viz/public/mojom/compositing/layer.mojom
+++ b/services/viz/public/mojom/compositing/layer.mojom
@@ -427,6 +427,20 @@
   // be a valid index in the same effect tree.
   int32 target_id;
 
+  // If this node is tagged with a ViewTransitionElementResourceId, it means it
+  // produces a snapshot for an element participating in a transition. This
+  // target id corresponds to the effect node where the
+  // ViewTransitionContentLayer using this resource draws. Can be unset if no
+  // layer using this resource is being drawn.
+  int32 view_transition_target_id;
+
+  // The ancestor ids indicate the existence of render surfaces, copy requests,
+  // or captures on ancestor effect nodes.
+  int32 closest_ancestor_with_cached_render_surface_id;
+  int32 closest_ancestor_with_copy_request_id;
+  int32 closest_ancestor_being_captured_id;
+  int32 closest_ancestor_with_shared_element_id;
+
   // Represents a resource id for a resource cached or generated in the Viz
   // process.
   ViewTransitionElementResourceId view_transition_element_resource_id;
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc
index 43e85170..c3d8119 100644
--- a/services/webnn/coreml/graph_builder_coreml.cc
+++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -4590,10 +4590,6 @@
       mode = "constant";
       constant = operation.mode->get_constant()->value;
       break;
-    case mojom::PaddingMode::Tag::kSymmetric:
-      // TODO: crbug.com/354101904 - figure out out how to emulate this or
-      // resolve the incompabitility at spec level.
-      return NewNotSupportedError("Unsupported mode symmetric for pad.");
     case mojom::PaddingMode::Tag::kEdge:
       mode = "replicate";
       break;
diff --git a/services/webnn/dml/graph_impl_dml.cc b/services/webnn/dml/graph_impl_dml.cc
index be06030..241a5e42a 100644
--- a/services/webnn/dml/graph_impl_dml.cc
+++ b/services/webnn/dml/graph_impl_dml.cc
@@ -2556,9 +2556,6 @@
     case mojom::PaddingMode::Tag::kReflection:
       padding_mode = DML_PADDING_MODE::DML_PADDING_MODE_REFLECTION;
       break;
-    case mojom::PaddingMode::Tag::kSymmetric:
-      padding_mode = DML_PADDING_MODE::DML_PADDING_MODE_SYMMETRIC;
-      break;
   }
 
   const auto& beginning_padding = pad->beginning_padding;
diff --git a/services/webnn/public/mojom/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
index 43d0bd80..d31bfbc 100644
--- a/services/webnn/public/mojom/webnn_graph.mojom
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -351,13 +351,10 @@
 
 struct ReflectionPadding {};
 
-struct SymmetricPadding {};
-
 union PaddingMode {
   ConstantPadding constant;
   EdgePadding edge;
   ReflectionPadding reflection;
-  SymmetricPadding symmetric;
 };
 
 // This operator performs the following normalization, defined as:
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index b897d2a..626df2944 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -5655,15 +5655,6 @@
                             .Union();
       break;
     }
-    case mojom::PaddingMode::Tag::kSymmetric: {
-      operator_code = ::tflite::BuiltinOperator::BuiltinOperator_MIRROR_PAD;
-      builtin_options_type =
-          ::tflite::BuiltinOptions::BuiltinOptions_MirrorPadOptions;
-      builtin_options = ::tflite::CreateMirrorPadOptions(
-                            builder_, ::tflite::MirrorPadMode_SYMMETRIC)
-                            .Union();
-      break;
-    }
   }
 
   const TensorIndex output_tensor_index =
diff --git a/services/webnn/webnn_test_utils.cc b/services/webnn/webnn_test_utils.cc
index 2349090..43d144a 100644
--- a/services/webnn/webnn_test_utils.cc
+++ b/services/webnn/webnn_test_utils.cc
@@ -157,10 +157,6 @@
       pad->mode =
           mojom::PaddingMode::NewReflection(mojom::ReflectionPadding::New());
       break;
-    case mojom::PaddingMode::Tag::kSymmetric:
-      pad->mode =
-          mojom::PaddingMode::NewSymmetric(mojom::SymmetricPadding::New());
-      break;
   }
 
   graph_info_->operations.push_back(mojom::Operation::NewPad(std::move(pad)));
diff --git a/testing/buildbot/filters/trees_in_viz.cc_unittests.filter b/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
index 3864553..ede78f8 100644
--- a/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
+++ b/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
@@ -49,8 +49,3 @@
 
 # TODO(crbug.com/406010462) View transition requests are lost between cc and viz
 -LayerTreeHostTestDamagePropagatesFromViewTransitionSurface.RunMultiThread_DelegatingRenderer
-
-# TODO(crbug.com/383016428) Readback of layers outside of the viewport stopped
-# working since crrev.com/c/6383158.
--All/LayerTreeHostReadbackPixelTest.ReadbackNonRootLayerOutsideViewport/*
--All/LayerTreeHostReadbackPixelTest.ReadbackOutsideViewportWhenNoDamage/*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 868f4f0..2dcd46c 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -22148,26 +22148,6 @@
             ]
         }
     ],
-    "ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement"
-                    ]
-                }
-            ]
-        }
-    ],
     "SettingSearchExplorationHaTS": [
         {
             "platforms": [
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index c3545f3..c701446b 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -305,7 +305,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13516689/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13518877/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/angle b/third_party/angle
index b4d39a0..dcbcee8 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit b4d39a07b317257d31b1fa3cdb2aecd822918ca7
+Subproject commit dcbcee8ab32af9ddc7ae1e91c42d995e5281602c
diff --git a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
index 8e1737f..87fa47d 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom
@@ -911,6 +911,7 @@
     kRuleWidth = 852,
     kRuleStyle = 853,
     kCaretShape = 854,
+    kRowRule = 855,
 
     // 1. Add new features above this line (don't change the assigned numbers of
     //    the existing items).
diff --git a/third_party/blink/renderer/core/css/build.gni b/third_party/blink/renderer/core/css/build.gni
index f98f981..82be6d81 100644
--- a/third_party/blink/renderer/core/css/build.gni
+++ b/third_party/blink/renderer/core/css/build.gni
@@ -146,7 +146,8 @@
   "css_alternate_value.h",
   "css_function_value.cc",
   "css_function_value.h",
-  "css_gap_decoration_property_enums.h",
+  "css_gap_decoration_property_utils.cc",
+  "css_gap_decoration_property_utils.h",
   "css_global_rule_set.cc",
   "css_global_rule_set.h",
   "css_gradient_value.cc",
diff --git a/third_party/blink/renderer/core/css/css_gap_decoration_property_enums.h b/third_party/blink/renderer/core/css/css_gap_decoration_property_enums.h
deleted file mode 100644
index b8ff9d377..0000000
--- a/third_party/blink/renderer/core/css/css_gap_decoration_property_enums.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_ENUMS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_ENUMS_H_
-
-namespace blink {
-
-enum class CSSGapDecorationPropertyType {
-  kColor,
-  kWidth,
-  kStyle,
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_ENUMS_H_
diff --git a/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.cc b/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.cc
new file mode 100644
index 0000000..9ab62f1
--- /dev/null
+++ b/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.cc
@@ -0,0 +1,35 @@
+// 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 "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
+
+namespace blink {
+
+CSSPropertyID CSSGapDecorationUtils::GetLonghandProperty(
+    CSSGapDecorationPropertyDirection direction,
+    CSSGapDecorationPropertyType type) {
+  switch (type) {
+    case CSSGapDecorationPropertyType::kWidth:
+      return direction == CSSGapDecorationPropertyDirection::kRow
+                 ? CSSPropertyID::kRowRuleWidth
+                 : CSSPropertyID::kColumnRuleWidth;
+    case CSSGapDecorationPropertyType::kStyle:
+      return direction == CSSGapDecorationPropertyDirection::kRow
+                 ? CSSPropertyID::kRowRuleStyle
+                 : CSSPropertyID::kColumnRuleStyle;
+    case CSSGapDecorationPropertyType::kColor:
+      return direction == CSSGapDecorationPropertyDirection::kRow
+                 ? CSSPropertyID::kRowRuleColor
+                 : CSSPropertyID::kColumnRuleColor;
+  }
+}
+
+CSSPropertyID CSSGapDecorationUtils::GetShorthandProperty(
+    CSSGapDecorationPropertyDirection direction) {
+  return direction == CSSGapDecorationPropertyDirection::kRow
+             ? CSSPropertyID::kRowRule
+             : CSSPropertyID::kColumnRule;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h b/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h
new file mode 100644
index 0000000..c5d6ba4a
--- /dev/null
+++ b/third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h
@@ -0,0 +1,36 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_UTILS_H_
+
+#include "third_party/blink/renderer/core/css/css_property_names.h"
+
+namespace blink {
+
+enum class CSSGapDecorationPropertyType : int {
+  kColor,
+  kWidth,
+  kStyle,
+};
+
+enum class CSSGapDecorationPropertyDirection : int {
+  kRow,
+  kColumn,
+};
+
+class CORE_EXPORT CSSGapDecorationUtils {
+  STATIC_ONLY(CSSGapDecorationUtils);
+
+ public:
+  static CSSPropertyID GetLonghandProperty(
+      CSSGapDecorationPropertyDirection direction,
+      CSSGapDecorationPropertyType type);
+  static CSSPropertyID GetShorthandProperty(
+      CSSGapDecorationPropertyDirection direction);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GAP_DECORATION_PROPERTY_UTILS_H_
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 7f200024..1c5e2fff 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -341,6 +341,7 @@
         "corner-shape",
         "currentcolor",
         "filter-data",
+        "gap-decorations",
         "has-transform",
         "inset",
         "layout",
@@ -6592,7 +6593,7 @@
       type_name: "GapDataList<EBorderStyle>",
       typedom_types: ["Keyword"],
       converter: "ConvertGapDecorationStyleDataList",
-      invalidate: ["paint"],
+      invalidate: ["paint", "gap-decorations"],
     },
     {
       name: "row-rule-style",
@@ -6609,7 +6610,7 @@
       type_name: "GapDataList<EBorderStyle>",
       typedom_types: ["Keyword"],
       converter: "ConvertGapDecorationStyleDataList",
-      invalidate: ["paint"],
+      invalidate: ["paint", "gap-decorations"],
       runtime_flag: "CSSGapDecoration",
     },
     {
@@ -8775,6 +8776,14 @@
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
+      name: "row-rule",
+      longhands: [
+        "row-rule-width", "row-rule-style", "row-rule-color"
+      ],
+      property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
+      runtime_flag: "CSSGapDecoration",
+    },
+    {
       name: "columns",
       longhands: ["column-width", "column-count"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
diff --git a/third_party/blink/renderer/core/css/css_property_equality.cc b/third_party/blink/renderer/core/css/css_property_equality.cc
index 11c153b..a717631 100644
--- a/third_party/blink/renderer/core/css/css_property_equality.cc
+++ b/third_party/blink/renderer/core/css/css_property_equality.cc
@@ -1288,6 +1288,7 @@
     case CSSPropertyID::kPlaceItems:
     case CSSPropertyID::kPlaceSelf:
     case CSSPropertyID::kPositionTry:
+    case CSSPropertyID::kRowRule:
     case CSSPropertyID::kRuleColor:
     case CSSPropertyID::kRuleWidth:
     case CSSPropertyID::kRuleStyle:
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 3b68fee4..eaadbed 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
 #include "third_party/blink/renderer/core/css/css_font_variation_value.h"
 #include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
@@ -3873,7 +3874,8 @@
     const ComputedStyle& style,
     const LayoutObject* layout_object,
     bool allow_visited_style,
-    CSSValuePhase value_phase) {
+    CSSValuePhase value_phase,
+    CSSGapDecorationPropertyDirection direction) {
   // If the CSSGapDecorations feature is not enabled, fallback to legacy
   // behavior of handling the shorthand since values are stored as single
   // values and not lists.
@@ -3883,9 +3885,15 @@
   }
 
   CHECK_EQ(shorthand.length(), 3u);
-  CHECK(shorthand.properties()[0]->IDEquals(CSSPropertyID::kColumnRuleWidth));
-  CHECK(shorthand.properties()[1]->IDEquals(CSSPropertyID::kColumnRuleStyle));
-  CHECK(shorthand.properties()[2]->IDEquals(CSSPropertyID::kColumnRuleColor));
+  CHECK(shorthand.properties()[0]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kWidth)));
+  CHECK(shorthand.properties()[1]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kStyle)));
+  CHECK(shorthand.properties()[2]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kColor)));
 
   const CSSValueList* width_values = DynamicTo<CSSValueList>(
       shorthand.properties()[0]->CSSValueFromComputedStyle(
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
index 2d4786ce..99581b50 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -34,6 +34,8 @@
 class StylePropertyShorthand;
 class StyleTimeline;
 
+enum class CSSGapDecorationPropertyDirection : int;
+
 namespace cssvalue {
 class CSSContentDistributionValue;
 }
@@ -338,7 +340,8 @@
       const ComputedStyle&,
       const LayoutObject*,
       bool allow_visited_style,
-      CSSValuePhase value_phase);
+      CSSValuePhase value_phase,
+      CSSGapDecorationPropertyDirection direction);
   static CSSValuePair* ValuesForGapShorthand(const StylePropertyShorthand&,
                                              const ComputedStyle&,
                                              const LayoutObject*,
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index da525475..6d9f3c6e1 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/css/css_font_feature_value.h"
 #include "third_party/blink/renderer/core/css/css_font_style_range_value.h"
 #include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
 #include "third_party/blink/renderer/core/css/css_gradient_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
@@ -7025,13 +7026,15 @@
 // Top level parsing function for the gap-decorations shorthand, which handles
 // the parsing of simple <gap-rule> or repeat <gap-rule> values.
 bool ConsumeGapDecorationsRuleShorthand(
+    CSSGapDecorationPropertyDirection direction,
     bool important,
     const CSSParserContext& context,
     CSSParserTokenStream& stream,
     HeapVector<CSSPropertyValue, 64>& properties) {
-  // TODO(samomekarajr): Add support for `row-rule` shorthand when implemented.
   const StylePropertyShorthand& gapDecorationsRuleShorthand =
-      columnRuleShorthand();
+      direction == CSSGapDecorationPropertyDirection::kRow
+          ? rowRuleShorthand()
+          : columnRuleShorthand();
   DCHECK_EQ(gapDecorationsRuleShorthand.length(), 3u);
 
   // If the CSSGapDecorations feature is not enabled, consume greedily since
@@ -7090,15 +7093,23 @@
   }
 
   css_parsing_utils::AddProperty(
-      CSSPropertyID::kColumnRuleWidth, CSSPropertyID::kColumnRule, *rule_widths,
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kWidth),
+      CSSGapDecorationUtils::GetShorthandProperty(direction), *rule_widths,
       important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
+
   css_parsing_utils::AddProperty(
-      CSSPropertyID::kColumnRuleStyle, CSSPropertyID::kColumnRule, *rule_styles,
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kStyle),
+      CSSGapDecorationUtils::GetShorthandProperty(direction), *rule_styles,
       important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
+
   css_parsing_utils::AddProperty(
-      CSSPropertyID::kColumnRuleColor, CSSPropertyID::kColumnRule, *rule_colors,
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kColor),
+      CSSGapDecorationUtils::GetShorthandProperty(direction), *rule_colors,
       important, css_parsing_utils::IsImplicitProperty::kNotImplicit,
       properties);
 
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index 575431d0..54b570e 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -10,7 +10,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_anchor_query_enums.h"
 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
-#include "third_party/blink/renderer/core/css/css_gap_decoration_property_enums.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
@@ -44,6 +43,9 @@
 class CSSValuePair;
 class StylePropertyShorthand;
 
+enum class CSSGapDecorationPropertyDirection : int;
+enum class CSSGapDecorationPropertyType : int;
+
 // "Consume" functions, when successful, should consume all the relevant tokens
 // as well as any trailing whitespace. When the start of the stream doesn't
 // match the type we're looking for, the position in the stream should
@@ -556,6 +558,7 @@
 CSSValue* ConsumeItemTolerance(CSSParserTokenStream&, const CSSParserContext&);
 
 bool ConsumeGapDecorationsRuleShorthand(
+    CSSGapDecorationPropertyDirection direction,
     bool important,
     const CSSParserContext&,
     CSSParserTokenStream&,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index db463eb0..fff39929 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/css/css_font_selector.h"
 #include "third_party/blink/renderer/core/css/css_font_variation_value.h"
 #include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
 #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
index d66cde5..4a513ea 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -5,6 +5,7 @@
 #include "base/memory/values_equivalent.h"
 #include "third_party/blink/renderer/core/animation/timeline_offset.h"
 #include "third_party/blink/renderer/core/css/css_content_distribution_value.h"
+#include "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value_mappings.h"
 #include "third_party/blink/renderer/core/css/css_initial_value.h"
@@ -1196,7 +1197,8 @@
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 64>& properties) const {
   return css_parsing_utils::ConsumeGapDecorationsRuleShorthand(
-      important, context, stream, properties);
+      CSSGapDecorationPropertyDirection::kColumn, important, context, stream,
+      properties);
 }
 
 const CSSValue* ColumnRule::CSSValueFromComputedStyleInternal(
@@ -1206,7 +1208,28 @@
     CSSValuePhase value_phase) const {
   return ComputedStyleUtils::ValueForGapDecorationRuleShorthand(
       columnRuleShorthand(), style, layout_object, allow_visited_style,
-      value_phase);
+      value_phase, CSSGapDecorationPropertyDirection::kColumn);
+}
+
+bool RowRule::ParseShorthand(
+    bool important,
+    CSSParserTokenStream& stream,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 64>& properties) const {
+  return css_parsing_utils::ConsumeGapDecorationsRuleShorthand(
+      CSSGapDecorationPropertyDirection::kRow, important, context, stream,
+      properties);
+}
+
+const CSSValue* RowRule::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const LayoutObject* layout_object,
+    bool allow_visited_style,
+    CSSValuePhase value_phase) const {
+  return ComputedStyleUtils::ValueForGapDecorationRuleShorthand(
+      rowRuleShorthand(), style, layout_object, allow_visited_style,
+      value_phase, CSSGapDecorationPropertyDirection::kRow);
 }
 
 bool Columns::ParseShorthand(
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc
index 6aed829..cfe620a9 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -28,6 +28,7 @@
 #include "base/logging.h"
 #include "base/memory/values_equivalent.h"
 #include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
+#include "third_party/blink/renderer/core/css/css_gap_decoration_property_utils.h"
 #include "third_party/blink/renderer/core/css/css_grid_template_areas_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_markup.h"
@@ -588,7 +589,11 @@
     case CSSPropertyID::kBorderStyle:
       return Get4Values(borderStyleShorthand());
     case CSSPropertyID::kColumnRule:
-      return GetShorthandValueForGapDecorationsRule(columnRuleShorthand());
+      return GetShorthandValueForGapDecorationsRule(
+          columnRuleShorthand(), CSSGapDecorationPropertyDirection::kColumn);
+    case CSSPropertyID::kRowRule:
+      return GetShorthandValueForGapDecorationsRule(
+          rowRuleShorthand(), CSSGapDecorationPropertyDirection::kRow);
     case CSSPropertyID::kColumns:
       return GetShorthandValueForColumns(columnsShorthand());
     case CSSPropertyID::kContainIntrinsicSize:
@@ -1930,7 +1935,8 @@
 // ComputedStyleUtils::ValueForGapDecorationRuleShorthand(). Look to refactor to
 // avoid duplicated logic when possible.
 String StylePropertySerializer::GetShorthandValueForGapDecorationsRule(
-    const StylePropertyShorthand& shorthand) const {
+    const StylePropertyShorthand& shorthand,
+    CSSGapDecorationPropertyDirection direction) const {
   // If the CSSGapDecorations feature is not enabled, fallback to legacy
   // behavior of serializing the shorthand since values are stored as single
   // values and not lists.
@@ -1939,9 +1945,15 @@
   }
 
   CHECK_EQ(shorthand.length(), 3u);
-  CHECK(shorthand.properties()[0]->IDEquals(CSSPropertyID::kColumnRuleWidth));
-  CHECK(shorthand.properties()[1]->IDEquals(CSSPropertyID::kColumnRuleStyle));
-  CHECK(shorthand.properties()[2]->IDEquals(CSSPropertyID::kColumnRuleColor));
+  CHECK(shorthand.properties()[0]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kWidth)));
+  CHECK(shorthand.properties()[1]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kStyle)));
+  CHECK(shorthand.properties()[2]->IDEquals(
+      CSSGapDecorationUtils::GetLonghandProperty(
+          direction, CSSGapDecorationPropertyType::kColor)));
 
   const CSSValueList* width_values = DynamicTo<CSSValueList>(
       property_set_.GetPropertyCSSValue(*shorthand.properties()[0]));
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.h b/third_party/blink/renderer/core/css/style_property_serializer.h
index b228f37..b2c5313d 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.h
+++ b/third_party/blink/renderer/core/css/style_property_serializer.h
@@ -39,6 +39,8 @@
 class CSSPropertyValueSet;
 class StylePropertyShorthand;
 
+enum class CSSGapDecorationPropertyDirection : int;
+
 class CORE_EXPORT StylePropertySerializer {
   STACK_ALLOCATED();
 
@@ -65,7 +67,8 @@
   String GetShorthandValueForBidirectionalGapRules(
       const StylePropertyShorthand&) const;
   String GetShorthandValueForGapDecorationsRule(
-      const StylePropertyShorthand&) const;
+      const StylePropertyShorthand&,
+      CSSGapDecorationPropertyDirection direction) const;
   String GetShorthandValueForColumnRule(const StylePropertyShorthand&) const;
   String GetShorthandValueForColumns(const StylePropertyShorthand&) const;
   // foo || bar || ... || baz
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 489d8790..58e8beeb 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -986,6 +986,22 @@
     return true;
   }
 
+  if (field_diff & kGapDecorations) {
+    bool column_rule_style_changed_from_none =
+        ColumnRuleStyle() ==
+            ComputedStyleInitialValues::InitialColumnRuleStyle() &&
+        other.ColumnRuleStyle() !=
+            ComputedStyleInitialValues::InitialColumnRuleStyle();
+    bool row_rule_style_changed_from_none =
+        RowRuleStyle() == ComputedStyleInitialValues::InitialRowRuleStyle() &&
+        other.RowRuleStyle() !=
+            ComputedStyleInitialValues::InitialRowRuleStyle();
+    if (column_rule_style_changed_from_none ||
+        row_rule_style_changed_from_none) {
+      return true;
+    }
+  }
+
   return false;
 }
 
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
index 509880c..d0f4b52 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
@@ -143,8 +143,7 @@
 enum MLPaddingMode {
   "constant",
   "edge",
-  "reflection",
-  "symmetric"
+  "reflection"
 };
 
 dictionary MLPadOptions : MLOperatorOptions {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
index 5679f937..1f2f0e9 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
@@ -1337,10 +1337,6 @@
       pad_mojo->mode = blink_mojom::PaddingMode::NewReflection(
           blink_mojom::ReflectionPadding::New());
       break;
-    case blink::V8MLPaddingMode::Enum::kSymmetric:
-      pad_mojo->mode = blink_mojom::PaddingMode::NewSymmetric(
-          blink_mojom::SymmetricPadding::New());
-      break;
   }
   pad_mojo->label = options->label();
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
index 90df9dd..1298cb0 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "third_party/blink/renderer/modules/webaudio/audio_param_handler.h"
 
+#include <algorithm>
+
+#include "base/containers/span.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -32,30 +30,31 @@
 namespace {
 
 // Replace NaN values in `values` with `default_value`.
-void HandleNaNValues(float* values,
-                     unsigned number_of_values,
-                     float default_value) {
+void HandleNaNValues(base::span<float> values, float default_value) {
   unsigned k = 0;
 #if defined(ARCH_CPU_X86_FAMILY)
-  if (number_of_values >= 4) {
+  if (values.size() >= 4) {
     __m128 defaults = _mm_set1_ps(default_value);
-    for (k = 0; k < number_of_values; k += 4) {
-      __m128 v = _mm_loadu_ps(values + k);
+    for (k = 0; k < values.size(); k += 4) {
+      // SAFETY: The for loop condition has been checked k < values.size().
+      __m128 v = _mm_loadu_ps(UNSAFE_BUFFERS(values.data() + k));
       // cmpuord returns all 1's if v is NaN for each elmeent of v.
       __m128 isnan = _mm_cmpunord_ps(v, v);
       // Replace NaN parts with default.
       __m128 result = _mm_and_ps(isnan, defaults);
       // Merge in the parts that aren't NaN
       result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
-      _mm_storeu_ps(values + k, result);
+      // SAFETY: The for loop condition has been checked k < values.size().
+      _mm_storeu_ps(UNSAFE_BUFFERS(values.data() + k), result);
     }
   }
 #elif defined(CPU_ARM_NEON)
-  if (number_of_values >= 4) {
+  if (values.size() >= 4) {
     uint32x4_t defaults =
         reinterpret_cast<uint32x4_t>(vdupq_n_f32(default_value));
-    for (k = 0; k < number_of_values; k += 4) {
-      float32x4_t v = vld1q_f32(values + k);
+    for (k = 0; k < values.size(); k += 4) {
+      // SAFETY: The for loop condition has been checked k < values.size().
+      float32x4_t v = vld1q_f32(UNSAFE_BUFFERS(values.data() + k));
       // Returns true (all ones) if v is not NaN
       uint32x4_t is_not_nan = vceqq_f32(v, v);
       // Get the parts that are not NaN
@@ -64,16 +63,16 @@
       // Replace the parts that are NaN with the default and merge with previous
       // result.  (Note: vbic_u32(x, y) = x and not y)
       result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
-      vst1q_f32(values + k, reinterpret_cast<float32x4_t>(result));
+      // SAFETY: The for loop condition has been checked k < values.size().
+      vst1q_f32(UNSAFE_BUFFERS(values.data() + k),
+                reinterpret_cast<float32x4_t>(result));
     }
   }
 #endif
 
-  for (; k < number_of_values; ++k) {
-    if (std::isnan(values[k])) {
-      values[k] = default_value;
-    }
-  }
+  std::ranges::replace_if(
+      values.subspan(k), [](float value) { return std::isnan(value); },
+      default_value);
 }
 
 }  // namespace
@@ -222,7 +221,7 @@
 
 float AudioParamHandler::FinalValue() {
   float value = IntrinsicValue();
-  CalculateFinalValues(&value, 1, false);
+  CalculateFinalValues(base::span_from_ref(value), false);
   return value;
 }
 
@@ -231,22 +230,20 @@
   DCHECK(GetDeferredTaskHandler().IsAudioThread());
   DCHECK(!values.empty());
 
-  CalculateFinalValues(values.data(), values.size(), IsAudioRate());
+  CalculateFinalValues(values, IsAudioRate());
 }
 
-void AudioParamHandler::CalculateFinalValues(float* values,
-                                             unsigned number_of_values,
+void AudioParamHandler::CalculateFinalValues(base::span<float> values,
                                              bool sample_accurate) {
   DCHECK(GetDeferredTaskHandler().IsAudioThread());
-  DCHECK(values);
-  DCHECK_GT(number_of_values, 0u);
+  DCHECK(!values.empty());
 
   // The calculated result will be the "intrinsic" value summed with all
   // audio-rate connections.
 
   if (sample_accurate) {
     // Calculate sample-accurate (a-rate) intrinsic values.
-    CalculateTimelineValues(values, number_of_values);
+    CalculateTimelineValues(values);
   } else {
     // Calculate control-rate (k-rate) intrinsic value.
     float value = IntrinsicValue();
@@ -258,9 +255,7 @@
       value = timeline_value;
     }
 
-    for (unsigned k = 0; k < number_of_values; ++k) {
-      values[k] = value;
-    }
+    std::ranges::fill(values, value);
     SetIntrinsicValue(value);
   }
 
@@ -268,13 +263,13 @@
   // together (unity-gain summing junction).  Note that connections would
   // normally be mono, but we mix down to mono if necessary.
   if (NumberOfRenderingConnections() > 0) {
-    DCHECK_LE(number_of_values, GetDeferredTaskHandler().RenderQuantumFrames());
+    DCHECK_LE(values.size(), GetDeferredTaskHandler().RenderQuantumFrames());
 
     // If we're not sample accurate, we only need one value, so make the summing
     // bus have length 1.  When the connections are added in, only the first
     // value will be added.  Which is exactly what we want.
-    summing_bus_->SetChannelMemory(0, values,
-                                   sample_accurate ? number_of_values : 1);
+    summing_bus_->SetChannelMemory(0, values.data(),
+                                   sample_accurate ? values.size() : 1);
 
     for (unsigned i = 0; i < NumberOfRenderingConnections(); ++i) {
       AudioNodeOutput* output = RenderingOutput(i);
@@ -291,9 +286,7 @@
     // If we're not sample accurate, duplicate the first element of `values` to
     // all of the elements.
     if (!sample_accurate) {
-      for (unsigned k = 0; k < number_of_values; ++k) {
-        values[k] = values[0];
-      }
+      std::ranges::fill(values, values[0]);
     }
 
     float min_value = MinValue();
@@ -308,28 +301,26 @@
       // range between the AudioParam's minValue and maxValue.
       //
       // See https://webaudio.github.io/web-audio-api/#computation-of-value.
-      HandleNaNValues(values, number_of_values, DefaultValue());
+      HandleNaNValues(values, DefaultValue());
     }
 
-    vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
-                       number_of_values);
+    vector_math::Vclip(values, 1, &min_value, &max_value, values, 1);
   }
 }
 
-void AudioParamHandler::CalculateTimelineValues(float* values,
-                                                unsigned number_of_values) {
+void AudioParamHandler::CalculateTimelineValues(base::span<float> values) {
   // Calculate values for this render quantum.  Normally
   // `number_of_values` will equal to
   // GetDeferredTaskHandler().RenderQuantumFrames() (the render quantum size).
   double sample_rate = DestinationHandler().SampleRate();
   size_t start_frame = DestinationHandler().CurrentSampleFrame();
-  size_t end_frame = start_frame + number_of_values;
+  size_t end_frame = start_frame + values.size();
 
   // Note we're running control rate at the sample-rate.
   // Pass in the current value as default value.
   SetIntrinsicValue(timeline_.ValuesForFrameRange(
-      start_frame, end_frame, IntrinsicValue(), values, number_of_values,
-      sample_rate, sample_rate, MinValue(), MaxValue(),
+      start_frame, end_frame, IntrinsicValue(), values, sample_rate,
+      sample_rate, MinValue(), MaxValue(),
       GetDeferredTaskHandler().RenderQuantumFrames()));
 }
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_handler.h b/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
index 8f9ca0fc..f53e2ee 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
@@ -180,10 +180,8 @@
 
   // sampleAccurate corresponds to a-rate (audio rate) vs. k-rate in the Web
   // Audio specification.
-  void CalculateFinalValues(float* values,
-                            unsigned number_of_values,
-                            bool sample_accurate);
-  void CalculateTimelineValues(float* values, unsigned number_of_values);
+  void CalculateFinalValues(base::span<float> values, bool sample_accurate);
+  void CalculateTimelineValues(base::span<float> values);
 
   // The type of AudioParam, indicating what this AudioParam represents and what
   // node it belongs to.  Mostly for informational purposes and doesn't affect
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
index de5407b..d2f652a 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -23,17 +23,13 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "third_party/blink/renderer/modules/webaudio/audio_param_timeline.h"
 
 #include <algorithm>
 #include <limits>
 #include <memory>
 
+#include "base/containers/span.h"
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -198,11 +194,10 @@
 float AudioParamTimeline::ValueCurveAtTime(double t,
                                            double time1,
                                            double duration,
-                                           const float* curve_data,
-                                           unsigned curve_length) {
-  double curve_index = (curve_length - 1) / duration * (t - time1);
-  unsigned k = std::min(static_cast<unsigned>(curve_index), curve_length - 1);
-  unsigned k1 = std::min(k + 1, curve_length - 1);
+                                           base::span<const float> curve_data) {
+  double curve_index = (curve_data.size() - 1) / duration * (t - time1);
+  size_t k = std::min(static_cast<size_t>(curve_index), curve_data.size() - 1);
+  size_t k1 = std::min(k + 1, curve_data.size() - 1);
   float c0 = curve_data[k];
   float c1 = curve_data[k1];
   float delta = std::min(curve_index - k, 1.0);
@@ -254,7 +249,7 @@
     double time,
     double duration) {
   double curve_points = (curve.size() - 1) / duration;
-  float end_value = curve.data()[curve.size() - 1];
+  float end_value = curve.back();
 
   return base::WrapUnique(new ParamEvent(ParamEvent::Type::kSetValueCurve, time,
                                          duration, curve, curve_points,
@@ -430,7 +425,7 @@
   DCHECK_EQ(type, ParamEvent::Type::kSetValueCurve);
   unsigned curve_length = curve.size();
   curve_.resize(curve_length);
-  memcpy(curve_.data(), curve.data(), curve_length * sizeof(float));
+  base::span(curve_).copy_from(curve);
 }
 
 // Create CancelValues event
@@ -560,9 +555,9 @@
   // Insert a setValueAtTime event too to establish an event so that all
   // following events will process from the end of the curve instead of the
   // beginning.
-  InsertEvent(ParamEvent::CreateSetValueCurveEndEvent(
-                  curve.data()[curve.size() - 1], time + duration),
-              exception_state);
+  InsertEvent(
+      ParamEvent::CreateSetValueCurveEndEvent(curve.back(), time + duration),
+      exception_state);
 }
 
 void AudioParamTimeline::InsertEvent(std::unique_ptr<ParamEvent> event,
@@ -912,7 +907,7 @@
           double new_duration = cancel_time - cancelled_event->Time();
           float end_value = ValueCurveAtTime(
               cancel_time, cancelled_event->Time(), cancelled_event->Duration(),
-              cancelled_event->Curve().data(), cancelled_event->Curve().size());
+              cancelled_event->Curve());
 
           // Replace the existing SetValueCurve with this new one that is
           // identical except for the duration.
@@ -971,9 +966,9 @@
   size_t start_frame = audio_destination.CurrentSampleFrame();
   // One parameter change per render quantum.
   double control_rate = sample_rate / render_quantum_frames;
-  value = ValuesForFrameRange(start_frame, start_frame + 1, default_value,
-                              &value, 1, sample_rate, control_rate, min_value,
-                              max_value, render_quantum_frames);
+  value = ValuesForFrameRange(
+      start_frame, start_frame + 1, default_value, base::span_from_ref(value),
+      sample_rate, control_rate, min_value, max_value, render_quantum_frames);
 
   return std::make_tuple(true, value);
 }
@@ -981,8 +976,7 @@
 float AudioParamTimeline::ValuesForFrameRange(size_t start_frame,
                                               size_t end_frame,
                                               float default_value,
-                                              float* values,
-                                              unsigned number_of_values,
+                                              base::span<float> values,
                                               double sample_rate,
                                               double control_rate,
                                               float min_value,
@@ -991,21 +985,16 @@
   // We can't contend the lock in the realtime audio thread.
   base::AutoTryLock try_locker(events_lock_);
   if (!try_locker.is_acquired()) {
-    if (values) {
-      for (unsigned i = 0; i < number_of_values; ++i) {
-        values[i] = default_value;
-      }
-    }
+    std::ranges::fill(values, default_value);
     return default_value;
   }
 
-  float last_value = ValuesForFrameRangeImpl(
-      start_frame, end_frame, default_value, values, number_of_values,
-      sample_rate, control_rate, render_quantum_frames);
+  float last_value =
+      ValuesForFrameRangeImpl(start_frame, end_frame, default_value, values,
+                              sample_rate, control_rate, render_quantum_frames);
 
   // Clamp the values now to the nominal range
-  vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
-                     number_of_values);
+  vector_math::Vclip(values, 1, &min_value, &max_value, values, 1);
 
   return last_value;
 }
@@ -1014,19 +1003,16 @@
     size_t start_frame,
     size_t end_frame,
     float default_value,
-    float* values,
-    unsigned number_of_values,
+    base::span<float> values,
     double sample_rate,
     double control_rate,
     unsigned render_quantum_frames) {
-  DCHECK(values);
-  DCHECK_GE(number_of_values, 1u);
+  DCHECK_GE(values.size(), 1u);
 
   // Return default value if there are no events matching the desired time
   // range.
   if (!events_.size() || (end_frame / sample_rate <= events_[0]->Time())) {
-    FillWithDefault(values, default_value, number_of_values, 0);
-
+    std::ranges::fill(values, default_value);
     return default_value;
   }
 
@@ -1047,8 +1033,7 @@
     double current_time = start_frame / sample_rate;
 
     if (HandleAllEventsInThePast(current_time, sample_rate, default_value,
-                                 number_of_values, values,
-                                 render_quantum_frames)) {
+                                 values, render_quantum_frames)) {
       return default_value;
     }
   }
@@ -1057,15 +1042,15 @@
   // If first event is after startFrame then fill initial part of values buffer
   // with defaultValue until we reach the first event time.
   auto [current_frame, write_index] =
-      HandleFirstEvent(values, default_value, number_of_values, start_frame,
-                       end_frame, sample_rate, start_frame, 0);
+      HandleFirstEvent(values, default_value, start_frame, end_frame,
+                       sample_rate, start_frame, 0);
 
   float value = default_value;
 
   // Go through each event and render the value buffer where the times overlap,
   // stopping when we've rendered all the requested values.
   int last_skipped_event_index = 0;
-  for (int i = 0; i < number_of_events && write_index < number_of_values; ++i) {
+  for (int i = 0; i < number_of_events && write_index < values.size(); ++i) {
     ParamEvent* event = events_[i].get();
     ParamEvent* next_event =
         i < number_of_events - 1 ? events_[i + 1].get() : nullptr;
@@ -1118,24 +1103,14 @@
     }
 
     DCHECK_GE(fill_to_end_frame, start_frame);
-    unsigned fill_to_frame =
-        static_cast<unsigned>(fill_to_end_frame - start_frame);
-    fill_to_frame = std::min(fill_to_frame, number_of_values);
+    size_t fill_to_frame = fill_to_end_frame - start_frame;
+    fill_to_frame = std::min(fill_to_frame, values.size());
 
     const AutomationState current_state = {
-        number_of_values,
-        start_frame,
-        end_frame,
-        sample_rate,
-        control_rate,
-        fill_to_frame,
-        fill_to_end_frame,
-        value1,
-        time1,
-        value2,
-        time2,
-        event,
-        i,
+        start_frame,  end_frame,     sample_rate,
+        control_rate, fill_to_frame, fill_to_end_frame,
+        value1,       time1,         value2,
+        time2,        event,         i,
     };
 
     // First handle linear and exponential ramps which require looking ahead to
@@ -1156,8 +1131,9 @@
 
           // Simply stay at a constant value.
           value = event->Value();
-          write_index =
-              FillWithDefault(values, value, fill_to_frame, write_index);
+          std::ranges::fill(
+              values.subspan(write_index, fill_to_frame - write_index), value);
+          write_index = fill_to_frame;
           break;
         }
 
@@ -1174,9 +1150,9 @@
           // the values after the end of the ramp, we just want to
           // continue with the ramp end value.
           value = event->Value();
-          write_index =
-              FillWithDefault(values, value, fill_to_frame, write_index);
-
+          std::ranges::fill(
+              values.subspan(write_index, fill_to_frame - write_index), value);
+          write_index = fill_to_frame;
           break;
         }
 
@@ -1210,17 +1186,16 @@
 
   // If there's any time left after processing the last event then just
   // propagate the last value to the end of the values buffer.
-  write_index = FillWithDefault(values, value, number_of_values, write_index);
+  std::ranges::fill(values.subspan(write_index), value);
 
   // This value is used to set the `.value` attribute of the AudioParam.  it
   // should be the last computed value.
-  return values[number_of_values - 1];
+  return values.back();
 }
 
 std::tuple<size_t, unsigned> AudioParamTimeline::HandleFirstEvent(
-    float* values,
+    base::span<float> values,
     float default_value,
-    unsigned number_of_values,
     size_t start_frame,
     size_t end_frame,
     double sample_rate,
@@ -1237,12 +1212,11 @@
     }
     DCHECK_GE(fill_to_end_frame, start_frame);
 
-    unsigned fill_to_frame =
-        static_cast<unsigned>(fill_to_end_frame - start_frame);
-    fill_to_frame = std::min(fill_to_frame, number_of_values);
-    write_index =
-        FillWithDefault(values, default_value, fill_to_frame, write_index);
-
+    size_t fill_to_frame = fill_to_end_frame - start_frame;
+    fill_to_frame = std::min(fill_to_frame, values.size());
+    std::ranges::fill(values.subspan(write_index, fill_to_frame - write_index),
+                      default_value);
+    write_index = fill_to_frame;
     current_frame += fill_to_frame;
   }
 
@@ -1313,8 +1287,7 @@
     double current_time,
     double sample_rate,
     float& default_value,
-    unsigned number_of_values,
-    float* values,
+    base::span<float> values,
     unsigned render_quantum_frames) {
   // Optimize the case where the last event is in the past.
   ParamEvent* last_event = events_[events_.size() - 1].get();
@@ -1350,7 +1323,7 @@
     // Since all events are now also in the past, we can just remove all
     // timeline events too because `default_value` has the expected
     // value.
-    FillWithDefault(values, default_value, number_of_values, 0);
+    std::ranges::fill(values, default_value);
     RemoveOldEvents(events_.size());
 
     return true;
@@ -1510,13 +1483,10 @@
 
 std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessLinearRamp(
     const AutomationState& current_state,
-    float* values,
+    base::span<float> values,
     size_t current_frame,
     float value,
     unsigned write_index) {
-#if defined(ARCH_CPU_X86_FAMILY)
-  auto number_of_values = current_state.number_of_values;
-#endif
   auto fill_to_frame = current_state.fill_to_frame;
   auto time1 = current_state.time1;
   auto time2 = current_state.time2;
@@ -1556,12 +1526,15 @@
     unsigned fill_to_frame_trunc =
         write_index + ((fill_to_frame - write_index) / 4) * 4;
     // Compute final time.
-    DCHECK_LE(fill_to_frame_trunc, number_of_values);
+    DCHECK_LE(fill_to_frame_trunc, values.size());
     current_frame += fill_to_frame_trunc - write_index;
 
     // Process 4 loop steps.
     for (; write_index < fill_to_frame_trunc; write_index += 4) {
-      _mm_storeu_ps(values + write_index, v_value);
+      // SAFETY: DCHECK previously checked that `fill_to_frame_trunc <
+      // values.size()`. In the for loop, `write_index < fill_to_frame_trunc` so
+      // this is safe.
+      _mm_storeu_ps(UNSAFE_BUFFERS(values.data() + write_index), v_value);
       v_value = _mm_add_ps(v_value, v_inc);
     }
   }
@@ -1573,20 +1546,22 @@
   }
 #endif
   // Serially process remaining values.
-  for (; write_index < fill_to_frame; ++write_index) {
-    float x = (current_frame / sample_rate - time1) * k;
-    // value = (1 - x) * value1 + x * value2;
-    value = value1 + x * value_delta;
-    values[write_index] = value;
-    ++current_frame;
-  }
+  std::ranges::generate(
+      values.subspan(write_index, fill_to_frame - write_index),
+      [=, &current_frame, &value]() {
+        float x = (current_frame / sample_rate - time1) * k;
+        // value = (1 - x) * value1 + x * value2;
+        value = value1 + x * value_delta;
+        ++current_frame;
+        return value;
+      });
 
-  return std::make_tuple(current_frame, value, write_index);
+  return std::make_tuple(current_frame, value, fill_to_frame);
 }
 
 std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessExponentialRamp(
     const AutomationState& current_state,
-    float* values,
+    base::span<float> values,
     size_t current_frame,
     float value,
     unsigned write_index) {
@@ -1603,9 +1578,9 @@
     // Handle this by propagating the previous value.
     value = value1;
 
-    for (; write_index < fill_to_frame; ++write_index) {
-      values[write_index] = value;
-    }
+    std::ranges::fill(values.subspan(write_index, fill_to_frame - write_index),
+                      value);
+    write_index = fill_to_frame;
   } else {
     double delta_time = time2 - time1;
     double num_sample_frames = delta_time * sample_rate;
@@ -1638,13 +1613,15 @@
     value = value1 *
             fdlibm::pow(value2 / static_cast<double>(value1),
                         (current_frame / sample_rate - time1) / delta_time);
-    for (double accumulator = value; write_index < fill_to_frame;
-         ++write_index) {
-      value = accumulator;
-      values[write_index] = value;
-      accumulator *= multiplier;
-      ++current_frame;
-    }
+    double accumulator = value;
+    std::ranges::generate(
+        values.subspan(write_index, fill_to_frame - write_index), [&]() {
+          value = accumulator;
+          accumulator *= multiplier;
+          ++current_frame;
+          return value;
+        });
+    write_index = fill_to_frame;
 
     // Due to roundoff it's possible that value exceeds value2.  Clip value
     // to value2 if we are within 1/2 frame of time2.
@@ -1658,13 +1635,10 @@
 
 std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessSetTarget(
     const AutomationState& current_state,
-    float* values,
+    base::span<float> values,
     size_t current_frame,
     float value,
     unsigned write_index) {
-#if defined(ARCH_CPU_X86_FAMILY)
-  auto number_of_values = current_state.number_of_values;
-#endif
   auto fill_to_frame = current_state.fill_to_frame;
   auto time1 = current_state.time1;
   auto value1 = current_state.value1;
@@ -1711,9 +1685,9 @@
   if (HasSetTargetConverged(value, target, current_frame / sample_rate, time1,
                             time_constant)) {
     current_frame += fill_to_frame - write_index;
-    for (; write_index < fill_to_frame; ++write_index) {
-      values[write_index] = target;
-    }
+    std::ranges::fill(values.subspan(write_index, fill_to_frame - write_index),
+                      target);
+    write_index = fill_to_frame;
   } else {
 #if defined(ARCH_CPU_X86_FAMILY)
     if (fill_to_frame > write_index) {
@@ -1738,7 +1712,7 @@
       // Process 4 loop steps.
       unsigned fill_to_frame_trunc =
           write_index + ((fill_to_frame - write_index) / 4) * 4;
-      DCHECK_LE(fill_to_frame_trunc, number_of_values);
+      DCHECK_LE(fill_to_frame_trunc, values.size());
 
       for (; write_index < fill_to_frame_trunc; write_index += 4) {
         delta = target - value;
@@ -1746,7 +1720,10 @@
         v_value = _mm_set_ps1(value);
 
         v_result = _mm_add_ps(v_value, _mm_mul_ps(v_delta, v_c));
-        _mm_storeu_ps(values + write_index, v_result);
+        // SAFETY: DCHECK previously checked that `fill_to_frame_trunc <
+        // values.size()`. In the for loop, `write_index < fill_to_frame_trunc`
+        // so this is safe.
+        _mm_storeu_ps(UNSAFE_BUFFERS(values.data() + write_index), v_result);
 
         // Update value for next iteration.
         value += delta * c3;
@@ -1754,14 +1731,18 @@
     }
 #endif
     // Serially process remaining values
-    for (; write_index < fill_to_frame; ++write_index) {
-      values[write_index] = value;
-      value += (target - value) * discrete_time_constant;
-    }
+    std::ranges::generate(
+        values.subspan(write_index, fill_to_frame - write_index), [&]() {
+          float v = value;
+          value += (target - value) * discrete_time_constant;
+          return v;
+        });
+    write_index = fill_to_frame;
+
     // The previous loops may have updated `value` one extra time.
     // Reset it to the last computed value.
-    if (write_index >= 1) {
-      value = values[write_index - 1];
+    if (fill_to_frame >= 1) {
+      value = values[fill_to_frame - 1];
     }
     current_frame = fill_to_end_frame;
   }
@@ -1771,11 +1752,10 @@
 
 std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessSetValueCurve(
     const AutomationState& current_state,
-    float* values,
+    base::span<float> values,
     size_t current_frame,
     float value,
     unsigned write_index) {
-  auto number_of_values = current_state.number_of_values;
   auto fill_to_frame = current_state.fill_to_frame;
   auto time1 = current_state.time1;
   auto sample_rate = current_state.sample_rate;
@@ -1784,9 +1764,7 @@
   auto fill_to_end_frame = current_state.fill_to_end_frame;
   auto* event = current_state.event.get();
 
-  const Vector<float> curve = event->Curve();
-  const float* curve_data = curve.data();
-  unsigned number_of_curve_points = curve.size();
+  base::span<const float> curve_data(event->Curve());
 
   float curve_end_value = event->CurveEndValue();
 
@@ -1796,13 +1774,12 @@
   // the term (N - 1)/Td in the specification.
   double curve_points_per_frame = event->CurvePointsPerSecond() / sample_rate;
 
-  if (!number_of_curve_points || duration <= 0 || sample_rate <= 0) {
+  if (curve_data.empty() || duration <= 0 || sample_rate <= 0) {
     // Error condition - simply propagate previous value.
     current_frame = fill_to_end_frame;
-    for (; write_index < fill_to_frame; ++write_index) {
-      values[write_index] = value;
-    }
-    return std::make_tuple(current_frame, value, write_index);
+    std::ranges::fill(values.subspan(write_index, fill_to_frame - write_index),
+                      value);
+    return std::make_tuple(current_frame, value, fill_to_frame);
   }
 
   // Save old values and recalculate information based on the curve's
@@ -1831,7 +1808,7 @@
   fill_to_frame = (fill_to_end_frame < start_frame)
                       ? 0
                       : static_cast<unsigned>(fill_to_end_frame - start_frame);
-  fill_to_frame = std::min(fill_to_frame, number_of_values);
+  fill_to_frame = std::min(fill_to_frame, values.size());
 
   // Index into the curve data using a floating-point value.
   // We're scaling the number of curve points by the duration (see
@@ -1857,7 +1834,7 @@
     const __m128 v_curve_virtual_index = _mm_set_ps1(curve_virtual_index);
     const __m128 v_curve_points_per_frame = _mm_set_ps1(curve_points_per_frame);
     const __m128 v_number_of_curve_points_m1 =
-        _mm_set_ps1(number_of_curve_points - 1);
+        _mm_set_ps1(curve_data.size() - 1);
     const __m128 v_n1 = _mm_set_ps1(1.0f);
     const __m128 v_n4 = _mm_set_ps1(4.0f);
 
@@ -1868,7 +1845,7 @@
     // Truncate loop steps to multiple of 4
     unsigned truncated_steps = ((fill_to_frame - write_index) / 4) * 4;
     unsigned fill_to_frame_trunc = write_index + truncated_steps;
-    DCHECK_LE(fill_to_frame_trunc, number_of_values);
+    DCHECK_LE(fill_to_frame_trunc, values.size());
 
     for (; write_index < fill_to_frame_trunc; write_index += 4) {
       // Compute current index this way to minimize round-off that would
@@ -1906,55 +1883,62 @@
       __m128 v_value =
           _mm_add_ps(v_c0, _mm_mul_ps(_mm_sub_ps(v_c1, v_c0), v_delta));
 
-      _mm_storeu_ps(values + write_index, v_value);
+      // SAFETY: DCHECK previously checked that `fill_to_frame_trunc <
+      // values.size()`. In the for loop, `write_index < fill_to_frame_trunc` so
+      // this is safe.
+      _mm_storeu_ps(UNSAFE_BUFFERS(values.data() + write_index), v_value);
     }
     // Pass along k to the serial loop.
     k = truncated_steps;
   }
+#endif
+
+  std::ranges::generate(
+      values.subspan(write_index, fill_to_frame - write_index), [&]() {
+        // Compute current index this way to minimize round-off that would
+        // have occurred by incrementing the index by curvePointsPerFrame.
+        double current_virtual_index =
+            curve_virtual_index + k * curve_points_per_frame;
+        size_t curve_index0;
+
+        // Clamp index to the last element of the array.
+        if (current_virtual_index < curve_data.size()) {
+          curve_index0 = static_cast<unsigned>(current_virtual_index);
+        } else {
+          curve_index0 = curve_data.size() - 1;
+        }
+
+        size_t curve_index1 = std::min(curve_index0 + 1, curve_data.size() - 1);
+
+        // Linearly interpolate between the two nearest curve points.  `delta`
+        // is clamped to 1 because `current_virtual_index` can exceed
+        // `curve_index0` by more than one.  This can happen when we reached the
+        // end of the curve but still need values to fill out the current
+        // rendering quantum.
+        DCHECK_LT(curve_index0, curve_data.size());
+        DCHECK_LT(curve_index1, curve_data.size());
+        float c0 = curve_data[curve_index0];
+        float c1 = curve_data[curve_index1];
+        double delta = std::min(current_virtual_index - curve_index0, 1.0);
+
+        ++k;
+        return c0 + (c1 - c0) * delta;
+      });
+
+  write_index = fill_to_frame;
   if (write_index >= 1) {
     value = values[write_index - 1];
   }
-#endif
-  for (; write_index < fill_to_frame; ++write_index, ++k) {
-    // Compute current index this way to minimize round-off that would
-    // have occurred by incrementing the index by curvePointsPerFrame.
-    double current_virtual_index =
-        curve_virtual_index + k * curve_points_per_frame;
-    unsigned curve_index0;
-
-    // Clamp index to the last element of the array.
-    if (current_virtual_index < number_of_curve_points) {
-      curve_index0 = static_cast<unsigned>(current_virtual_index);
-    } else {
-      curve_index0 = number_of_curve_points - 1;
-    }
-
-    unsigned curve_index1 =
-        std::min(curve_index0 + 1, number_of_curve_points - 1);
-
-    // Linearly interpolate between the two nearest curve points.  `delta` is
-    // clamped to 1 because `current_virtual_index` can exceed `curve_index0` by
-    // more than one.  This can happen when we reached the end of the curve but
-    // still need values to fill out the current rendering quantum.
-    DCHECK_LT(curve_index0, number_of_curve_points);
-    DCHECK_LT(curve_index1, number_of_curve_points);
-    float c0 = curve_data[curve_index0];
-    float c1 = curve_data[curve_index1];
-    double delta = std::min(current_virtual_index - curve_index0, 1.0);
-
-    value = c0 + (c1 - c0) * delta;
-
-    values[write_index] = value;
-  }
 
   // If there's any time left after the duration of this event and the
   // start of the next, then just propagate the last value of the
   // `curve_data`. Don't modify `value` unless there is time left.
   if (write_index < next_event_fill_to_frame) {
     value = curve_end_value;
-    for (; write_index < next_event_fill_to_frame; ++write_index) {
-      values[write_index] = value;
-    }
+    std::ranges::fill(
+        values.subspan(write_index, next_event_fill_to_frame - write_index),
+        value);
+    write_index = next_event_fill_to_frame;
   }
 
   // Re-adjust current time
@@ -1965,7 +1949,7 @@
 
 std::tuple<size_t, float, unsigned> AudioParamTimeline::ProcessCancelValues(
     const AutomationState& current_state,
-    float* values,
+    base::span<float> values,
     size_t current_frame,
     float value,
     unsigned write_index) {
@@ -2000,26 +1984,12 @@
   }
 
   // Simply stay at the current value.
-  for (; write_index < fill_to_frame; ++write_index) {
-    values[write_index] = value;
-  }
+  std::ranges::fill(values.subspan(write_index, fill_to_frame - write_index),
+                    value);
 
   current_frame = fill_to_end_frame;
 
-  return std::make_tuple(current_frame, value, write_index);
-}
-
-uint32_t AudioParamTimeline::FillWithDefault(float* values,
-                                             float default_value,
-                                             uint32_t end_frame,
-                                             uint32_t write_index) {
-  uint32_t index = write_index;
-
-  for (; index < end_frame; ++index) {
-    values[index] = default_value;
-  }
-
-  return index;
+  return std::make_tuple(current_frame, value, fill_to_frame);
 }
 
 void AudioParamTimeline::RemoveCancelledEvents(
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
index 57e8cad6..b3374fed 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
@@ -93,8 +93,7 @@
   float ValuesForFrameRange(size_t start_frame,
                             size_t end_frame,
                             float default_value,
-                            float* values,
-                            unsigned number_of_values,
+                            base::span<float> values,
                             double sample_rate,
                             double control_rate,
                             float min_value,
@@ -274,9 +273,6 @@
 
   // State of the timeline for the current event.
   struct AutomationState {
-    // Parameters for the current automation request.  Number of
-    // values to be computed for the automation request
-    const unsigned number_of_values;
     // Start and end frames for this automation request
     const size_t start_frame;
     const size_t end_frame;
@@ -286,7 +282,7 @@
     const double control_rate;
 
     // Parameters needed for processing the current event.
-    const unsigned fill_to_frame;
+    const size_t fill_to_frame;
     const size_t fill_to_end_frame;
 
     // Value and time for the current event
@@ -307,8 +303,7 @@
   float ValuesForFrameRangeImpl(size_t start_frame,
                                 size_t end_frame,
                                 float default_value,
-                                float* values,
-                                unsigned number_of_values,
+                                base::span<float> values,
                                 double sample_rate,
                                 double control_rate,
                                 unsigned render_quantum_frames)
@@ -337,16 +332,14 @@
   float ValueCurveAtTime(double t,
                          double time1,
                          double duration,
-                         const float* curve_data,
-                         unsigned curve_length);
+                         base::span<const float> curve_data);
 
   // Handles the special case where the first event in the timeline
   // starts after `start_frame`.  These initial values are filled using
   // `default_value`.  The updated `current_frame` and `write_index` is
   // returned.
-  std::tuple<size_t, unsigned> HandleFirstEvent(float* values,
+  std::tuple<size_t, unsigned> HandleFirstEvent(base::span<float> values,
                                                 float default_value,
-                                                unsigned number_of_values,
                                                 size_t start_frame,
                                                 size_t end_frame,
                                                 double sample_rate,
@@ -374,8 +367,7 @@
   bool HandleAllEventsInThePast(double current_time,
                                 double sample_rate,
                                 float& default_value,
-                                unsigned number_of_values,
-                                float* values,
+                                base::span<float> values,
                                 unsigned render_quantum_frames)
       EXCLUSIVE_LOCKS_REQUIRED(events_lock_);
 
@@ -407,7 +399,7 @@
   // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessLinearRamp(
       const AutomationState& current_state,
-      float* values,
+      base::span<float> values,
       size_t current_frame,
       float value,
       unsigned write_index);
@@ -417,7 +409,7 @@
   // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessExponentialRamp(
       const AutomationState& current_state,
-      float* values,
+      base::span<float> values,
       size_t current_frame,
       float value,
       unsigned write_index);
@@ -427,7 +419,7 @@
   // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessSetTarget(
       const AutomationState& current_state,
-      float* values,
+      base::span<float> values,
       size_t current_frame,
       float value,
       unsigned write_index);
@@ -437,7 +429,7 @@
   // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessSetValueCurve(
       const AutomationState& current_state,
-      float* values,
+      base::span<float> values,
       size_t current_frame,
       float value,
       unsigned write_index);
@@ -447,19 +439,11 @@
   // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessCancelValues(
       const AutomationState& current_state,
-      float* values,
+      base::span<float> values,
       size_t current_frame,
       float value,
       unsigned write_index) EXCLUSIVE_LOCKS_REQUIRED(events_lock_);
 
-  // Fill the output vector `values` with the value `default_value`,
-  // starting at `write_index` and continuing up to `end_frame`
-  // (exclusive).  `write_index` is updated with the new index.
-  uint32_t FillWithDefault(float* values,
-                           float default_value,
-                           uint32_t end_frame,
-                           uint32_t write_index);
-
   // When cancelling events, remove the items from `events_` starting
   // at the given index.  Update `new_events_` too.
   void RemoveCancelledEvents(wtf_size_t first_event_to_remove)
diff --git a/third_party/blink/renderer/platform/audio/vector_math.cc b/third_party/blink/renderer/platform/audio/vector_math.cc
index c16a05b..8f19754 100644
--- a/third_party/blink/renderer/platform/audio/vector_math.cc
+++ b/third_party/blink/renderer/platform/audio/vector_math.cc
@@ -119,28 +119,27 @@
              dest_stride, frames_to_process);
 }
 
-void Vclip(const float* source_p,
+void Vclip(base::span<const float> source_p,
            int source_stride,
            const float* low_threshold_p,
            const float* high_threshold_p,
-           float* dest_p,
-           int dest_stride,
-           uint32_t frames_to_process) {
+           base::span<float> dest_p,
+           int dest_stride) {
   float low_threshold = *low_threshold_p;
   float high_threshold = *high_threshold_p;
 
 #if DCHECK_IS_ON()
   // Do the same DCHECKs that |ClampTo| would do so that optimization paths do
   // not have to do them.
-  for (size_t i = 0u; i < frames_to_process; ++i) {
+  for (size_t i = 0u; i < dest_p.size(); ++i) {
     DCHECK(!std::isnan(source_p[i]));
   }
   // This also ensures that thresholds are not NaNs.
   DCHECK_LE(low_threshold, high_threshold);
 #endif
 
-  impl::Vclip(source_p, source_stride, &low_threshold, &high_threshold, dest_p,
-              dest_stride, frames_to_process);
+  impl::Vclip(source_p.data(), source_stride, &low_threshold, &high_threshold,
+              dest_p.data(), dest_stride, dest_p.size());
 }
 
 void Vclip(const float* source_p,
diff --git a/third_party/blink/renderer/platform/audio/vector_math.h b/third_party/blink/renderer/platform/audio/vector_math.h
index e7657ed..db7a62b 100644
--- a/third_party/blink/renderer/platform/audio/vector_math.h
+++ b/third_party/blink/renderer/platform/audio/vector_math.h
@@ -172,13 +172,12 @@
 //
 // where y = clip(x, low, high) = max(low, min(x, high)), effectively making
 // low <= y <= high.
-PLATFORM_EXPORT void Vclip(const float* source_p,
+PLATFORM_EXPORT void Vclip(base::span<const float> source_p,
                            int source_stride,
                            const float* low_threshold_p,
                            const float* high_threshold_p,
-                           float* dest_p,
-                           int dest_stride,
-                           uint32_t frames_to_process);
+                           base::span<float> dest_p,
+                           int dest_stride);
 
 PLATFORM_EXPORT void Vclip(const float* source_p,
                            int source_stride,
diff --git a/third_party/blink/renderer/platform/audio/vector_math_test.cc b/third_party/blink/renderer/platform/audio/vector_math_test.cc
index b372fd1a..586e317b 100644
--- a/third_party/blink/renderer/platform/audio/vector_math_test.cc
+++ b/third_party/blink/renderer/platform/audio/vector_math_test.cc
@@ -151,6 +151,7 @@
   T* p() const { return p_; }
   size_t size() const { return size_; }
   int stride() const { return static_cast<int>(memory_layout()->stride); }
+  base::span<T> as_span() const { return base::span<T>(p_.get(), size_); }
 
   bool operator==(const TestVector& other) const {
     return std::ranges::equal(*this, other, Equal);
@@ -365,8 +366,8 @@
       expected_dest[i] = ClampTo(source[i], low_threshold, high_threshold);
     }
     for (auto& dest : GetSecondaryVectors(GetDestination(1u), source)) {
-      Vclip(source.p(), source.stride(), &low_threshold, &high_threshold,
-            dest.p(), dest.stride(), source.size());
+      Vclip(source.as_span(), source.stride(), &low_threshold, &high_threshold,
+            dest.as_span(), dest.stride());
       EXPECT_EQ(expected_dest, dest);
     }
   }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a22a6e1..a8a2f8e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2826,7 +2826,7 @@
 crbug.com/418804941 [ Mac11-arm64 ] external/wpt/pointerevents/pointerevent_lostpointercapture_remove_setcapture_node.html [ Timeout ]
 crbug.com/418804941 [ Mac11 ] external/wpt/pointerevents/pointerevent_lostpointercapture_remove_setcapture_node.html [ Timeout ]
 crbug.com/418804941 [ Linux ] external/wpt/pointerevents/pointerevent_lostpointercapture_remove_setcapture_node.html [ Timeout ]
-crbug.com/418804914 [ Mac15 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html [ Timeout ]
+crbug.com/418804914 [ Mac15 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html [ Skip Timeout ]
 crbug.com/418466380 [ Win11 ] external/wpt/css/css-images/tiled-gradients.html [ Failure ]
 crbug.com/418466380 [ Win11-arm64 ] external/wpt/css/css-images/tiled-gradients.html [ Failure ]
 crbug.com/418466380 [ Win10.20h2 ] external/wpt/css/css-images/tiled-gradients.html [ Failure ]
@@ -2856,7 +2856,7 @@
 crbug.com/418466380 [ Mac11 ] virtual/gpu-rasterization/external/wpt/css/css-images/tiled-gradients.html [ Failure ]
 crbug.com/418466380 [ Linux ] virtual/gpu-rasterization/external/wpt/css/css-images/tiled-gradients.html [ Failure ]
 crbug.com/418370871 [ Win11 ] virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechRecognition-installOnDevice.https.html [ Timeout ]
-crbug.com/418277794 [ Mac14 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html [ Timeout ]
+crbug.com/418277794 [ Mac14 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html [ Skip Timeout ]
 crbug.com/418175808 [ Mac12 ] external/wpt/html/cross-origin-embedder-policy/credentialless/reporting-subresource-corp.https.window.html [ Skip Timeout ]
 crbug.com/418024434 [ Mac13 ] external/wpt/html/document-isolation-policy/service-worker-coep-credentialless-proxy.https.tentative.window.html [ Timeout ]
 crbug.com/418031072 [ Linux ] external/wpt/webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestLists/content_shell.filter b/third_party/blink/web_tests/TestLists/content_shell.filter
index 111631be..7715ba6 100644
--- a/third_party/blink/web_tests/TestLists/content_shell.filter
+++ b/third_party/blink/web_tests/TestLists/content_shell.filter
@@ -982,7 +982,7 @@
 virtual/speculation-rules-prerender-target-hint/external/wpt/speculation-rules/prerender/restriction-speech-synthesis.html
 virtual/speech-with-unified-autoplay/external/wpt/speech-api/idlharness.window.html
 virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechSynthesis*
-virtual/stable/external/wpt/soft-navigation-heuristics/disabled.html
+virtual/stable/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp.html
 virtual/third-party-storage-partitioning/external/wpt/service-workers/service-worker/partitioned-matchAll.tentative.https.html
 virtual/threaded/external/wpt/css/css-backgrounds/background-attachment-fixed-inline-002.html
 virtual/threaded/external/wpt/css/css-backgrounds/background-clip/clip-text-*
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index e924034..6671fc8e 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -364,7 +364,7 @@
               "media/stable",
               "webexposed",
               "compositing/filters",
-              "external/wpt/soft-navigation-heuristics/disabled.html",
+              "external/wpt/soft-navigation-heuristics/smoke/tentative/lcp.html",
               "wpt_internal/performance-timeline/performance-user-timing-mark-feature-usage.html"
             ],
     "exclusive_tests": ["media/stable"],
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 cca146e..3111185 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
@@ -134437,6 +134437,19 @@
         ],
         {}
        ]
+      ],
+      "flex-gap-decorations-023.html": [
+       "9a7c429a1a15719e3b4f799570e7789c18eafe4a",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/agnostic/gap-decorations-006-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
       ]
      },
      "grid": {
@@ -134908,6 +134921,19 @@
         {}
        ]
       ],
+      "grid-gap-decorations-039.html": [
+       "c03d482ac495fc6b29d742fda8682d2bb8060174",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/agnostic/gap-decorations-006-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "grid-gap-decorations-38.html": [
        "8b87bcd4860ac50a1c2f3de98cec9599bebb77a3",
        [
@@ -135143,6 +135169,19 @@
         ],
         {}
        ]
+      ],
+      "multicol-gap-intersections-018.html": [
+       "b8f8e1619a0dc25c6824cb2cd441635d93885e06",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
       ]
      }
     },
@@ -350692,6 +350731,10 @@
       "gap-decorations-003-ref.html": [
        "52e45c4f65f01e5eb98a98590788a0af7bcf7230",
        []
+      ],
+      "gap-decorations-006-ref.html": [
+       "09bef415d402fb2cf9025bdfc6bd887902a439a9",
+       []
       ]
      },
      "flex": {
@@ -350970,6 +351013,10 @@
       "multicol-gap-decorations-017-ref.html": [
        "23fd089ac8e575e4035c5614c10ae55d7c3b06a4",
        []
+      ],
+      "multicol-gap-decorations-018-ref.html": [
+       "521d39250624e99afccf528824bab05b36e8f17d",
+       []
       ]
      }
     },
@@ -388401,10 +388448,18 @@
       []
      ],
      "resources": {
+      "fetch-private-http.html": [
+       "e372d90b26a02bdfa0b9a34c9c8ad956b5d0cc02",
+       []
+      ],
       "fetch-private.html": [
        "b96a207ec33a13e5dd4c53083ac3d73123b23cbb",
        []
       ],
+      "fetch-public-http-wrong-address-space.html": [
+       "1d149d00cb351b9aaa4402b9b8b7d975d56a9acb",
+       []
+      ],
       "support.sub.js": [
        "774e34d0a6fe59bab19aca14cb71b6e520acb798",
        []
@@ -393245,7 +393300,7 @@
         []
        ],
        "OWNERS": [
-        "263ee12ddb3e9a1f485fcc61802915f7bfb14bcd",
+        "db5debfcc6a4fcaa50d34165ae3e08165ee0615d",
         []
        ],
        "README.md": [
@@ -426321,10 +426376,6 @@
     }
    },
    "soft-navigation-heuristics": {
-    "disabled-expected.txt": [
-     "fc1c1b9908df6e2a8cf2dda4faa54b693537484c",
-     []
-    ],
     "resources": {
      "empty.html": [
       "5fa1cdf5e66008396ab71673dbb9386066d7cc5f",
@@ -426337,7 +426388,19 @@
      "soft-navigation-helper.js": [
       "c9f2b41b552855d6cbd049008c314fe4c953464b",
       []
+     ],
+     "soft-navigation-test-helper.js": [
+      "a572f55e66dbce825d399f61c4a2dfa34df9b4ca",
+      []
      ]
+    },
+    "smoke": {
+     "tentative": {
+      "almost-soft-navigation-expected.txt": [
+       "36456e16370b5ac50a176307e7e831a27135fe84",
+       []
+      ]
+     }
     }
    },
    "speculation-rules": {
@@ -439103,23 +439166,23 @@
     },
     "depth-sensing": {
      "dataUnavailableTests.js": [
-      "7460af71326291923e7a5406ea4773be0953137f",
+      "cd503aa5f146a0cfbca4b1eaaecc936125ff84d2",
       []
      ],
      "inactiveFrameTests.js": [
-      "0cc425955374e214cd5dd9bdb75a654c7c69faa9",
+      "e08d9b5a12dd2b7e47d3fb19512fa17864b38d66",
       []
      ],
      "matchDepthViewValues.js": [
-      "7bd1b37b7c36539f92325da01417660f97feda79",
+      "3c76a5e9576fa8683e1aea9033032c0563e3cd63",
       []
      ],
      "pauseResumeTests.js": [
-      "e7513ef61c13b856ea9e49ff93ad9088e57163b3",
+      "82bb72170be3313dadf0bcf3a46b18325552b073",
       []
      ],
      "staleViewsTests.js": [
-      "b1f11c9651d8d85e0acbb1123c35216857dfdf5b",
+      "4080ea6230951b03198b795f9631ee56a3691f9e",
       []
      ]
     },
@@ -440748,14 +440811,6 @@
      []
     ],
     "formdata": {
-     "append.any-expected.txt": [
-      "3d2ae96ef2a3c9f65deca98276041b340dfc4ef9",
-      []
-     ],
-     "append.any.worker-expected.txt": [
-      "3d2ae96ef2a3c9f65deca98276041b340dfc4ef9",
-      []
-     ],
      "set-blob.any-expected.txt": [
       "0708771ed774756cdcc1d55915d80bf4f3af87c2",
       []
@@ -478437,29 +478492,32 @@
     ],
     "iframes": {
      "dialog-same-origin-nn.html": [
-      "250fbf7e5f733b89449203b7b881c8f710898dbd",
+      "b2da2d415a835bce1e27ebf439294f87a84785ed",
       [
        null,
        {
-        "testdriver": true
+        "testdriver": true,
+        "timeout": "long"
        }
       ]
      ],
      "dialog-same-origin-ynn.html": [
-      "b5cfab5c5d91315103796e783e1187757932e3db",
+      "3ab5b758684d7792781b82808e0f68c4bff0ad20",
       [
        null,
        {
-        "testdriver": true
+        "testdriver": true,
+        "timeout": "long"
        }
       ]
      ],
      "dialog-same-origin-ynyn.html": [
-      "4f55e9b24aa61d026603f2448f81dfe1b9858a8e",
+      "e486fcb36828e9abda642e7f3923c97925f42e40",
       [
        null,
        {
-        "testdriver": true
+        "testdriver": true,
+        "timeout": "long"
        }
       ]
      ]
@@ -505994,29 +506052,36 @@
         {}
        ]
       ],
-      "gap-decorations-rule-shorthand-computed-from-longhands.html": [
-       "562c166e90b3cc983c117c8deec63a1b3105cb35",
+      "gap-decorations-rule-shorthand-computed.html": [
+       "686560d87d035393bcbb15820b9ce19081ff5ad4",
        [
         null,
         {}
        ]
       ],
-      "gap-decorations-rule-shorthand-computed.html": [
-       "7bb3e1858dd9fef26389628aa5ea11cab06fb22d",
+      "gap-decorations-rule-shorthand-from-longhands.tentative.html": [
+       "ed7c9a317e66984cd3420470819a3de75749c8c2",
        [
         null,
         {}
        ]
       ],
       "gap-decorations-rule-shorthand-invalid.html": [
-       "f7c6b45b16d08e9a3e1db4587dba27ab95b91829",
+       "b8ba8b01136c2aef4739da3ef6c8a7f775b829b8",
+       [
+        null,
+        {}
+       ]
+      ],
+      "gap-decorations-rule-shorthand-valid.html": [
+       "9b37ed7b9a627f51892c5ef4f7ab9dd9b9133b0c",
        [
         null,
         {}
        ]
       ],
       "gap-decorations-rule-shorthand.html": [
-       "420b6757e7fafd4b7d49c4f4aef2ef17a0552704",
+       "f65ab342a3d9303990c7bc99d89a8422570c445b",
        [
         null,
         {}
@@ -580059,7 +580124,7 @@
     },
     "local-network-access": {
      "fetch.tentative.https.html": [
-      "9c591f309b75af6731c6d6be9c0907d3b8c22618",
+      "ac2c3cca28eaf2c0a36d3350aa92d87d1ba75b34",
       [
        null,
        {
@@ -651635,7 +651700,7 @@
         ]
        ],
        "dialog-closedby-corner-cases.html": [
-        "511acaccef334c8ad5c6255c7543b8cf69e1801f",
+        "2c9dff9753abfa76a67c0f97505e9f5c5edaa81a",
         [
          null,
          {
@@ -713492,15 +713557,19 @@
       }
      ]
     ],
-    "disabled.html": [
-     "b53c2f701222c4a85e80d2f604ea34baef2b859b",
-     [
-      null,
-      {
-       "testdriver": true
-      }
-     ]
-    ],
+    "detection": {
+     "tentative": {
+      "racing-soft-navigations.html": [
+       "ba510b717e5232d0349fa7bd83d8e68e41edc7a9",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ]
+     }
+    },
     "dropped-entries.tentative.html": [
      "d27ad452be07b778aea1aff5525d1670fb66ec5f",
      [
@@ -713784,6 +713853,15 @@
         }
        ]
       ],
+      "lcp.html": [
+       "eb19c01494dcdb99c5bedb78b5242059563436f1",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "task-attribution.html": [
        "8f6f93c8daf6c089efd0eee7fefdc1a8ffa704f1",
        [
@@ -814828,14 +814906,14 @@
     "depth-sensing": {
      "cpu": {
       "depth_sensing_cpu_dataUnavailable.https.html": [
-       "e120f0b7dd161a01059ebf9bb773cbb706721d48",
+       "c3942c9ab251d7654846965336d9f8f6a0fef5dc",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_cpu_inactiveFrame.https.html": [
-       "c6ac8c60b0a765ecc893d7b5e0e7555c3ddabf51",
+       "6af5febff744bc3f1928fcb168d4ec4423f17e76",
        [
         null,
         {}
@@ -814863,21 +814941,21 @@
        ]
       ],
       "depth_sensing_cpu_matchDepthViewIdentity.https.html": [
-       "df1b52bacb8ba021668859b8ca17046a8a394420",
+       "306ad03fa04aeefcca53c8a65c68ea48dc2bfe25",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_cpu_pauseResume.https.html": [
-       "47469f4a0ea186e981843db8c00a1d72bc938907",
+       "78c5c89f7a9c9d4d31bbcc33784bbf53724d6960",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_cpu_staleView.https.html": [
-       "6a411ace451f817ba20c69a3eca22b55c536a56a",
+       "04b346ebfcb86d06be3815f87ec6059b0cde755a",
        [
         null,
         {}
@@ -814914,14 +814992,14 @@
      ],
      "gpu": {
       "depth_sensing_gpu_dataUnavailable.https.html": [
-       "018edf7693452d69753758dc0db8e25a36d8615c",
+       "de67b712e01dba01c9079d4ca0eeb5830c0fc1e9",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_gpu_inactiveFrame.https.html": [
-       "8528b4f80d85b44dad93dafc92ce598b8ea79bb0",
+       "9bd850ab9c9966862becc1be767256c48f706577",
        [
         null,
         {}
@@ -814935,21 +815013,21 @@
        ]
       ],
       "depth_sensing_gpu_matchDepthViewIdentity.https.html": [
-       "cd78212423847bf0852c0b8288d1c12bc75a48dc",
+       "a6f1eb184e967192cb20e9d00db194a0c41eb327",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_gpu_pauseResume.https.html": [
-       "d51edb8cd3b85192fc5904df9f488e7c32356080",
+       "8be32feb807d8825e238c6d9cfe8e8dc4e09bb71",
        [
         null,
         {}
        ]
       ],
       "depth_sensing_gpu_staleView.https.html": [
-       "ecd0d479f7aac7222d512edeafef9565993add1d",
+       "95a0c6f78254ceb431edbb8bbc3a139d79009d5c",
        [
         null,
         {}
@@ -820704,7 +820782,7 @@
       ]
      ],
      "append.any.js": [
-      "fb365618d20b281fd59a2c3b2ab4435e323c2f02",
+      "6871f69df591cc468e5fd99ae6456d48ad96e3a9",
       [
        "xhr/formdata/append.any.html",
        {
diff --git a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html
index 250fbf7..b2da2d41 100644
--- a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html
+++ b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-nn.html
@@ -1,4 +1,5 @@
 <!doctype html>
+<meta name="timeout" content="long">
 <link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html
index b5cfab5c..3ab5b75 100644
--- a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html
+++ b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html
@@ -1,4 +1,5 @@
 <!doctype html>
+<meta name="timeout" content="long">
 <link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html
index 4f55e9b..e486fcb3 100644
--- a/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html
+++ b/third_party/blink/web_tests/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html
@@ -1,4 +1,5 @@
 <!doctype html>
+<meta name="timeout" content="long">
 <link rel="author" href="mailto:wpt@keithcirkel.co.uk" />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/agnostic/gap-decorations-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/agnostic/gap-decorations-006-ref.html
new file mode 100644
index 0000000..09bef41
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/agnostic/gap-decorations-006-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+    body {
+        margin: 0px;
+    }
+
+  .container {
+    display: flex;
+    width: 110px;
+    height: 110px;
+    column-gap: 10px;
+    row-gap: 10px;
+    flex-wrap: wrap;
+  }
+
+  .item {
+    background: skyblue;
+    height: 50px;
+    width: 50px;
+    margin: 0;
+  }
+
+  .row-gap {
+    position: absolute;
+    top: 50px;
+    background: green;
+    width: 110px;
+    height: 10px;
+  }
+
+  .column-gap {
+    position: absolute;
+    top: 0px;
+    left: 50px;
+    background: pink;
+    height: 110px;
+    width: 10px;
+  }
+
+</style>
+<div class="container">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+</div>
+<button id="btn">Set decorations</button>
+
+<div class="column-gap"></div>
+<div class="row-gap"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-023.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-023.html
new file mode 100644
index 0000000..9a7c429a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/flex/flex-gap-decorations-023.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>
+    CSS Gap Decorations: flex gaps are painted when going from no gap rule to a gap rule that would be visible.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="../agnostic/gap-decorations-006-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+    body {
+        margin: 0px;
+    }
+
+    .flex-container {
+        height: 110px;
+        width: 110px;
+
+        display: flex;
+
+        column-gap: 10px;
+        row-gap: 10px;
+
+        flex-wrap: wrap;
+    }
+
+    .flex-item {
+        background: skyblue;
+        width: 50px;
+    }
+</style>
+<script>
+    function setup() {
+        const button = document.getElementById('btn');
+        button.click();
+    }
+
+    function setDecorations() {
+        const container = document.querySelector('.flex-container');
+        if (container) {
+            container.style.columnRuleStyle = 'solid';
+            container.style.columnRuleWidth = '10px';
+            container.style.columnRuleColor = 'pink';
+            container.style.rowRuleStyle = 'solid';
+            container.style.rowRuleWidth = '10px';
+            container.style.rowRuleColor = 'green';
+        }
+    }
+</script>
+
+<body onload="setup()">
+    <div class="flex-container">
+        <div class="flex-item"></div>
+        <div class="flex-item"></div>
+        <div class="flex-item"></div>
+        <div class="flex-item"></div>
+    </div>
+    <button onclick="setDecorations()" id="btn">Set decorations</button>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-039.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-039.html
new file mode 100644
index 0000000..c03d482
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/grid/grid-gap-decorations-039.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<title>
+  CSS Gap Decorations: grid column gaps are painted with solid styling.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="../agnostic/gap-decorations-006-ref.html">
+<link rel="author" title="Sam Davis Omekara Jr." href="mailto:samomekarajr@microsoft.com">
+<style>
+  body {
+    margin: 0px;
+  }
+
+  .grid-container {
+    height: 110px;
+    width: 110px;
+
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+
+    column-gap: 10px;
+    row-gap: 10px;
+
+    column-rule-color: pink;
+    column-rule-style: solid;
+    column-rule-width: 10px;
+
+    row-rule-color: green;
+    row-rule-style: solid;
+    row-rule-width: 10px;
+  }
+
+  .grid-item {
+    background: skyblue;
+  }
+</style>
+<script>
+  function setup() {
+    const button = document.getElementById('btn');
+    button.click();
+  }
+
+  function setDecorations() {
+    const container = document.querySelector('.grid-container');
+    if (container) {
+      container.style.columnRuleStyle = 'solid';
+      container.style.columnRuleWidth = '10px';
+      container.style.columnRuleColor = 'pink';
+      container.style.rowRuleStyle = 'solid';
+      container.style.rowRuleWidth = '10px';
+      container.style.rowRuleColor = 'green';
+    }
+  }
+</script>
+
+<body onload="setup()">
+  <div class="grid-container">
+    <div class="grid-item"></div>
+    <div class="grid-item"></div>
+    <div class="grid-item"></div>
+    <div class="grid-item"></div>
+  </div>
+  <button onclick="setDecorations()" id="btn">Set decorations</button>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html
new file mode 100644
index 0000000..521d392
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+    body {
+        margin: 0px;
+    }
+
+    .container {
+        border: 2px solid rgb(96 139 168);
+        width: 200px;
+        height: 130px;
+        column-gap: 10px;
+        display: flex;
+    }
+
+    .items {
+        background: rgb(96 139 168 / 0.2);
+        height: 130px;
+        margin: 0px;
+        width: 60px;
+    }
+
+    .row-gap {
+        position: absolute;
+        height: 10px;
+        width: 200px;
+        background: gold;
+        left: 2px;
+        top: 62px;
+    }
+
+    .column-gap {
+        position: absolute;
+        height: 130px;
+        width: 10px;
+        background: blue;
+        top: 2px;
+    }
+</style>
+
+<div class="container">
+    <div class="items"></div>
+    <div class="items"></div>
+    <div class="items"></div>
+</div>
+<button onclick="setDecorations()" id="btn">Set decorations</button>
+<div class="column-gap" style="left:62px;"></div>
+<div class="column-gap" style="left:132px;"></div>
+<div class="row-gap"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-intersections-018.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-intersections-018.html
new file mode 100644
index 0000000..b8f8e16
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/multicol/multicol-gap-intersections-018.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>
+    CSS Gap Decorations: Multicolumn gap decorations that are added later are painted.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-gaps-1/">
+<link rel="match" href="multicol-gap-decorations-018-ref.html">
+<link rel="author" title="Javier Contreras" href="mailto:javiercon@microsoft.com">
+<style>
+    body {
+        margin: 0px;
+    }
+
+    .container {
+        border: 2px solid rgb(96 139 168);
+        width: 200px;
+        height: 130px;
+        column-count: 3;
+        column-width: 60px;
+        column-height: 60px;
+        column-gap: 10px;
+        row-gap: 10px;
+        column-wrap: wrap;
+    }
+
+    p {
+        background: rgb(96 139 168 / 0.2);
+        height: 60px;
+        margin: 0px;
+    }
+</style>
+<script>
+    function setup() {
+        const button = document.getElementById('btn');
+        button.click();
+    }
+
+    function setDecorations() {
+        const container = document.querySelector('.container');
+        if (container) {
+            container.style.columnRuleStyle = 'solid';
+            container.style.columnRuleWidth = '10px';
+            container.style.columnRuleColor = 'blue';
+            container.style.rowRuleStyle = 'solid';
+            container.style.rowRuleWidth = '10px';
+            container.style.rowRuleColor = 'gold';
+        }
+    }
+</script>
+
+<body onload="setup()">
+    <div class="container">
+        <p></p>
+        <p></p>
+        <p></p>
+        <p></p>
+        <p></p>
+        <p></p>
+    </div>
+    <button onclick="setDecorations()" id="btn">Set decorations</button>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html
index 7bb3e18..686560d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html
@@ -23,8 +23,8 @@
   }
 </style>
 <script>
-// TODO(samomekarajr): Add `row-rule` to this test when implemented.
-const properties = ["column-rule",];
+// TODO(samomekarajr): Add `rule` to this test when implemented.
+const properties = ["column-rule", "row-rule"];
 for (let property of properties) {
   const currentcolor = "rgb(0, 255, 0)";
   const mediumWidth = getComputedStyle(document.getElementById('reference')).columnRuleWidth;  // e.g. 3px.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html
index 23999a1a..ed7c9a3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html
@@ -64,11 +64,13 @@
   },
 ];
 
-// TODO(samomekarajr): Add `row-rule` to this test.
 const rule_properties = {
     'column-rule': ['columnRuleWidth',
                     'columnRuleStyle',
                     'columnRuleColor'],
+    'row-rule':    ['rowRuleWidth',
+                    'rowRuleStyle',
+                    'rowRuleColor'],
 };
 
 for(rule_property in rule_properties) {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html
index f7c6b45..b8ba8b0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html
@@ -12,8 +12,8 @@
 </head>
 <body>
 <script>
-// TODO(samomekarajr): Add `row-rule` and `rule` to this test.
-const properties = ["column-rule",];
+// TODO(samomekarajr): Add `rule` to this test.
+const properties = ["column-rule", "row-rule"];
 for (let property of properties) {
     test_invalid_value(property, "auto");
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html
index f9799ed..9b37ed7b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html
@@ -13,8 +13,8 @@
 <body>
 <script>
 
-// TODO(samomekarajr): Add `row-rule` and `rule` to this test.
-const properties = ["column-rule",];
+// TODO(samomekarajr): Add `rule` to this test.
+const properties = ["column-rule", "row-rule"];
 for (let property of properties) {
     // <gap-rule> = [<line-width> || <line-style> || <line-color>]
     test_valid_value(property, "5px solid red");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand.html b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand.html
index 420b6757..f65ab34 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-gaps/parsing/gap-decorations-rule-shorthand.html
@@ -11,11 +11,13 @@
 </head>
 <body>
 <script>
-// TODO(samomekarajr): Add `row-rule` to this test.
 const rule_properties = {
     'column-rule': ['column-rule-width',
                     'column-rule-style',
                     'column-rule-color'],
+    'row-rule':    ['row-rule-width',
+                    'row-rule-style',
+                    'row-rule-color'],
 };
 
 for(rule_property in rule_properties) {
diff --git a/third_party/blink/web_tests/external/wpt/preload/preload-referrer-policy-subresource-header.tentative.html b/third_party/blink/web_tests/external/wpt/preload/preload-referrer-policy-subresource-header.tentative.html
index 0e1c9be..65f5afe 100644
--- a/third_party/blink/web_tests/external/wpt/preload/preload-referrer-policy-subresource-header.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/preload/preload-referrer-policy-subresource-header.tentative.html
@@ -1,5 +1,9 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
+<meta name=variant content="?isCrossOriginPreload=true&isCrossOriginResource=true">
+<meta name=variant content="?isCrossOriginPreload=true&isCrossOriginResource=false">
+<meta name=variant content="?isCrossOriginPreload=false&isCrossOriginResource=true">
+<meta name=variant content="?isCrossOriginPreload=false&isCrossOriginResource=false">
 <title>The referrerpolicy attribute on Link header should be ignored for subresources</title>
 <meta name="timeout" content="long">
 <script src="resources/dummy.js?link-header-preload2"></script>
@@ -64,17 +68,16 @@
 "strict-origin-when-cross-origin",
 "unsafe-url"]
 
+const params = new URLSearchParams(location.search);
+const isCrossOriginPreload = params.get('isCrossOriginPreload') === 'true';
+const isCrossOriginResource = params.get('isCrossOriginResource') === 'true';
 for (const preloadPolicy of policies) {
     for (const resourcePolicy of policies) {
-        for (const isCrossOriginPreload of [true, false]) {
-            for (const isCrossOriginResource of [true, false]) {
-                test_referrer_policy(
-                    preloadPolicy,
-                    resourcePolicy,
-                    isCrossOriginPreload,
-                    isCrossOriginResource);
-            }
-        }
+        test_referrer_policy(
+            preloadPolicy,
+            resourcePolicy,
+            isCrossOriginPreload,
+            isCrossOriginResource);
     }
 }
 
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/racing-soft-navigations.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/racing-soft-navigations.html
new file mode 100644
index 0000000..ba510b71
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/detection/tentative/racing-soft-navigations.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>Two soft navigations racing each other.</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/testdriver.js"></script>
+    <script src="/resources/testdriver-vendor.js"></script>
+    <script></script>
+  </head>
+  <body>
+    <div id="slow-soft-navigation">Click here!</div>
+    <div id="fast-soft-navigation">Click here!</div>
+
+    <script>
+      // This soft navigation is slow - it will wait 1s before it changes the URL.
+      function slowSoftNavigation(t) {
+        const greeting = document.createElement("div");
+        greeting.textContent = "Hello, World.";
+        document.body.appendChild(greeting);
+        t.step_timeout(() => history.pushState({}, "", "/slow-soft-navigation"), 1000);
+      }
+
+      // This soft navigation is fast - it will change the URL immediately.
+      function fastSoftNavigation() {
+        const greeting = document.createElement("div");
+        greeting.textContent = "Hello, World.";
+        document.body.appendChild(greeting);
+        history.pushState({}, "", "/fast-soft-navigation");
+      }
+
+      promise_test(async (t) => {
+        // TODO(crbug.com/418839741) - Update this test if/when we also detect the slow navigation.
+
+        document.getElementById("slow-soft-navigation").addEventListener("click", () => {
+          slowSoftNavigation(t);
+        });
+        document
+          .getElementById("fast-soft-navigation")
+          .addEventListener("click", fastSoftNavigation);
+
+        // Wait for the fast soft navigation to complete.
+        const promise = new Promise((resolve) => {
+          let entries = [];
+          new PerformanceObserver((list, observer) => {
+            entries.push(...list.getEntries());
+            if (entries.length >= 1) {
+              observer.disconnect();
+              resolve(entries);
+            }
+          }).observe({ type: "soft-navigation" });
+        });
+        // Start both soft navigations in rapid succession.
+        if (test_driver) {
+          test_driver.click(document.getElementById("slow-soft-navigation"));
+          test_driver.click(document.getElementById("fast-soft-navigation"));
+        }
+
+        // Notice that only the fast soft navigation is detected.
+        const entries = await promise;
+        assert_equals(entries.length, 1, "Expected just one soft navigation entry.");
+        assert_equals(
+          entries[0].name.replace(/.*\//, ""),
+          "fast-soft-navigation",
+          "First entry should be the fast soft navigation.",
+        );
+
+        // Wait for the effect of the slow soft navigation (URL change).
+        // We're not detecting this soft navigation for now. See crbug.com/418839741.
+        await t.step_wait(
+          () => location.href.replace(/.*\//, "") === "slow-soft-navigation",
+          "Expecting the slow navigation to eventually change the URL.",
+        );
+      }, "Two soft navigations that race each other should be detected correctly.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled-expected.txt b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled-expected.txt
deleted file mode 100644
index fc1c1b9..0000000
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that a soft navigation is not detected when the feature is disabled
-  promise_test: Unhandled rejection with value: "Soft navigation should not be triggered"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled.html
deleted file mode 100644
index b53c2f7..0000000
--- a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/disabled.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-<title>Detect simple soft navigation.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-<script src="resources/soft-navigation-helper.js"></script>
-</head>
-<body>
-  <main id=main>
-  <a id=link>Click me!</a>
-  </main>
-    <script>
-    const link = document.getElementById("link");
-    testSoftNavigationNotDetected({
-      eventHandler: url => {
-        addTextToDivOnMain();
-        history.pushState({}, '', 'foobar.html');
-      },
-      link: link,
-      eventName: "click",
-      eventTarget: link,
-      testName: "Test that a soft navigation is not detected when the feature "
-                + "is disabled"});
-  </script>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-test-helper.js b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-test-helper.js
new file mode 100644
index 0000000..a572f55e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/resources/soft-navigation-test-helper.js
@@ -0,0 +1,92 @@
+/**
+ * @fileoverview Helper class for soft navigation tests.
+ *
+ * This class provides helper functions for soft navigation tests. It can be
+ * used to wait for performance entries and create promises with timeout
+ * messages.
+ */
+class SoftNavigationTestHelper {
+  /**
+   * Constructs a new instance of the helper class.
+   * @param {!Test} test The test object. See
+   *     https://web-platform-tests.org/writing-tests/testharness-api.html#test-objects
+   */
+  constructor(test) {
+    this.test_ = test;
+  }
+
+  /**
+   * Wraps a promise with a timeout message, so that it rejects with this
+   * message if it does not resolve within the given timeout.
+   * @param {!Promise} promise The promise to wait for.
+   * @param {string} message The message to use if the promise times out.
+   * @param {number=} timeout The timeout in milliseconds. Defaults to 1000.
+   * @return {!Promise} The promise with a timeout message.
+   */
+  async withTimeoutMessage(promise, message, timeout = 1000) {
+    return Promise.race([
+      promise,
+      new Promise((resolve, reject) => {
+        this.test_.step_timeout(() => {
+          reject(new Error(message));
+        }, timeout);
+      }),
+    ]);
+  }
+
+  /**
+   * Creates a new promise with a timeout message, so that it rejects with this
+   * message if it does not resolve within the given timeout, and otherwise
+   * resolves.
+   * @param {!Function} executor The executor function to create the promise;
+   *     see
+   *     https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise#executor
+   * @param {string} message The message to use if the promise times out.
+   * @param {number=} timeout The timeout in milliseconds. Defaults to 1000.
+   * @return {!Promise} The promise with a timeout message.
+   */
+  async newPromiseWithTimeoutMessage(executor, message, timeout = 1000) {
+    return this.withTimeoutMessage(new Promise(executor), message, timeout);
+  }
+
+  /**
+   * Waits for a number of buffered performance entries of a given type,
+   * optionally including soft navigation observations, with a timeout message.
+   * @param {string} type The type of the entries to wait for.
+   * @param {boolean} includeSoftNavigationObservations Whether to include
+   *     soft navigation observations.
+   * @param {number} minNumEntries The minimum number of entries to wait for.
+   * @param {number=} timeout The timeout in milliseconds. Defaults to 1000.
+   * @return {!Promise} The promise, which either resolves with the entries or
+   *     rejects with a timeout message.
+   */
+  async getBufferedPerformanceEntriesWithTimeout(
+      type, includeSoftNavigationObservations, minNumEntries, timeout = 1000) {
+    let observer;
+    return this
+        .newPromiseWithTimeoutMessage(
+            (resolve) => {
+              const entries = [];
+              observer = new PerformanceObserver((list) => {
+                entries.push(...list.getEntries());
+                if (entries.length >= minNumEntries) {
+                  resolve(entries);
+                }
+              })
+              observer.observe({
+                type: type,
+                buffered: true,
+                includeSoftNavigationObservations:
+                    includeSoftNavigationObservations,
+              });
+            },
+            `${minNumEntries} entries of type ${type}${
+                includeSoftNavigationObservations ?
+                    ' with soft navigation observations' :
+                    ''} never arrived`,
+            timeout)
+        .finally(() => {
+          observer.disconnect();
+        });
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp.html b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp.html
new file mode 100644
index 0000000..eb19c01
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp.html
@@ -0,0 +1,153 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+    <title>Soft Navigation Detection: LCP.</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/testdriver.js"></script>
+    <script src="/resources/testdriver-vendor.js"></script>
+    <script src="/soft-navigation-heuristics/resources/soft-navigation-test-helper.js"></script>
+    <script>
+      // The click handler is triggered by user interaction; it modifies
+      // the DOM by adding an image to the page; this triggers both
+      // a soft navigation and a soft navigation LCP entry.
+      function clickHandler() {
+        const img = new Image();
+        img.src = "/images/lcp-256x256.png";
+        img.id = "lcp-img";
+        document.body.appendChild(img);
+        history.pushState({}, "", "/show-image");
+      }
+    </script>
+  </head>
+  <body>
+    <div id="click-target" onclick="clickHandler()">Click here!</div>
+
+    <script>
+      promise_test(async (t) => {
+        const helper = new SoftNavigationTestHelper(t);
+
+        // Wait for the initial LCP entry, prior to clicking, so that
+        // we may later observe the soft navigation LCP entry in addition.
+        const initial_lcp = await helper.getBufferedPerformanceEntriesWithTimeout(
+          /*type=*/ "largest-contentful-paint",
+          /*include_soft_navigation_observations=*/ false,
+          /*min_num_entries=*/ 1,
+        );
+
+        assert_equals(initial_lcp.length, 1, "There's one initial LCP entry.");
+        assert_equals(
+          initial_lcp[0].id,
+          "click-target",
+          "The initial LCP entry is the div for the click target.",
+        );
+
+        if (test_driver) {
+          test_driver.click(document.getElementById("click-target"));
+        }
+
+        // Now that we've clicked, we expect to see a soft navigation,
+        // and a soft navigation LCP entry; and since there was already
+        // an LCP entry, we expect two LCP entries.
+        const results = await Promise.allSettled([
+          helper.getBufferedPerformanceEntriesWithTimeout(
+            /*type=*/ "soft-navigation",
+            /*include_soft_navigation_observations=*/ true,
+            /*min_num_entries=*/ 1,
+          ),
+          helper.getBufferedPerformanceEntriesWithTimeout(
+            /*type=*/ "largest-contentful-paint",
+            /*include_soft_navigation_observations=*/ true,
+            /*min_num_entries=*/ 2,
+          ),
+        ]);
+
+        // If either or both of soft nav entry or soft nav LCP are missing,
+        // fail the test.
+        const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason.message);
+        if (errors.length > 0) {
+          throw new AssertionError("PerformanceObservers failed: " + format_value(errors));
+        }
+
+        // Examine the soft navigation entries.
+        const soft_navs = results[0].value;
+        assert_equals(soft_navs.length, 1, "Expecting one soft navigation entry.");
+        assert_equals(
+          soft_navs[0].name.replace(/.*\//, ""),
+          "show-image",
+          "Expecting soft navigation to 'greeting'",
+        );
+
+        // Examine the soft navigation LCP entries.
+        const lcp_including_soft_nav = results[1].value;
+        assert_equals(
+          lcp_including_soft_nav.length,
+          2,
+          "Expecting 2 entries: initial LCP and soft nav LCP.",
+        );
+
+        // Now observe the hard navs again. There should only be one entry.
+        // See also crbug.com/40073849: We really don't want to emit hard nav
+        // LCP entries for soft navigations unintentionally.
+        const observer = new PerformanceObserver(assert_unreached);
+        observer.observe({
+          type: "largest-contentful-paint",
+          buffered: true,
+        });
+        const hard_nav_lcp = observer.takeRecords();
+        observer.disconnect();
+
+        assert_equals(hard_nav_lcp.length, 1, "Expecting one entry for the hard nav LCP.");
+
+        // Compare the first soft nav LCP entry with the hard nav LCP entry.
+        assert_equals(
+          hard_nav_lcp[0].id,
+          "click-target",
+          "Hard nav LCP entry is (still) for the click target.",
+        );
+        assert_equals(
+          lcp_including_soft_nav[0].id,
+          "click-target",
+          "First soft nav LCP entry is for the click target.",
+        );
+        assert_equals(
+          lcp_including_soft_nav[1].id,
+          "lcp-img",
+          "Second soft nav LCP entry is for the image.",
+        );
+
+        assert_equals(
+          hard_nav_lcp[0],
+          lcp_including_soft_nav[0],
+          "Hard nav and first soft nav LCP entries are the same entry.",
+        );
+        // Since we don't rust assert_equals fully, we also compare
+        // render time and navigation ID. :-)
+        assert_equals(
+          hard_nav_lcp[0].renderTime,
+          lcp_including_soft_nav[0].renderTime,
+          "Hard nav and first soft nav LCP entries have the same render time.",
+        );
+        assert_equals(
+          hard_nav_lcp[0].navigationId,
+          lcp_including_soft_nav[0].navigationId,
+          "Hard nav and first soft nav LCP entries have the same navigation ID.",
+        );
+
+        // Compare the two soft nav LCP entries, and show that the navigation ID
+        // changes for the second one to be that of the soft navigation entry.
+        assert_not_equals(
+          lcp_including_soft_nav[0].navigationId,
+          lcp_including_soft_nav[1].navigationId,
+          "Soft nav LCP entries have have different navigation IDs.",
+        );
+        assert_equals(
+          lcp_including_soft_nav[1].navigationID,
+          soft_navs[0].navigationID,
+          "Second soft nav LCP entry has the same navigation ID as the soft nav entry.",
+        );
+      }, "Detect soft navigation and LCP after a click.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/disabled-expected.txt b/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/disabled-expected.txt
deleted file mode 100644
index d2490db..0000000
--- a/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/disabled-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This is a testharness.js-based test.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp-expected.txt b/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp-expected.txt
new file mode 100644
index 0000000..ad3a4ea6
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/stable/external/wpt/soft-navigation-heuristics/smoke/tentative/lcp-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Detect soft navigation and LCP after a click.
+  PerformanceObservers failed: ["1 entries of type soft-navigation with soft navigation observations never arrived", "2 entries of type largest-contentful-paint with soft navigation observations never arrived"]
+Harness: the test ran to completion.
+
diff --git a/third_party/crossbench b/third_party/crossbench
index de2f8a4..85adce1 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit de2f8a499257e1622a1c122fab1c84a46b98e469
+Subproject commit 85adce1424ed4df795f8c810fc1a8ee22bffe3fa
diff --git a/third_party/dawn b/third_party/dawn
index c4b1eaf..a3bfb33 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit c4b1eaf4958270e3a14c361720792dd073d6e4c5
+Subproject commit a3bfb33a777c75f77da36a7eb5ea4be24b86810f
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium
index 386b8ba6..6d3e50f 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: 729443409942a1816ddf74b95224003b83f4925c
-Date: 2025-05-07
+Version: ae3aba99db4c829b4cc4d9fdd54321dedd814dc4
+Date: 2025-05-15
 License: MPL-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/eigen3/src b/third_party/eigen3/src
index 7294434..ae3aba9 160000
--- a/third_party/eigen3/src
+++ b/third_party/eigen3/src
@@ -1 +1 @@
-Subproject commit 729443409942a1816ddf74b95224003b83f4925c
+Subproject commit ae3aba99db4c829b4cc4d9fdd54321dedd814dc4
diff --git a/third_party/fuchsia-gn-sdk/src/prepare_package_inputs.py b/third_party/fuchsia-gn-sdk/src/prepare_package_inputs.py
index 46b37f0..76c664c 100755
--- a/third_party/fuchsia-gn-sdk/src/prepare_package_inputs.py
+++ b/third_party/fuchsia-gn-sdk/src/prepare_package_inputs.py
@@ -65,9 +65,9 @@
     This is done by inspecting its FourCC header.
     """
 
-    with open(path, 'rb') as f:
-        file_tag = f.read(4)
-    return file_tag == b'\x7fELF'
+    output = subprocess.check_output(
+                ['file', path]).decode('utf8')
+    return 'ELF 64-bit' in output
 
 
 def _write_build_ids_txt(readelf_exec, binary_paths, ids_txt_path):
diff --git a/third_party/openscreen/src b/third_party/openscreen/src
index 4b64bb7..8cc5a0e 160000
--- a/third_party/openscreen/src
+++ b/third_party/openscreen/src
@@ -1 +1 @@
-Subproject commit 4b64bb75ad30c5d9e170caa21c6f5065583cb49c
+Subproject commit 8cc5a0e8f6695263d44206cf5930641979cb3179
diff --git a/third_party/pdfium b/third_party/pdfium
index 0be9b6b..9d59dcd 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit 0be9b6bf152df319d17d9e4b05b2845d3226f5a5
+Subproject commit 9d59dcd0a1e2781f2ac5c1c5f3ddb77e06173912
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index f81d458..afd1bd83 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -650,8 +650,8 @@
                              "defines",
                              "visibility",
                            ])
-    deps = []
-    public_deps = [ ":$_action_name" ]
+    deps = [ ":$_action_name" ]
+    public_deps = []
 
     # This will link any libraries in the deps (the use of invoker.deps in the
     # action won't link it).
diff --git a/third_party/pthreadpool/README.chromium b/third_party/pthreadpool/README.chromium
index 6e832e5..765fa3aa 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/google/pthreadpool
-Version: 290ee6fff0c36614702d6b297c148e3fa08e056a
-Date: 2025-04-22
+Version: dcc9f28589066af0dbd4555579281230abbf74dd
+Date: 2025-05-15
 License: BSD-2-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/pthreadpool/src b/third_party/pthreadpool/src
index 290ee6f..dcc9f28 160000
--- a/third_party/pthreadpool/src
+++ b/third_party/pthreadpool/src
@@ -1 +1 @@
-Subproject commit 290ee6fff0c36614702d6b297c148e3fa08e056a
+Subproject commit dcc9f28589066af0dbd4555579281230abbf74dd
diff --git a/third_party/search_engines_data/resources_internal b/third_party/search_engines_data/resources_internal
new file mode 160000
index 0000000..665a33d
--- /dev/null
+++ b/third_party/search_engines_data/resources_internal
@@ -0,0 +1 @@
+Subproject commit 665a33dd0140d181ed70ab33eda19e8c1c8c118d
diff --git a/third_party/skia b/third_party/skia
index 6064699..13a2999 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 60646997b471616ef833e5af7b395019a2cbb026
+Subproject commit 13a299964c9f66e7af63defde83b9c03055fa304
diff --git a/third_party/tflite/BUILD.gn b/third_party/tflite/BUILD.gn
index 1ccc957a..a3e2b8a 100644
--- a/third_party/tflite/BUILD.gn
+++ b/third_party/tflite/BUILD.gn
@@ -550,6 +550,7 @@
     "src/tensorflow/lite/kernels/fully_connected.cc",
     "src/tensorflow/lite/kernels/gather.cc",
     "src/tensorflow/lite/kernels/gather_nd.cc",
+    "src/tensorflow/lite/kernels/hadamard_rotation.cc",
     "src/tensorflow/lite/kernels/hashtable_lookup.cc",
     "src/tensorflow/lite/kernels/if.cc",
     "src/tensorflow/lite/kernels/kernel_util.cc",
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium
index b5c84b7..6157fa3 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: c4aa8ff91256b43fe0cecc246c77a00e2145b3bd
-Date: 2025-05-07
+Version: 151774faba661a5985a8264653f4457c70a56dea
+Date: 2025-05-15
 License: Caffe, Apache-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/tflite/src b/third_party/tflite/src
index c4aa8ff..151774f 160000
--- a/third_party/tflite/src
+++ b/third_party/tflite/src
@@ -1 +1 @@
-Subproject commit c4aa8ff91256b43fe0cecc246c77a00e2145b3bd
+Subproject commit 151774faba661a5985a8264653f4457c70a56dea
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn
index 89cc476..152366ce 100644
--- a/third_party/xnnpack/BUILD.gn
+++ b/third_party/xnnpack/BUILD.gn
@@ -186,7 +186,7 @@
     ":f32-rminmax_x64",
     ":f32-rsum_avx-no-avx2-no-f16c-no-fma",
     ":f32-rsum_avx512f",
-    ":f32-rsum_sse-no-sse2",
+    ":f32-rsum_sse2-no-sse3",
     ":f32-rsum_x64",
     ":f32-spmm_sse-no-sse2",
     ":f32-spmm_x64",
@@ -260,8 +260,7 @@
     ":f32-vrnd_x64",
     ":f32-vrsqrt_avx-no-avx2-no-f16c-no-fma",
     ":f32-vrsqrt_avx512f",
-    ":f32-vrsqrt_f16c-fma-no-avx2",
-    ":f32-vrsqrt_sse-no-sse2",
+    ":f32-vrsqrt_sse2-no-sse3",
     ":f32-vrsqrt_x64",
     ":f32-vsigmoid_avx-no-avx2-no-f16c-no-fma",
     ":f32-vsigmoid_avx512f",
@@ -276,8 +275,7 @@
     ":f32-vsin_x64",
     ":f32-vsqrt_avx-no-avx2-no-f16c-no-fma",
     ":f32-vsqrt_avx512f",
-    ":f32-vsqrt_f16c-fma-no-avx2",
-    ":f32-vsqrt_sse-no-sse2",
+    ":f32-vsqrt_sse2-no-sse3",
     ":f32-vsqrt_x64",
     ":f32-vtanh_avx-no-avx2-no-f16c-no-fma",
     ":f32-vtanh_avx512f",
@@ -692,7 +690,7 @@
     ":f32-rminmax_x64_standalone",
     ":f32-rsum_avx-no-avx2-no-f16c-no-fma_standalone",
     ":f32-rsum_avx512f_standalone",
-    ":f32-rsum_sse-no-sse2_standalone",
+    ":f32-rsum_sse2-no-sse3_standalone",
     ":f32-rsum_x64_standalone",
     ":f32-spmm_sse-no-sse2_standalone",
     ":f32-spmm_x64_standalone",
@@ -766,8 +764,7 @@
     ":f32-vrnd_x64_standalone",
     ":f32-vrsqrt_avx-no-avx2-no-f16c-no-fma_standalone",
     ":f32-vrsqrt_avx512f_standalone",
-    ":f32-vrsqrt_f16c-fma-no-avx2_standalone",
-    ":f32-vrsqrt_sse-no-sse2_standalone",
+    ":f32-vrsqrt_sse2-no-sse3_standalone",
     ":f32-vrsqrt_x64_standalone",
     ":f32-vsigmoid_avx-no-avx2-no-f16c-no-fma_standalone",
     ":f32-vsigmoid_avx512f_standalone",
@@ -782,8 +779,7 @@
     ":f32-vsin_x64_standalone",
     ":f32-vsqrt_avx-no-avx2-no-f16c-no-fma_standalone",
     ":f32-vsqrt_avx512f_standalone",
-    ":f32-vsqrt_f16c-fma-no-avx2_standalone",
-    ":f32-vsqrt_sse-no-sse2_standalone",
+    ":f32-vsqrt_sse2-no-sse3_standalone",
     ":f32-vsqrt_x64_standalone",
     ":f32-vtanh_avx-no-avx2-no-f16c-no-fma_standalone",
     ":f32-vtanh_avx512f_standalone",
@@ -5910,9 +5906,6 @@
       "src/src/f32-gemm/gen/f32-gemm-1x4-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-relu-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-minmax-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-relu-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x4-minmax-scalar.c",
@@ -5943,9 +5936,6 @@
       "src/src/f32-gemm/gen/f32-gemm-1x4-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-relu-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-minmax-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-relu-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x4-minmax-scalar.c",
@@ -6437,9 +6427,6 @@
       "src/src/f32-igemm/gen/f32-igemm-1x4-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-relu-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-minmax-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-relu-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x4-minmax-scalar.c",
@@ -6470,9 +6457,6 @@
       "src/src/f32-igemm/gen/f32-igemm-1x4-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-relu-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-minmax-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-relu-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x4-minmax-scalar.c",
@@ -7547,7 +7531,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -7572,7 +7555,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -7838,7 +7820,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -7863,7 +7844,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -8931,15 +8911,15 @@
     }
   }
 
-  source_set("f32-rsum_sse-no-sse2") {
+  source_set("f32-rsum_sse2-no-sse3") {
     cflags = [
-      "-mno-sse2",
-      "-msse",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-rsum/gen/f32-rsum-sse-u16-acc4.c",
+      "src/src/f32-rsum/gen/f32-rsum-sse2-u16-acc4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -8957,15 +8937,15 @@
   }
 
   # This is a target that cannot depend on //base.
-  source_set("f32-rsum_sse-no-sse2_standalone") {
+  source_set("f32-rsum_sse2-no-sse3_standalone") {
     cflags = [
-      "-mno-sse2",
-      "-msse",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-rsum/gen/f32-rsum-sse-u16-acc4.c",
+      "src/src/f32-rsum/gen/f32-rsum-sse2-u16-acc4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -10965,7 +10945,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u2.c",
       "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u4.c",
     ]
 
@@ -10989,7 +10968,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u2.c",
       "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u4.c",
     ]
 
@@ -12916,13 +12894,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12946,13 +12920,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12983,7 +12953,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt-u16.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13011,7 +12982,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt-u16.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13037,7 +13009,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt-u32.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13060,7 +13033,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt-u32.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13081,16 +13055,15 @@
     }
   }
 
-  source_set("f32-vrsqrt_f16c-fma-no-avx2") {
+  source_set("f32-vrsqrt_sse2-no-sse3") {
     cflags = [
-      "-mf16c",
-      "-mfma",
-      "-mno-avx2",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-fma3-rsqrt-u16.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13108,71 +13081,15 @@
   }
 
   # This is a target that cannot depend on //base.
-  source_set("f32-vrsqrt_f16c-fma-no-avx2_standalone") {
+  source_set("f32-vrsqrt_sse2-no-sse3_standalone") {
     cflags = [
-      "-mf16c",
-      "-mfma",
-      "-mno-avx2",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-fma3-rsqrt-u16.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("f32-vrsqrt_sse-no-sse2") {
-    cflags = [
-      "-mno-sse2",
-      "-msse",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse-rsqrt-u8.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("f32-vrsqrt_sse-no-sse2_standalone") {
-    cflags = [
-      "-mno-sse2",
-      "-msse",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse-rsqrt-u8.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13199,7 +13116,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u4.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13223,7 +13140,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u4.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13847,7 +13764,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt-u16.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13875,7 +13793,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt-u16.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13901,7 +13820,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt-u16.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13924,7 +13843,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt-u16.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13945,16 +13864,15 @@
     }
   }
 
-  source_set("f32-vsqrt_f16c-fma-no-avx2") {
+  source_set("f32-vsqrt_sse2-no-sse3") {
     cflags = [
-      "-mf16c",
-      "-mfma",
-      "-mno-avx2",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-fma3-rsqrt-u16.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13972,71 +13890,15 @@
   }
 
   # This is a target that cannot depend on //base.
-  source_set("f32-vsqrt_f16c-fma-no-avx2_standalone") {
+  source_set("f32-vsqrt_sse2-no-sse3_standalone") {
     cflags = [
-      "-mf16c",
-      "-mfma",
-      "-mno-avx2",
+      "-mno-sse3",
+      "-msse2",
     ]
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-fma3-rsqrt-u16.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("f32-vsqrt_sse-no-sse2") {
-    cflags = [
-      "-mno-sse2",
-      "-msse",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-sse-rsqrt-u12.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("f32-vsqrt_sse-no-sse2_standalone") {
-    cflags = [
-      "-mno-sse2",
-      "-msse",
-    ]
-
-    sources = [
-      "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-sse-rsqrt-u12.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -14062,7 +13924,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -14085,7 +13947,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -17155,7 +17017,6 @@
       "src/include/xnnpack.h",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x4-minmax-scalar.c",
-      "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4-minmax-scalar.c",
     ]
 
@@ -17181,7 +17042,6 @@
       "src/include/xnnpack.h",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x4-minmax-scalar.c",
-      "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4-minmax-scalar.c",
     ]
 
@@ -17665,7 +17525,6 @@
       "src/include/xnnpack.h",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x4-minmax-scalar.c",
-      "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4-minmax-scalar.c",
     ]
 
@@ -17691,7 +17550,6 @@
       "src/include/xnnpack.h",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x4-minmax-scalar.c",
-      "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4-minmax-scalar.c",
     ]
 
@@ -18022,10 +17880,8 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -18050,10 +17906,8 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -18430,7 +18284,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u1.c",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -18454,7 +18307,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u1.c",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -19027,13 +18879,10 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -19058,13 +18907,10 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -19668,9 +19514,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -19694,9 +19538,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -20300,9 +20142,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -20326,9 +20166,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -22083,7 +21921,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u1.c",
       "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u4.c",
     ]
 
@@ -22107,7 +21944,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u1.c",
       "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u4.c",
     ]
 
@@ -22416,7 +22252,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -22440,7 +22275,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -23524,10 +23358,8 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -23552,10 +23384,8 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -23875,7 +23705,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u1.c",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -23899,7 +23728,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u1.c",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -24228,9 +24056,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-gemm/gen/qu8-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -24254,9 +24080,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-gemm/gen/qu8-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -24585,9 +24409,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-igemm/gen/qu8-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -24611,9 +24433,7 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-igemm/gen/qu8-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x4-minmax-fp32-scalar-lrintf.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x4-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -25872,7 +25692,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u1.c",
       "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u4.c",
     ]
 
@@ -25896,7 +25715,6 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u1.c",
       "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u4.c",
     ]
 
@@ -26205,7 +26023,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -26229,7 +26046,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -27852,6 +27668,7 @@
       "src/src/subgraph/static-resize-bilinear-2d.c",
       "src/src/subgraph/static-slice.c",
       "src/src/subgraph/static-transpose.c",
+      "src/src/subgraph/subgraph-utils.c",
       "src/src/subgraph/unary.c",
       "src/src/subgraph/unpooling-2d.c",
       "src/src/subgraph/validation.c",
@@ -27902,6 +27719,7 @@
       "src/src/subgraph/static-resize-bilinear-2d.c",
       "src/src/subgraph/static-slice.c",
       "src/src/subgraph/static-transpose.c",
+      "src/src/subgraph/subgraph-utils.c",
       "src/src/subgraph/unary.c",
       "src/src/subgraph/unpooling-2d.c",
       "src/src/subgraph/validation.c",
@@ -33720,9 +33538,6 @@
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8s4-minmax-neonfma.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-minmax-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-relu-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
@@ -33762,9 +33577,6 @@
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8s4-minmax-neonfma.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-minmax-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-relu-scalar.c",
-      "src/src/f32-gemm/gen/f32-gemm-2x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
@@ -34000,9 +33812,6 @@
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8s4-minmax-neonfma.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-minmax-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-relu-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
@@ -34042,9 +33851,6 @@
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8s4-minmax-neonfma.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-minmax-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-relu-scalar.c",
-      "src/src/f32-igemm/gen/f32-igemm-2x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
@@ -34311,7 +34117,6 @@
       "src/include/xnnpack.h",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-neon-u32.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-neonv8-u32.c",
-      "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -34338,7 +34143,6 @@
       "src/include/xnnpack.h",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-neon-u32.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-neonv8-u32.c",
-      "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -34368,7 +34172,6 @@
       "src/include/xnnpack.h",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-neon-u32.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-neonv8-u32.c",
-      "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -34395,7 +34198,6 @@
       "src/include/xnnpack.h",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-neon-u32.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-neonv8-u32.c",
-      "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u1.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u4.c",
       "src/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-lrintf-u4.c",
     ]
@@ -35140,7 +34942,6 @@
       "src/src/f32-velu/gen/f32-velu-neon-rr2-lut16-p3-u8.c",
       "src/src/f32-velu/gen/f32-velu-neonfma-rr1-lut16-p3-u16.c",
       "src/src/f32-velu/gen/f32-velu-neonfma-rr1-p6-u8.c",
-      "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u2.c",
       "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u4.c",
     ]
 
@@ -35167,7 +34968,6 @@
       "src/src/f32-velu/gen/f32-velu-neon-rr2-lut16-p3-u8.c",
       "src/src/f32-velu/gen/f32-velu-neonfma-rr1-lut16-p3-u16.c",
       "src/src/f32-velu/gen/f32-velu-neonfma-rr1-p6-u8.c",
-      "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u2.c",
       "src/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u4.c",
     ]
 
@@ -35556,19 +35356,15 @@
       "src/src/f32-vrnd/gen/f32-vrndd-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndd-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndne-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndne-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndu-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndu-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndz-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndz-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35594,19 +35390,15 @@
       "src/src/f32-vrnd/gen/f32-vrndd-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndd-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndne-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndne-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndu-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndu-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u4.c",
       "src/src/f32-vrnd/gen/f32-vrndz-neon-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndz-neonv8-u8.c",
       "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u1.c",
-      "src/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35632,9 +35424,9 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-neon-rsqrt-u16.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-neon-rsqrt.c",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u4.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35657,9 +35449,9 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-neon-rsqrt-u16.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-neon-rsqrt.c",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c",
-      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u4.c",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35789,8 +35581,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-aarch64-neon-sqrt-u4.c",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-aarch64-neon-sqrt.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -35813,8 +35605,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-aarch64-neon-sqrt-u4.c",
-      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-aarch64-neon-sqrt.c",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -36039,7 +35831,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/pf16-gemm/pf16-gemm-32x32-minmax-neonsme2.c",
+      "src/src/pf16-gemm/pf16-gemm-1x32c2-minmax-neonsme2.c",
+      "src/src/pf16-gemm/pf16-gemm-32x32c2-minmax-neonsme2.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -36062,7 +35855,8 @@
 
     sources = [
       "src/include/xnnpack.h",
-      "src/src/pf16-gemm/pf16-gemm-32x32-minmax-neonsme2.c",
+      "src/src/pf16-gemm/pf16-gemm-1x32c2-minmax-neonsme2.c",
+      "src/src/pf16-gemm/pf16-gemm-32x32c2-minmax-neonsme2.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -37398,7 +37192,6 @@
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x8c2s4-minmax-neon-mlal.c",
-      "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x8c2s4-minmax-neon-mlal.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4-minmax-scalar.c",
     ]
@@ -37426,7 +37219,6 @@
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x8c2s4-minmax-neon-mlal.c",
-      "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x8c2s4-minmax-neon-mlal.c",
       "src/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4-minmax-scalar.c",
     ]
@@ -37619,7 +37411,6 @@
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8-minmax-neon-mlal-lane.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8c2s4-minmax-neon-mlal.c",
-      "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x8c2s4-minmax-neon-mlal.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x8-minmax-neon-mlal-lane.c",
@@ -37649,7 +37440,6 @@
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8-minmax-neon-mlal-lane.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8c2s4-minmax-neon-mlal.c",
-      "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x2-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x8c2s4-minmax-neon-mlal.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4-minmax-scalar.c",
       "src/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x8-minmax-neon-mlal-lane.c",
@@ -38035,12 +37825,10 @@
       "src/include/xnnpack.h",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p16c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p8c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p16c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -38066,12 +37854,10 @@
       "src/include/xnnpack.h",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p16c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-25p8c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p16c-minmax-rndnu-neon-mla8-ld64.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -38148,7 +37934,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-neon-u32.c",
-      "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u1.c",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -38173,7 +37958,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-neon-u32.c",
-      "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u1.c",
       "src/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -38355,7 +38139,6 @@
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p8c-minmax-fp32-neon-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p8c-minmax-fp32-neonv8-mla8-ld64.c",
@@ -38363,12 +38146,10 @@
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-neonv8-mla8-ld128.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-neon-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -38394,7 +38175,6 @@
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p8c-minmax-fp32-neon-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p8c-minmax-fp32-neonv8-mla8-ld64.c",
@@ -38402,12 +38182,10 @@
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-neonv8-mla8-ld128.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-neon-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-neonv8-mla8-ld64.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -38612,11 +38390,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x16-minmax-fp32-neonv8-mlal-lane.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c2s4-minmax-fp32-neonv8-mlal.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x8c2s4-minmax-fp32-neonv8-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4-minmax-fp32-scalar-lrintf.c",
@@ -38643,11 +38419,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x16-minmax-fp32-neonv8-mlal-lane.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c2s4-minmax-fp32-neonv8-mlal.c",
-      "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x8c2s4-minmax-fp32-neonv8-mlal.c",
       "src/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4-minmax-fp32-scalar-lrintf.c",
@@ -38854,11 +38628,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x16-minmax-fp32-neonv8-mlal-lane.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c2s4-minmax-fp32-neonv8-mlal.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x8c2s4-minmax-fp32-neonv8-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4-minmax-fp32-scalar-lrintf.c",
@@ -38885,11 +38657,9 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x16-minmax-fp32-neonv8-mlal-lane.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c2s4-minmax-fp32-neonv8-mlal.c",
-      "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x8c2s4-minmax-fp32-neon-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x8c2s4-minmax-fp32-neonv8-mlal.c",
       "src/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4-minmax-fp32-scalar-lrintf.c",
@@ -39229,7 +38999,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-vcvt/gen/qs8-vcvt-neon-u32.c",
-      "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u1.c",
       "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u4.c",
     ]
 
@@ -39254,7 +39023,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qs8-vcvt/gen/qs8-vcvt-neon-u32.c",
-      "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u1.c",
       "src/src/qs8-vcvt/gen/qs8-vcvt-scalar-u4.c",
     ]
 
@@ -39283,7 +39051,6 @@
       "src/include/xnnpack.h",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-neon-u32.c",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -39308,7 +39075,6 @@
       "src/include/xnnpack.h",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-neon-u32.c",
       "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -39584,12 +39350,10 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p8c-minmax-rndnu-neon-mul8.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p16c-minmax-rndnu-neon-mul8.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -39614,12 +39378,10 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-25p8c-minmax-rndnu-neon-mul8.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p16c-minmax-rndnu-neon-mul8.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c",
-      "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c",
     ]
 
@@ -39647,7 +39409,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-neon-u32.c",
-      "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u1.c",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -39672,7 +39433,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-neon-u32.c",
-      "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u1.c",
       "src/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u4.c",
     ]
 
@@ -39760,10 +39520,8 @@
       "src/include/xnnpack.h",
       "src/src/qu8-gemm/gen/qu8-gemm-1x16-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x16-minmax-rndnu16-neon-mlal-lane.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x8-minmax-rndnu-neon-mlal-lane.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x8-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-neon-mlal-lane.c",
@@ -39791,10 +39549,8 @@
       "src/include/xnnpack.h",
       "src/src/qu8-gemm/gen/qu8-gemm-1x16-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x16-minmax-rndnu16-neon-mlal-lane.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-gemm/gen/qu8-gemm-1x8-minmax-rndnu-neon-mlal-lane.c",
-      "src/src/qu8-gemm/gen/qu8-gemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-gemm/gen/qu8-gemm-3x8-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-gemm/gen/qu8-gemm-4x16-minmax-rndnu-neon-mlal-lane.c",
@@ -39884,10 +39640,8 @@
       "src/include/xnnpack.h",
       "src/src/qu8-igemm/gen/qu8-igemm-1x16-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x16-minmax-rndnu16-neon-mlal-lane.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x8-minmax-rndnu-neon-mlal-lane.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x8-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-neon-mlal-lane.c",
@@ -39915,10 +39669,8 @@
       "src/include/xnnpack.h",
       "src/src/qu8-igemm/gen/qu8-igemm-1x16-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x16-minmax-rndnu16-neon-mlal-lane.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-1x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-igemm/gen/qu8-igemm-1x8-minmax-rndnu-neon-mlal-lane.c",
-      "src/src/qu8-igemm/gen/qu8-igemm-2x2-minmax-fp32-scalar-imagic.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x4-minmax-fp32-scalar-lrintf.c",
       "src/src/qu8-igemm/gen/qu8-igemm-3x8-minmax-rndnu-neon-mlal-lane.c",
       "src/src/qu8-igemm/gen/qu8-igemm-4x16-minmax-rndnu-neon-mlal-lane.c",
@@ -40162,7 +39914,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-vcvt/gen/qu8-vcvt-neon-u32.c",
-      "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u1.c",
       "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u4.c",
     ]
 
@@ -40187,7 +39938,6 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/qu8-vcvt/gen/qu8-vcvt-neon-u32.c",
-      "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u1.c",
       "src/src/qu8-vcvt/gen/qu8-vcvt-scalar-u4.c",
     ]
 
@@ -40216,7 +39966,6 @@
       "src/include/xnnpack.h",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-neon-u32.c",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -40241,7 +39990,6 @@
       "src/include/xnnpack.h",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-neon-u32.c",
       "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-andxor-u4.c",
-      "src/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-select-u4.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -40863,6 +40611,7 @@
       "src/src/subgraph/static-resize-bilinear-2d.c",
       "src/src/subgraph/static-slice.c",
       "src/src/subgraph/static-transpose.c",
+      "src/src/subgraph/subgraph-utils.c",
       "src/src/subgraph/unary.c",
       "src/src/subgraph/unpooling-2d.c",
       "src/src/subgraph/validation.c",
@@ -40913,6 +40662,7 @@
       "src/src/subgraph/static-resize-bilinear-2d.c",
       "src/src/subgraph/static-slice.c",
       "src/src/subgraph/static-transpose.c",
+      "src/src/subgraph/subgraph-utils.c",
       "src/src/subgraph/unary.c",
       "src/src/subgraph/unpooling-2d.c",
       "src/src/subgraph/validation.c",
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium
index daa3c43..2a378dc 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: 1b2beba83092bed68775b6e2433596627988c74b
-Date: 2025-05-07
+Version: f82ad65ca52cb4d39b73088468a5fe00f56fb47c
+Date: 2025-05-15
 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 58a24d3..9e5516a 100644
--- a/third_party/xnnpack/build_identifier.c
+++ b/third_party/xnnpack/build_identifier.c
@@ -182,9 +182,6 @@
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-1x8-minmax-avx-broadcast.c
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-1x8-minmax-fma3-broadcast.c
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-1x8-minmax-sse-load1.c
-// - external/xnnpack+/src/f32-gemm/gen/f32-gemm-2x4-minmax-scalar.c
-// - external/xnnpack+/src/f32-gemm/gen/f32-gemm-2x4-relu-scalar.c
-// - external/xnnpack+/src/f32-gemm/gen/f32-gemm-2x4-scalar.c
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-4x16s4-minmax-fma3-broadcast.c
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c
 // - external/xnnpack+/src/f32-gemm/gen/f32-gemm-4x2-scalar.c
@@ -217,9 +214,6 @@
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-1x8-minmax-avx-broadcast.c
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-1x8-minmax-fma3-broadcast.c
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-1x8-minmax-sse-load1.c
-// - external/xnnpack+/src/f32-igemm/gen/f32-igemm-2x4-minmax-scalar.c
-// - external/xnnpack+/src/f32-igemm/gen/f32-igemm-2x4-relu-scalar.c
-// - external/xnnpack+/src/f32-igemm/gen/f32-igemm-2x4-scalar.c
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-4x16s4-minmax-fma3-broadcast.c
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c
 // - external/xnnpack+/src/f32-igemm/gen/f32-igemm-4x2-scalar.c
@@ -264,7 +258,6 @@
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-avx-u32.c
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-avx2-u64.c
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-avx512skx-u128.c
-// - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u1.c
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-imagic-u4.c
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-scalar-lrintf-u4.c
 // - external/xnnpack+/src/f32-qs8-vcvt/gen/f32-qs8-vcvt-sse2-u32.c
@@ -272,7 +265,6 @@
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-avx-u32.c
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-avx2-u64.c
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-avx512skx-u128.c
-// - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u1.c
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-imagic-u4.c
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-scalar-lrintf-u4.c
 // - external/xnnpack+/src/f32-qu8-vcvt/gen/f32-qu8-vcvt-sse2-u32.c
@@ -308,7 +300,7 @@
 // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-avx-u32-acc4.c
 // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-avx512f-u32-acc2.c
 // - external/xnnpack+/src/f32-rsum/gen/f32-rsum-scalar-u4-acc4.c
-// - external/xnnpack+/src/f32-rsum/gen/f32-rsum-sse-u16-acc4.c
+// - external/xnnpack+/src/f32-rsum/gen/f32-rsum-sse2-u16-acc4.c
 // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-32x1-minmax-sse.c
 // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-8x1-minmax-scalar.c
 // - external/xnnpack+/src/f32-spmm/gen/f32-spmm-8x2-minmax-scalar.c
@@ -422,7 +414,6 @@
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx-rr2-lut4-p4-perm-u32.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx2-rr1-lut4-p4-perm-u32.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx512f-rr1-p6-u64.c
-// - external/xnnpack+/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u2.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-scalar-rr2-lut16-p3-u4.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-sse2-rr2-lut16-p3-u12.c
 // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-avx-rational-3-2-div.c
@@ -459,33 +450,30 @@
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-avx-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-avx512f-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u1.c
-// - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-scalar-libm-u4.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-sse2-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndd-sse41-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-avx-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-avx512f-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u1.c
-// - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-scalar-libm-u4.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-sse2-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndne-sse41-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-avx-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-avx512f-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u1.c
-// - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-scalar-libm-u4.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-sse2-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndu-sse41-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-avx-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-avx512f-u16.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u1.c
-// - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-scalar-libm-u4.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-sse2-u8.c
 // - external/xnnpack+/src/f32-vrnd/gen/f32-vrndz-sse41-u8.c
-// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt-u16.c
-// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt-u32.c
-// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-fma3-rsqrt-u16.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx-rsqrt.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx-sqrt.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-rsqrt.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-sqrt.c
 // - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c
-// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u4.c
-// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-sse-rsqrt-u8.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c
 // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-avx-rr2-p5-nr2-u16.c
 // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-avx2-rr1-p5-div-u16.c
 // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-avx512f-rr2-lut32-p2-perm2-scalef-div-u64.c
@@ -497,11 +485,11 @@
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-fma3-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-scalar-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-sse2-rational-5-4-div.c
-// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt-u16.c
-// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt-u16.c
-// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-fma3-rsqrt-u16.c
-// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt-u1.c
-// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-sse-rsqrt-u12.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx-sqrt.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-fma3-rational-9-8-div.c
@@ -601,7 +589,6 @@
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x8c8-minmax-avx2.c
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x8c8-minmax-avx256skx.c
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-1x8c8-minmax-avxvnni-prfm.c
-// - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-2x2-minmax-scalar.c
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4-minmax-scalar.c
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4c8-minmax-sse2-ld64.c
 // - external/xnnpack+/src/qd8-f32-qc8w-gemm/gen/qd8-f32-qc8w-gemm-4x4c8-minmax-sse41-ld64.c
@@ -622,7 +609,6 @@
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8c8-minmax-avx2.c
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8c8-minmax-avx256skx.c
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-1x8c8-minmax-avxvnni-prfm.c
-// - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-2x2-minmax-scalar.c
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4-minmax-scalar.c
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4c8-minmax-sse2-ld64.c
 // - external/xnnpack+/src/qd8-f32-qc8w-igemm/gen/qd8-f32-qc8w-igemm-4x4c8-minmax-sse41-ld64.c
@@ -633,7 +619,6 @@
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p16c-minmax-fp32-avx-mul16-add16.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p1c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-25p8c-minmax-fp32-sse2-mul16-add16.c
@@ -641,7 +626,6 @@
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p16c-minmax-fp32-avx-mul16-add16.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qs8-dwconv/gen/qs8-dwconv-9p8c-minmax-fp32-sse2-mul16-add16.c
@@ -650,7 +634,6 @@
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-avx-u32.c
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-avx2-u16.c
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-avx512skx-u32.c
-// - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u1.c
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-scalar-u4.c
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-sse2-u32.c
 // - external/xnnpack+/src/qs8-f32-vcvt/gen/qs8-f32-vcvt-sse41-u16.c
@@ -664,7 +647,6 @@
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-avx-mul16-add16.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p1c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-25p8c-minmax-fp32-sse2-mul16.c
@@ -672,7 +654,6 @@
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-avx-mul16-add16.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-3p8c-minmax-fp32-sse2-mul16.c
@@ -680,7 +661,6 @@
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-avx-mul16-add16.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qs8-qc8w-dwconv/gen/qs8-qc8w-dwconv-9p8c-minmax-fp32-sse2-mul16.c
@@ -688,7 +668,6 @@
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-16x64c4-minmax-fp32-avx512amx.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x16c8-minmax-fp32-avx512skx-prfm.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x16c8-minmax-fp32-avx512vnni-prfm.c
-// - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x4c8-minmax-fp32-sse2-ld64.c
@@ -698,7 +677,6 @@
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c8-minmax-fp32-avx256skx.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c8-minmax-fp32-avxvnni-prfm.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-1x8c8-minmax-fp32-avxvnniint8-prfm.c
-// - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-2x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-gemm/gen/qs8-qc8w-gemm-3x4c8-minmax-fp32-sse2-ld64.c
@@ -712,7 +690,6 @@
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-16x64c4-minmax-fp32-avx512amx.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x16c8-minmax-avx512vnni-prfm.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x16c8-minmax-fp32-avx512skx-prfm.c
-// - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x4c8-minmax-fp32-sse2-ld64.c
@@ -722,7 +699,6 @@
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c8-minmax-fp32-avx256skx.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c8-minmax-fp32-avxvnni-prfm.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-1x8c8-minmax-fp32-avxvnniint8-prfm.c
-// - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-2x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qs8-qc8w-igemm/gen/qs8-qc8w-igemm-3x4c8-minmax-fp32-sse2-ld64.c
@@ -763,7 +739,6 @@
 // - external/xnnpack+/src/qs8-vaddc/gen/qs8-vaddc-minmax-sse41-mul16-ld64-u8.c
 // - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-avx-u32.c
 // - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-avx2-u32.c
-// - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-scalar-u1.c
 // - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-scalar-u4.c
 // - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-sse2-u32.c
 // - external/xnnpack+/src/qs8-vcvt/gen/qs8-vcvt-sse41-u32.c
@@ -771,7 +746,6 @@
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-avx-u32.c
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-avx2-u32.c
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-andxor-u4.c
-// - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-scalar-select-u4.c
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-sse2-u32.c
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-sse41-u32.c
 // - external/xnnpack+/src/qs8-vlrelu/gen/qs8-vlrelu-ssse3-u32.c
@@ -792,7 +766,6 @@
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p16c-minmax-fp32-avx-mul16.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p1c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-25p8c-minmax-fp32-sse2-mul16.c
@@ -800,7 +773,6 @@
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p16c-minmax-fp32-avx-mul16.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p16c-minmax-fp32-avx2-mul32.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p1c-minmax-fp32-scalar-fmagic.c
-// - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p2c-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p32c-minmax-fp32-avx512skx-mul32.c
 // - external/xnnpack+/src/qu8-dwconv/gen/qu8-dwconv-9p8c-minmax-fp32-sse2-mul16.c
@@ -808,18 +780,15 @@
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-avx-u32.c
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-avx2-u16.c
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-avx512skx-u32.c
-// - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u1.c
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-scalar-u4.c
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-sse2-u32.c
 // - external/xnnpack+/src/qu8-f32-vcvt/gen/qu8-f32-vcvt-sse41-u16.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x16c8-minmax-fp32-avx512skx-prfm.c
-// - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x4c8-minmax-fp32-sse2-ld64.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x4c8-minmax-fp32-sse41-ld64.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-1x8c8-minmax-fp32-avx2.c
-// - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-2x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-2x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-3x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-3x4c8-minmax-fp32-sse2-ld64.c
@@ -827,13 +796,11 @@
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-3x8c8-minmax-fp32-avx2.c
 // - external/xnnpack+/src/qu8-gemm/gen/qu8-gemm-7x16c8-minmax-fp32-avx512skx-prfm.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x16c8-minmax-fp32-avx512skx-prfm.c
-// - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x4c8-minmax-fp32-sse2-ld64.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x4c8-minmax-fp32-sse41-ld64.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-1x8c8-minmax-fp32-avx2.c
-// - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-2x2-minmax-fp32-scalar-imagic.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-2x4c8-minmax-fp32-avx-ld128.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-3x4-minmax-fp32-scalar-lrintf.c
 // - external/xnnpack+/src/qu8-igemm/gen/qu8-igemm-3x4c8-minmax-fp32-sse2-ld64.c
@@ -861,7 +828,6 @@
 // - external/xnnpack+/src/qu8-vaddc/gen/qu8-vaddc-minmax-sse41-mul16-ld64-u8.c
 // - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-avx-u32.c
 // - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-avx2-u32.c
-// - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-scalar-u1.c
 // - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-scalar-u4.c
 // - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-sse2-u32.c
 // - external/xnnpack+/src/qu8-vcvt/gen/qu8-vcvt-sse41-u32.c
@@ -869,7 +835,6 @@
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-avx-u32.c
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-avx2-u32.c
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-andxor-u4.c
-// - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-scalar-select-u4.c
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-sse2-u32.c
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-sse41-u32.c
 // - external/xnnpack+/src/qu8-vlrelu/gen/qu8-vlrelu-ssse3-u32.c
@@ -997,10 +962,10 @@
 #include <string.h>
 
 static const uint8_t xnn_build_identifier[] = {
-  111, 182, 175,  28,  10,  59, 117, 199,
-  161,   4,  44,  68,  47, 182,   3, 207,
-  101, 198,  29, 180, 128, 137, 252,  57,
-   60,  17,  99, 112, 242, 192, 175, 208
+  149, 211,  46,  48, 250, 232, 248, 229,
+   62, 155, 121, 247,   2, 205,  53, 241,
+   41,   3, 110, 143, 132,  15, 198, 224,
+   93,  92, 171, 189, 231,  92, 246,  74
 };
 
 size_t xnn_experimental_get_build_identifier_size() {
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src
index 1b2beba..f82ad65 160000
--- a/third_party/xnnpack/src
+++ b/third_party/xnnpack/src
@@ -1 +1 @@
-Subproject commit 1b2beba83092bed68775b6e2433596627988c74b
+Subproject commit f82ad65ca52cb4d39b73088468a5fe00f56fb47c
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml
index 9800ba1..a2dd51a 100644
--- a/tools/metrics/histograms/metadata/blink/enums.xml
+++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -7796,6 +7796,7 @@
   <int value="852" label="rule-width"/>
   <int value="853" label="rule-style"/>
   <int value="854" label="caret-shape"/>
+  <int value="855" label="row-rule"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom:CSSSampleId) -->
diff --git a/tools/metrics/histograms/metadata/browser/enums.xml b/tools/metrics/histograms/metadata/browser/enums.xml
index ad6028a..c2d90438 100644
--- a/tools/metrics/histograms/metadata/browser/enums.xml
+++ b/tools/metrics/histograms/metadata/browser/enums.xml
@@ -257,7 +257,8 @@
   <int value="58" label="SYNC_ERROR_INFOBAR_DELEGATE_IOS"/>
   <int value="59" label="UPGRADE_INFOBAR_DELEGATE"/>
   <int value="60" label="WINDOW_ERROR_INFOBAR_DELEGATE_ANDROID"/>
-  <int value="61" label="DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID"/>
+  <int value="61"
+      label="DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID (Obsolete)"/>
   <int value="62" label="WINDOWS_DESKTOP_SEARCH_INFOBAR_DELEGATE (Obsolete)"/>
   <int value="63" label="UPDATE_PASSWORD_INFOBAR_DELEGATE_MOBILE"/>
   <int value="64" label="DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID"/>
diff --git a/tools/metrics/histograms/metadata/collaboration_service/enums.xml b/tools/metrics/histograms/metadata/collaboration_service/enums.xml
index d015402..cf8db7d 100644
--- a/tools/metrics/histograms/metadata/collaboration_service/enums.xml
+++ b/tools/metrics/histograms/metadata/collaboration_service/enums.xml
@@ -76,6 +76,7 @@
   <int value="31" label="Managed account signed in"/>
   <int value="32" label="Account info is not ready upon signin"/>
   <int value="33" label="Read new group result: user is already member"/>
+  <int value="34" label="Failed adding the user to a group"/>
 </enum>
 
 <!-- LINT.ThenChange(//components/collaboration/internal/metrics.h:CollaborationServiceJoinEvent) -->
diff --git a/tools/metrics/histograms/metadata/geolocation/histograms.xml b/tools/metrics/histograms/metadata/geolocation/histograms.xml
index 12e14e5a..2a14c767 100644
--- a/tools/metrics/histograms/metadata/geolocation/histograms.xml
+++ b/tools/metrics/histograms/metadata/geolocation/histograms.xml
@@ -45,7 +45,7 @@
 </histogram>
 
 <histogram name="Geolocation.CoreLocationProvider.ErrorCode"
-    enum="CoreLocationErrorCode" expires_after="2025-07-01">
+    enum="CoreLocationErrorCode" expires_after="2025-12-31">
   <owner>alvinji@chromium.org</owner>
   <owner>device-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index f809d38..ccd2a62 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1331,23 +1331,6 @@
   </summary>
 </histogram>
 
-<histogram name="Navigation.LatencyAblation.ExcessWaitTime" units="ms"
-    expires_after="2023-08-08">
-  <owner>ryansturm@chromium.org</owner>
-  <owner>spelchat@chromium.org</owner>
-  <summary>
-    The time the user waits beyond what is configured for the latency ablation
-    study. The enabled arms of the latency ablation study prescribe an amount of
-    time to delay the navigation, and this histogram records the amount of time
-    that was waited beyond that prescription. Recorded upon resuming the
-    navigation after the ablation occurs. This ablation occurs for most
-    navigations, but does not occur for subframes, prerenders, fenced frames,
-    bf/restore style navigations, and client redirects. The experiment can be
-    configured to only affect default search (or only affect non default
-    search).
-  </summary>
-</histogram>
-
 <histogram name="Navigation.LoadIfNecessaryType"
     enum="NavigationNeedsReloadType" expires_after="never">
 <!-- expires-never: Generally useful metric on Android that tracks number of automatic tab reloads and their cause.  -->
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index a4f38c4f..b8a81ea 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -1019,6 +1019,17 @@
   <token key="ModelExecutionFeature" variants="ModelExecutionFeature"/>
 </histogram>
 
+<histogram name="OptimizationGuide.ModelExecution.OnDeviceModelCrashCount"
+    enum="OnDeviceModelValidationResult" expires_after="2026-05-19">
+  <owner>cduvall@chromium.org</owner>
+  <owner>sophiechang@chromium.org</owner>
+  <summary>
+    Records the number of consecutive crashes of the on-device model service
+    without a successful response. Recorded each time the on-device model
+    service crashes.
+  </summary>
+</histogram>
+
 <histogram
     name="OptimizationGuide.ModelExecution.OnDeviceModelEligibilityReason.{ModelExecutionFeature}"
     enum="OptimizationGuideOnDeviceModelEligibilityReason"
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml
index 8555d56..084631ee 100644
--- a/tools/metrics/histograms/metadata/permissions/histograms.xml
+++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -1418,6 +1418,7 @@
     <variant name="IdleDetection"/>
     <variant name="MidiSysEx"/>
     <variant name="Notifications"/>
+    <variant name="RegisterProtocolHandler"/>
     <variant name="VideoCapture"/>
     <variant name="VR"/>
   </token>
@@ -1527,6 +1528,7 @@
     <variant name="IdleDetection"/>
     <variant name="MidiSysEx"/>
     <variant name="Notifications"/>
+    <variant name="RegisterProtocolHandler"/>
     <variant name="VideoCapture"/>
     <variant name="VR"/>
   </token>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 23298ff..a9a9bbe 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "87550f9256f793288f52f37f7902476e21ebb651",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/fbb70355b61977525cc0919d0f28bc53a537caa3/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5a66f76326a04bf33f05433665cd77b7eb288fcc/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "da0c3e780366c0dde3891e30805d94d037011cf6",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fbb70355b61977525cc0919d0f28bc53a537caa3/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/5a66f76326a04bf33f05433665cd77b7eb288fcc/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index f2409000..4c2e4f0 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -512,4 +512,5 @@
  <item id="forms_classifications_model_execution" added_in_milestone="137" content_hash_code="051d9c71" os_list="linux,windows,chromeos,android" file_path="components/optimization_guide/core/model_execution/model_execution_fetcher.cc" />
  <item id="gemini_user_status" added_in_milestone="137" content_hash_code="03062011" os_list="linux,windows" file_path="chrome/browser/glic/glic_user_status_fetcher.cc" />
  <item id="notification_telemetry" added_in_milestone="137" content_hash_code="07930dca" os_list="linux,windows,android,chromeos" file_path="chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.cc" />
+ <item id="corp_register_support_host_request" added_in_milestone="138" content_hash_code="03509e36" os_list="linux,windows,chromeos" file_path="remoting/host/corp_register_support_host_request.cc" />
 </annotations>
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index 2a1ea11..739ac838 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -377,6 +377,7 @@
       <annotation id="forms_classifications_model_execution"/>
       <annotation id="gemini_user_status"/>
       <annotation id="notification_telemetry"/>
+      <annotation id="corp_register_support_host_request"/>
     </sender>
   </group>
   <group name="Admin Features" hidden="true">
diff --git a/tools/utr/run.py b/tools/utr/run.py
index eb3b0117..9d1c56b 100755
--- a/tools/utr/run.py
+++ b/tools/utr/run.py
@@ -36,8 +36,8 @@
 
 
 def maybe_print_survey_link():
-  # Only print the link every 100 runs
-  if random.random() < 0.01:
+  # Only print the link every 5% of runs
+  if random.random() < 0.05:
     logging.info('Help us improve by sharing your feedback in this short '
                  'survey: %s' % _SURVEY_LINK)
 
diff --git a/tools/utr/run_test.py b/tools/utr/run_test.py
index 71b7344..cd2f8ae 100755
--- a/tools/utr/run_test.py
+++ b/tools/utr/run_test.py
@@ -64,7 +64,7 @@
 
     # No logs to the mock result in an exception trying to assert
     # Verify nothing new is logged instead
-    mock_random.return_value = 0.02
+    mock_random.return_value = 0.051
     with self.assertLogs() as info_log:
       logging.info('')
       run.maybe_print_survey_link()
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index c8c1fea..423dfd9 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -1548,12 +1548,6 @@
       const std::wstring& active_composition_text,
       bool is_composition_committed);
 
-  // Notifies observers that basic MSAA usage was detected. Only some of the
-  // APIs were chosen to avoid accessibility being enabled unnecessarily or
-  // unexpectedly in a test environment, while still ensuring that clients that
-  // only use MSAA/IAccessible have a way to turn on accessibility.
-  void NotifyObserverForMSAAUsage() const;
-
   void NotifyAPIObserverForPatternRequest(PATTERNID pattern_id) const;
   void NotifyAPIObserverForPropertyRequest(PROPERTYID property_id) const;
 
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index d088b65a..e0a25922 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -418,6 +418,7 @@
     "java/src/org/chromium/ui/interpolators/AndroidxInterpolators.java",
     "java/src/org/chromium/ui/interpolators/Interpolators.java",
     "java/src/org/chromium/ui/listmenu/BasicListMenu.java",
+    "java/src/org/chromium/ui/listmenu/ContextMenuCheckItemProperties.java",
     "java/src/org/chromium/ui/listmenu/ListMenu.java",
     "java/src/org/chromium/ui/listmenu/ListMenuButton.java",
     "java/src/org/chromium/ui/listmenu/ListMenuDelegate.java",
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index ca4ac5ec..5a04e405 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -94,6 +94,37 @@
   sources = [ "platform_event.h" ]
 
   public_deps = [ "//base" ]
+
+  if (is_android) {
+    public_deps += [ ":platform_event_android" ]
+  }
+}
+
+if (is_android) {
+  source_set("platform_event_android") {
+    sources = [
+      "android/event_flags_android.cc",
+      "android/event_flags_android.h",
+      "android/event_type_android.cc",
+      "android/event_type_android.h",
+      "android/key_event_android.cc",
+      "android/key_event_android.h",
+      "android/platform_event_android.cc",
+      "android/platform_event_android.h",
+
+      # Allow this target to include events_export.h without depending on the
+      # events target (which would be circular).
+      "events_export.h",
+    ]
+
+    deps = [
+      ":event_constants",
+      ":keyevent_jni_headers",
+      ":motionevent_jni_headers",
+      "//base",
+      "//ui/events/types:headers",
+    ]
+  }
 }
 
 component("events_base") {
@@ -123,6 +154,13 @@
     "pointer_details.h",
   ]
 
+  if (is_android) {
+    sources += [
+      "keycodes/keyboard_code_conversion_android.cc",
+      "keycodes/keyboard_code_conversion_android.h",
+    ]
+  }
+
   if (is_win) {
     sources += [
       "keycodes/keyboard_code_conversion_win.cc",
@@ -145,16 +183,6 @@
     "//ui/gfx/geometry",
   ]
 
-  if (is_android) {
-    sources += [
-      "android/event_flags_android.cc",
-      "android/event_flags_android.h",
-      "keycodes/keyboard_code_conversion_android.cc",
-      "keycodes/keyboard_code_conversion_android.h",
-    ]
-    deps += [ ":motionevent_jni_headers" ]
-  }
-
   if (is_mac) {
     sources += [
       "keycodes/keyboard_code_conversion_mac.h",
@@ -360,7 +388,7 @@
     ]
   }
 
-  if (is_win || is_apple || use_ozone) {
+  if (is_win || is_apple || use_ozone || is_android) {
     sources -= [ "events_stub.cc" ]
   }
 
@@ -368,9 +396,9 @@
     public += [
       "android/drag_event_android.h",
       "android/event_handler_android.h",
+      "android/events_android_utils.h",
       "android/gesture_event_android.h",
       "android/gesture_event_type.h",
-      "android/key_event_android.h",
       "android/key_event_utils.h",
       "android/motion_event_android.h",
       "android/motion_event_android_java.h",
@@ -383,8 +411,9 @@
     sources += [
       "android/drag_event_android.cc",
       "android/event_handler_android.cc",
+      "android/events_android.cc",
+      "android/events_android_utils.cc",
       "android/gesture_event_android.cc",
-      "android/key_event_android.cc",
       "android/key_event_utils.cc",
       "android/motion_event_android.cc",
       "android/motion_event_android_java.cc",
@@ -720,7 +749,10 @@
     ]
 
     if (is_android) {
-      sources += [ "android/motion_event_android_unittest.cc" ]
+      sources += [
+        "android/motion_event_android_unittest.cc",
+        "keycodes/keyboard_code_conversion_android_unittest.cc",
+      ]
       deps += [
         ":motionevent_jni_headers",
         "//ui/android:ui_full_java",
diff --git a/ui/events/android/event_flags_android.cc b/ui/events/android/event_flags_android.cc
index 0fbc172..9e6abb417 100644
--- a/ui/events/android/event_flags_android.cc
+++ b/ui/events/android/event_flags_android.cc
@@ -13,7 +13,7 @@
 
 namespace ui {
 
-int EventFlagsFromAndroidMetaState(int meta_state) {
+EventFlags EventFlagsFromAndroidMetaState(int meta_state) {
   int flags = EF_NONE;
 
   if ((meta_state & AMETA_SHIFT_ON) != 0) {
@@ -35,7 +35,29 @@
   return flags;
 }
 
-int EventFlagsFromAndroidButtonState(int button_state) {
+int AndroidMetaStateFromEventFlags(EventFlags event_flags) {
+  int meta_state = AMETA_NONE;
+
+  if (event_flags & EF_SHIFT_DOWN) {
+    meta_state |= AMETA_SHIFT_ON;
+  }
+  if (event_flags & EF_CONTROL_DOWN) {
+    meta_state |= AMETA_CTRL_ON;
+  }
+  if (event_flags & EF_ALT_DOWN) {
+    meta_state |= AMETA_ALT_ON;
+  }
+  if (event_flags & EF_COMMAND_DOWN) {
+    meta_state |= AMETA_META_ON;
+  }
+  if (event_flags & EF_CAPS_LOCK_ON) {
+    meta_state |= AMETA_CAPS_LOCK_ON;
+  }
+
+  return meta_state;
+}
+
+EventFlags EventFlagsFromAndroidButtonState(int button_state) {
   int flags = EF_NONE;
 
   if ((button_state & JNI_MotionEvent::BUTTON_BACK) != 0) {
diff --git a/ui/events/android/event_flags_android.h b/ui/events/android/event_flags_android.h
index f8c54f6..e55b2a1 100644
--- a/ui/events/android/event_flags_android.h
+++ b/ui/events/android/event_flags_android.h
@@ -5,15 +5,19 @@
 #ifndef UI_EVENTS_ANDROID_EVENT_FLAGS_ANDROID_H_
 #define UI_EVENTS_ANDROID_EVENT_FLAGS_ANDROID_H_
 
-#include "ui/events/events_base_export.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/events_export.h"
 
 namespace ui {
 
 // Converts android meta state to event flags.
-EVENTS_BASE_EXPORT int EventFlagsFromAndroidMetaState(int meta_state);
+EVENTS_EXPORT EventFlags EventFlagsFromAndroidMetaState(int meta_state);
+
+// Converts event flags to android meta state.
+EVENTS_EXPORT int AndroidMetaStateFromEventFlags(EventFlags event_flags);
 
 // Converts android button state to event flags.
-EVENTS_BASE_EXPORT int EventFlagsFromAndroidButtonState(int button_state);
+EVENTS_EXPORT EventFlags EventFlagsFromAndroidButtonState(int button_state);
 
 }  // namespace ui
 
diff --git a/ui/events/android/event_type_android.cc b/ui/events/android/event_type_android.cc
new file mode 100644
index 0000000..bb29c6db
--- /dev/null
+++ b/ui/events/android/event_type_android.cc
@@ -0,0 +1,35 @@
+// 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 "ui/events/android/event_type_android.h"
+
+#include <android/input.h>
+
+#include "base/notreached.h"
+
+namespace ui {
+
+EventType EventTypeFromAndroidKeyEventAction(int key_event_action) {
+  switch (key_event_action) {
+    case AKEY_EVENT_ACTION_DOWN:
+      return EventType::kKeyPressed;
+    case AKEY_EVENT_ACTION_UP:
+      return EventType::kKeyReleased;
+    default:
+      return EventType::kUnknown;
+  }
+}
+
+int AndroidKeyEventActionFromEventType(EventType event_type) {
+  switch (event_type) {
+    case EventType::kKeyPressed:
+      return AKEY_EVENT_ACTION_DOWN;
+    case EventType::kKeyReleased:
+      return AKEY_EVENT_ACTION_UP;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace ui
diff --git a/ui/events/android/event_type_android.h b/ui/events/android/event_type_android.h
new file mode 100644
index 0000000..f8e9334
--- /dev/null
+++ b/ui/events/android/event_type_android.h
@@ -0,0 +1,22 @@
+// 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 UI_EVENTS_ANDROID_EVENT_TYPE_ANDROID_H_
+#define UI_EVENTS_ANDROID_EVENT_TYPE_ANDROID_H_
+
+#include "ui/events/events_export.h"
+#include "ui/events/types/event_type.h"
+
+namespace ui {
+
+// Converts android key event action to EventType.
+EVENTS_EXPORT EventType
+EventTypeFromAndroidKeyEventAction(int key_event_action);
+
+// Converts EventType for a key event to android key event action.
+EVENTS_EXPORT int AndroidKeyEventActionFromEventType(EventType event_type);
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_ANDROID_EVENT_TYPE_ANDROID_H_
diff --git a/ui/events/android/events_android.cc b/ui/events/android/events_android.cc
new file mode 100644
index 0000000..8542e20b
--- /dev/null
+++ b/ui/events/android/events_android.cc
@@ -0,0 +1,166 @@
+// 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 <android/input.h>
+
+#include "base/notreached.h"
+#include "base/time/time.h"
+#include "ui/events/android/event_flags_android.h"
+#include "ui/events/android/event_type_android.h"
+#include "ui/events/android/key_event_android.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/events_export.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/keyboard_code_conversion_android.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/platform_event.h"
+#include "ui/events/pointer_details.h"
+#include "ui/events/types/event_type.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace ui {
+
+EventType EventTypeFromNative(const PlatformEvent& native_event) {
+  const KeyEventAndroid* key_event = native_event.AsKeyboardEventAndroid();
+  if (key_event == nullptr) {
+    return EventType::kUnknown;
+  }
+  return EventTypeFromAndroidKeyEventAction(key_event->Action());
+}
+
+int EventFlagsFromNative(const PlatformEvent& native_event) {
+  const KeyEventAndroid* key_event = native_event.AsKeyboardEventAndroid();
+  if (key_event == nullptr) {
+    return 0;
+  }
+  return EventFlagsFromAndroidMetaState(key_event->MetaState());
+}
+
+base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return base::TimeTicks();
+}
+
+base::TimeTicks EventLatencyTimeFromNative(const PlatformEvent& native_event,
+                                           base::TimeTicks current_time) {
+  return EventTimeFromNative(native_event);
+}
+
+gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return gfx::PointF();
+}
+
+gfx::Point EventSystemLocationFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return gfx::Point();
+}
+
+int EventButtonFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+int GetChangedMouseButtonFlagsFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+PointerDetails GetMousePointerDetailsFromNative(
+    const PlatformEvent& native_event) {
+  return PointerDetails(EventPointerType::kMouse);
+}
+
+gfx::Vector2d GetMouseWheelOffset(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return gfx::Vector2d();
+}
+
+gfx::Vector2d GetMouseWheelTick120ths(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return gfx::Vector2d();
+}
+
+bool ShouldCopyPlatformEvents() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+// Exported for tests to use.
+EVENTS_EXPORT PlatformEvent CreateInvalidPlatformEvent() {
+  return PlatformEventAndroid();
+}
+
+bool IsPlatformEventValid(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+PointerDetails GetTouchPointerDetailsFromNative(
+    const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return PointerDetails(EventPointerType::kUnknown,
+                        /* radius_x */ 1.0,
+                        /* radius_y */ 1.0,
+                        /* force */ 0.f,
+                        /* twist */ 0.f,
+                        /* tilt_x */ 0.f,
+                        /* tilt_y */ 0.f);
+}
+
+bool GetScrollOffsets(const PlatformEvent& native_event,
+                      float* x_offset,
+                      float* y_offset,
+                      float* x_offset_ordinal,
+                      float* y_offset_ordinal,
+                      int* finger_count,
+                      EventMomentumPhase* momentum_phase) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool GetFlingData(const PlatformEvent& native_event,
+                  float* vx,
+                  float* vy,
+                  float* vx_ordinal,
+                  float* vy_ordinal,
+                  bool* is_cancel) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+KeyboardCode KeyboardCodeFromNative(const PlatformEvent& native_event) {
+  const KeyEventAndroid* key_event = native_event.AsKeyboardEventAndroid();
+  if (key_event == nullptr) {
+    return static_cast<KeyboardCode>(0);
+  }
+  return KeyboardCodeFromAndroidKeyCode(key_event->key_code());
+}
+
+DomCode CodeFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return DomCode::NONE;
+}
+
+bool IsCharFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+uint32_t WindowsKeycodeFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+uint16_t TextFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+uint16_t UnmodifiedTextFromNative(const PlatformEvent& native_event) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+}  // namespace ui
diff --git a/ui/events/android/events_android_utils.cc b/ui/events/android/events_android_utils.cc
new file mode 100644
index 0000000..0d72867
--- /dev/null
+++ b/ui/events/android/events_android_utils.cc
@@ -0,0 +1,35 @@
+// 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 "ui/events/android/events_android_utils.h"
+
+#include <android/input.h>
+
+#include "base/notreached.h"
+#include "ui/events/android/event_flags_android.h"
+#include "ui/events/android/event_type_android.h"
+#include "ui/events/keycodes/keyboard_code_conversion_android.h"
+
+namespace ui {
+
+PlatformEvent NativeEventFromEvent(Event& event) {
+  if (event.HasNativeEvent()) {
+    return event.native_event();
+  }
+
+  if (event.IsKeyEvent()) {
+    KeyEvent* key_event = event.AsKeyEvent();
+
+    int action = AndroidKeyEventActionFromEventType(key_event->type());
+    int key_code = AndroidKeyCodeFromKeyboardCode(key_event->key_code());
+    int meta_state = AndroidMetaStateFromEventFlags(key_event->flags());
+
+    return PlatformEventAndroid(KeyEventAndroid(action, key_code, meta_state));
+  }
+
+  // Support other event types as needed.
+  NOTREACHED();
+}
+
+}  // namespace ui
diff --git a/ui/events/android/events_android_utils.h b/ui/events/android/events_android_utils.h
new file mode 100644
index 0000000..8db080a
--- /dev/null
+++ b/ui/events/android/events_android_utils.h
@@ -0,0 +1,17 @@
+// 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 UI_EVENTS_ANDROID_EVENTS_ANDROID_UTILS_H_
+#define UI_EVENTS_ANDROID_EVENTS_ANDROID_UTILS_H_
+
+#include "ui/events/event.h"
+
+namespace ui {
+
+// Creates a PlatformEvent from the given event.
+EVENTS_EXPORT PlatformEvent NativeEventFromEvent(Event& event);
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_ANDROID_EVENTS_ANDROID_UTILS_H_
diff --git a/ui/events/android/key_event_android.cc b/ui/events/android/key_event_android.cc
index e00505a9..9c39243 100644
--- a/ui/events/android/key_event_android.cc
+++ b/ui/events/android/key_event_android.cc
@@ -6,9 +6,7 @@
 
 #include "base/android/jni_android.h"
 #include "ui/events/android/event_flags_android.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/keyboard_code_conversion_android.h"
-#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/android/event_type_android.h"
 
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "ui/events/keyevent_jni_headers/KeyEvent_jni.h"
@@ -28,21 +26,39 @@
   event_.Reset(env, event);
 }
 
-KeyEventAndroid::~KeyEventAndroid() {}
+KeyEventAndroid::KeyEventAndroid(int action, int key_code, int meta_state)
+    : key_code_(key_code) {
+  JNIEnv* env = AttachCurrentThread();
+
+  int down_time = 0;
+  int event_time = 0;
+  int repeat = 0;
+
+  jni_zero::ScopedJavaLocalRef<jobject> event =
+      JNI_KeyEvent::Java_KeyEvent_Constructor(
+          env, down_time, event_time, action, key_code, repeat, meta_state);
+
+  event_.Reset(env, event.obj());
+}
+
+KeyEventAndroid::KeyEventAndroid(const KeyEventAndroid& other) = default;
+KeyEventAndroid& KeyEventAndroid::KeyEventAndroid::operator=(
+    const KeyEventAndroid& other) = default;
+
+KeyEventAndroid::~KeyEventAndroid() = default;
 
 ScopedJavaLocalRef<jobject> KeyEventAndroid::GetJavaObject() const {
   return ScopedJavaLocalRef<jobject>(event_);
 }
 
-KeyEvent KeyEventAndroid::ToKeyEvent() const {
-  KeyboardCode key_code = KeyboardCodeFromAndroidKeyCode(key_code_);
-
+int KeyEventAndroid::MetaState() const {
   JNIEnv* env = AttachCurrentThread();
-  jint android_meta_state =
-      JNI_KeyEvent::Java_KeyEvent_getMetaState(env, event_);
-  EventFlags modifiers = EventFlagsFromAndroidMetaState(android_meta_state);
+  return JNI_KeyEvent::Java_KeyEvent_getMetaState(env, event_);
+}
 
-  return KeyEvent(EventType::kKeyPressed, key_code, modifiers);
+int KeyEventAndroid::Action() const {
+  JNIEnv* env = AttachCurrentThread();
+  return JNI_KeyEvent::Java_KeyEvent_getAction(env, event_);
 }
 
 }  // namespace ui
diff --git a/ui/events/android/key_event_android.h b/ui/events/android/key_event_android.h
index 6bb18dbc..2bc408f 100644
--- a/ui/events/android/key_event_android.h
+++ b/ui/events/android/key_event_android.h
@@ -8,7 +8,6 @@
 #include <jni.h>
 
 #include "base/android/scoped_java_ref.h"
-#include "ui/events/event.h"
 #include "ui/events/events_export.h"
 
 namespace ui {
@@ -19,19 +18,19 @@
  public:
   KeyEventAndroid(JNIEnv* env, jobject event);
   KeyEventAndroid(JNIEnv* env, jobject event, int key_code);
+  // Synthesize android key event from given android action, key code, etc.
+  KeyEventAndroid(int action, int key_code, int meta_state);
 
-  KeyEventAndroid(const KeyEventAndroid&) = delete;
-  KeyEventAndroid& operator=(const KeyEventAndroid&) = delete;
+  KeyEventAndroid(const KeyEventAndroid& other);
+  KeyEventAndroid& operator=(const KeyEventAndroid& other);
 
   ~KeyEventAndroid();
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const;
   int key_code() const { return key_code_; }
 
-  // Converts the event to the cross-platform key event.
-  // TODO(crbug.com/417078839): Update PlatformEvent to be a union-ish type that
-  // can be a KeyEventAndroid and allow direct conversion of it to the KeyEvent.
-  KeyEvent ToKeyEvent() const;
+  int MetaState() const;
+  int Action() const;
 
  private:
   // The Java reference to the key event.
diff --git a/ui/events/android/platform_event_android.cc b/ui/events/android/platform_event_android.cc
new file mode 100644
index 0000000..2d276795
--- /dev/null
+++ b/ui/events/android/platform_event_android.cc
@@ -0,0 +1,32 @@
+// 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 "ui/events/android/platform_event_android.h"
+
+namespace ui {
+
+PlatformEventAndroid::PlatformEventAndroid() : event_(std::monostate{}) {}
+
+PlatformEventAndroid::PlatformEventAndroid(const KeyEventAndroid& key_event)
+    : event_(key_event) {}
+
+PlatformEventAndroid::PlatformEventAndroid(const PlatformEventAndroid& other) =
+    default;
+PlatformEventAndroid& PlatformEventAndroid::operator=(
+    const PlatformEventAndroid& other) = default;
+
+PlatformEventAndroid::~PlatformEventAndroid() {}
+
+bool PlatformEventAndroid::IsKeyboardEvent() const {
+  return std::holds_alternative<KeyEventAndroid>(event_);
+}
+
+const KeyEventAndroid* PlatformEventAndroid::AsKeyboardEventAndroid() const {
+  if (!IsKeyboardEvent()) {
+    return nullptr;
+  }
+  return &std::get<KeyEventAndroid>(event_);
+}
+
+}  // namespace ui
diff --git a/ui/events/android/platform_event_android.h b/ui/events/android/platform_event_android.h
new file mode 100644
index 0000000..5c5b85f4
--- /dev/null
+++ b/ui/events/android/platform_event_android.h
@@ -0,0 +1,39 @@
+// 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 UI_EVENTS_ANDROID_PLATFORM_EVENT_ANDROID_H_
+#define UI_EVENTS_ANDROID_PLATFORM_EVENT_ANDROID_H_
+
+#include "ui/events/android/key_event_android.h"
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+// Concrete type for the `PlatformEvent` on Android.
+class EVENTS_EXPORT PlatformEventAndroid {
+ public:
+  PlatformEventAndroid();
+
+  explicit PlatformEventAndroid(const KeyEventAndroid& key_event);
+
+  PlatformEventAndroid(const PlatformEventAndroid& other);
+  PlatformEventAndroid& operator=(const PlatformEventAndroid& other);
+
+  ~PlatformEventAndroid();
+
+  bool IsKeyboardEvent() const;
+
+  // Returns the keyboard event if the event is a keyboard event, otherwise
+  // returns nullptr.
+  const KeyEventAndroid* AsKeyboardEventAndroid() const;
+
+ private:
+  // TODO(crbug.com/417078839): Add `MotionEventAndroid` as a variant and
+  // replace its direct usages with `PlatformEvent` as appropriate.
+  std::variant<std::monostate, KeyEventAndroid> event_;
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_ANDROID_PLATFORM_EVENT_ANDROID_H_
diff --git a/ui/events/keycodes/keyboard_code_conversion_android.cc b/ui/events/keycodes/keyboard_code_conversion_android.cc
index 252b7c2..cc2e8bee 100644
--- a/ui/events/keycodes/keyboard_code_conversion_android.cc
+++ b/ui/events/keycodes/keyboard_code_conversion_android.cc
@@ -6,6 +6,8 @@
 
 #include <android/keycodes.h>
 
+#include "ui/events/keycodes/keyboard_codes.h"
+
 namespace ui {
 namespace {
 
@@ -776,4 +778,236 @@
   }
 }
 
+int AndroidKeyCodeFromKeyboardCode(KeyboardCode key_code) {
+  switch (key_code) {
+    case VKEY_BACK:
+      return AKEYCODE_DEL;
+    case VKEY_TAB:
+      return AKEYCODE_TAB;
+    case VKEY_CLEAR:
+      return AKEYCODE_CLEAR;
+    case VKEY_RETURN:
+      return AKEYCODE_ENTER;
+    case VKEY_LSHIFT:
+      return AKEYCODE_SHIFT_LEFT;
+    case VKEY_RSHIFT:
+      return AKEYCODE_SHIFT_RIGHT;
+    case VKEY_BROWSER_BACK:
+      return AKEYCODE_BACK;
+    case VKEY_BROWSER_FORWARD:
+      return AKEYCODE_FORWARD;
+    case VKEY_SPACE:
+      return AKEYCODE_SPACE;
+    case VKEY_HOME:
+      return AKEYCODE_MOVE_HOME;
+    case VKEY_LEFT:
+      return AKEYCODE_DPAD_LEFT;
+    case VKEY_UP:
+      return AKEYCODE_DPAD_UP;
+    case VKEY_RIGHT:
+      return AKEYCODE_DPAD_RIGHT;
+    case VKEY_DOWN:
+      return AKEYCODE_DPAD_DOWN;
+    case VKEY_0:
+      return AKEYCODE_0;
+    case VKEY_1:
+      return AKEYCODE_1;
+    case VKEY_2:
+      return AKEYCODE_2;
+    case VKEY_3:
+      return AKEYCODE_3;
+    case VKEY_4:
+      return AKEYCODE_4;
+    case VKEY_5:
+      return AKEYCODE_5;
+    case VKEY_6:
+      return AKEYCODE_6;
+    case VKEY_7:
+      return AKEYCODE_7;
+    case VKEY_8:
+      return AKEYCODE_8;
+    case VKEY_9:
+      return AKEYCODE_9;
+    case VKEY_A:
+      return AKEYCODE_A;
+    case VKEY_B:
+      return AKEYCODE_B;
+    case VKEY_C:
+      return AKEYCODE_C;
+    case VKEY_D:
+      return AKEYCODE_D;
+    case VKEY_E:
+      return AKEYCODE_E;
+    case VKEY_F:
+      return AKEYCODE_F;
+    case VKEY_G:
+      return AKEYCODE_G;
+    case VKEY_H:
+      return AKEYCODE_H;
+    case VKEY_I:
+      return AKEYCODE_I;
+    case VKEY_J:
+      return AKEYCODE_J;
+    case VKEY_K:
+      return AKEYCODE_K;
+    case VKEY_L:
+      return AKEYCODE_L;
+    case VKEY_M:
+      return AKEYCODE_M;
+    case VKEY_N:
+      return AKEYCODE_N;
+    case VKEY_O:
+      return AKEYCODE_O;
+    case VKEY_P:
+      return AKEYCODE_P;
+    case VKEY_Q:
+      return AKEYCODE_Q;
+    case VKEY_R:
+      return AKEYCODE_R;
+    case VKEY_S:
+      return AKEYCODE_S;
+    case VKEY_T:
+      return AKEYCODE_T;
+    case VKEY_U:
+      return AKEYCODE_U;
+    case VKEY_V:
+      return AKEYCODE_V;
+    case VKEY_W:
+      return AKEYCODE_W;
+    case VKEY_X:
+      return AKEYCODE_X;
+    case VKEY_Y:
+      return AKEYCODE_Y;
+    case VKEY_Z:
+      return AKEYCODE_Z;
+    case VKEY_VOLUME_DOWN:
+      return AKEYCODE_VOLUME_DOWN;
+    case VKEY_VOLUME_UP:
+      return AKEYCODE_VOLUME_UP;
+    case VKEY_MEDIA_NEXT_TRACK:
+      return AKEYCODE_MEDIA_NEXT;
+    case VKEY_MEDIA_PREV_TRACK:
+      return AKEYCODE_MEDIA_PREVIOUS;
+    case VKEY_MEDIA_STOP:
+      return AKEYCODE_MEDIA_STOP;
+    case VKEY_MEDIA_PLAY_PAUSE:
+      return AKEYCODE_MEDIA_PLAY_PAUSE;
+    // Colon key.
+    case VKEY_OEM_1:
+      return AKEYCODE_SEMICOLON;
+    case VKEY_OEM_COMMA:
+      return AKEYCODE_COMMA;
+    case VKEY_OEM_MINUS:
+      return AKEYCODE_MINUS;
+    case VKEY_OEM_PLUS:
+      return AKEYCODE_EQUALS;
+    case VKEY_OEM_PERIOD:
+      return AKEYCODE_PERIOD;
+    case VKEY_OEM_2:
+      return AKEYCODE_SLASH;
+    case VKEY_OEM_4:
+      return AKEYCODE_LEFT_BRACKET;
+    case VKEY_OEM_5:
+      return AKEYCODE_BACKSLASH;
+    case VKEY_OEM_6:
+      return AKEYCODE_RIGHT_BRACKET;
+    case VKEY_VOLUME_MUTE:
+      return AKEYCODE_VOLUME_MUTE;
+    case VKEY_ESCAPE:
+      return AKEYCODE_ESCAPE;
+    case VKEY_END:
+      return AKEYCODE_MOVE_END;
+    case VKEY_LMENU:
+      return AKEYCODE_ALT_LEFT;
+    case VKEY_RMENU:
+      return AKEYCODE_ALT_RIGHT;
+    case VKEY_OEM_3:
+      return AKEYCODE_GRAVE;
+    case VKEY_OEM_103:
+      return AKEYCODE_MEDIA_REWIND;
+    case VKEY_OEM_104:
+      return AKEYCODE_MEDIA_FAST_FORWARD;
+    case VKEY_PRIOR:
+      return AKEYCODE_CHANNEL_UP;
+    case VKEY_NEXT:
+      return AKEYCODE_CHANNEL_DOWN;
+    case VKEY_DELETE:
+      return AKEYCODE_FORWARD_DEL;
+    case VKEY_LCONTROL:
+      return AKEYCODE_CTRL_LEFT;
+    case VKEY_RCONTROL:
+      return AKEYCODE_CTRL_RIGHT;
+    case VKEY_CAPITAL:
+      return AKEYCODE_CAPS_LOCK;
+    case VKEY_SCROLL:
+      return AKEYCODE_SCROLL_LOCK;
+    case VKEY_LWIN:
+      return AKEYCODE_META_LEFT;
+    case VKEY_RWIN:
+      return AKEYCODE_META_RIGHT;
+    case VKEY_PAUSE:
+      return AKEYCODE_BREAK;
+    case VKEY_INSERT:
+      return AKEYCODE_INSERT;
+    case VKEY_F1:
+      return AKEYCODE_F1;
+    case VKEY_F2:
+      return AKEYCODE_F2;
+    case VKEY_F3:
+      return AKEYCODE_F3;
+    case VKEY_F4:
+      return AKEYCODE_F4;
+    case VKEY_F5:
+      return AKEYCODE_F5;
+    case VKEY_F6:
+      return AKEYCODE_F6;
+    case VKEY_F7:
+      return AKEYCODE_F7;
+    case VKEY_F8:
+      return AKEYCODE_F8;
+    case VKEY_F9:
+      return AKEYCODE_F9;
+    case VKEY_F10:
+      return AKEYCODE_F10;
+    case VKEY_F11:
+      return AKEYCODE_F11;
+    case VKEY_F12:
+      return AKEYCODE_F12;
+    case VKEY_NUMLOCK:
+      return AKEYCODE_NUM_LOCK;
+    case VKEY_NUMPAD0:
+      return AKEYCODE_NUMPAD_0;
+    case VKEY_NUMPAD1:
+      return AKEYCODE_NUMPAD_1;
+    case VKEY_NUMPAD2:
+      return AKEYCODE_NUMPAD_2;
+    case VKEY_NUMPAD3:
+      return AKEYCODE_NUMPAD_3;
+    case VKEY_NUMPAD4:
+      return AKEYCODE_NUMPAD_4;
+    case VKEY_NUMPAD5:
+      return AKEYCODE_NUMPAD_5;
+    case VKEY_NUMPAD6:
+      return AKEYCODE_NUMPAD_6;
+    case VKEY_NUMPAD7:
+      return AKEYCODE_NUMPAD_7;
+    case VKEY_NUMPAD8:
+      return AKEYCODE_NUMPAD_8;
+    case VKEY_NUMPAD9:
+      return AKEYCODE_NUMPAD_9;
+    case VKEY_DIVIDE:
+      return AKEYCODE_NUMPAD_DIVIDE;
+    case VKEY_MULTIPLY:
+      return AKEYCODE_NUMPAD_MULTIPLY;
+    case VKEY_SUBTRACT:
+      return AKEYCODE_NUMPAD_SUBTRACT;
+    case VKEY_ADD:
+      return AKEYCODE_NUMPAD_ADD;
+    case VKEY_DECIMAL:
+      return AKEYCODE_NUMPAD_DOT;
+    default:
+      return AKEYCODE_UNKNOWN;
+  }
+}
+
 }  // namespace ui
diff --git a/ui/events/keycodes/keyboard_code_conversion_android.h b/ui/events/keycodes/keyboard_code_conversion_android.h
index 2f130bb2..b960a96 100644
--- a/ui/events/keycodes/keyboard_code_conversion_android.h
+++ b/ui/events/keycodes/keyboard_code_conversion_android.h
@@ -13,6 +13,9 @@
 
 EVENTS_BASE_EXPORT KeyboardCode KeyboardCodeFromAndroidKeyCode(int keycode);
 
+EVENTS_BASE_EXPORT int AndroidKeyCodeFromKeyboardCode(
+    KeyboardCode keyboard_code);
+
 // Returns DomKey from an Android character and keycode.
 EVENTS_BASE_EXPORT DomKey GetDomKeyFromAndroidEvent(int keycode,
                                                     int unicode_character);
diff --git a/ui/events/keycodes/keyboard_code_conversion_android_unittest.cc b/ui/events/keycodes/keyboard_code_conversion_android_unittest.cc
new file mode 100644
index 0000000..bee6a8376
--- /dev/null
+++ b/ui/events/keycodes/keyboard_code_conversion_android_unittest.cc
@@ -0,0 +1,110 @@
+// 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 "ui/events/keycodes/keyboard_code_conversion_android.h"
+
+#include <android/keycodes.h>
+
+#include <array>
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/dom_us_layout_data.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/test/keyboard_layout.h"
+
+namespace ui {
+namespace {
+
+struct AndroidKeyCodeToKeyboardCode {
+  int android_key_code;
+  KeyboardCode keyboard_code;
+};
+
+constexpr std::array<AndroidKeyCodeToKeyboardCode, 21>
+    kAndroidKeyCodeToKeyboardCodeMap = {
+        {// Spot-check several key codes
+         {AKEYCODE_DEL, KeyboardCode::VKEY_BACK},
+         {AKEYCODE_SHIFT_LEFT, KeyboardCode::VKEY_LSHIFT},
+         {AKEYCODE_BACK, KeyboardCode::VKEY_BROWSER_BACK},
+         {AKEYCODE_DPAD_LEFT, KeyboardCode::VKEY_LEFT},
+         {AKEYCODE_0, KeyboardCode::VKEY_0},
+         {AKEYCODE_Z, KeyboardCode::VKEY_Z},
+         {AKEYCODE_VOLUME_DOWN, KeyboardCode::VKEY_VOLUME_DOWN},
+         {AKEYCODE_SEMICOLON, KeyboardCode::VKEY_OEM_1},
+         {AKEYCODE_SLASH, KeyboardCode::VKEY_OEM_2},
+         {AKEYCODE_INSERT, KeyboardCode::VKEY_INSERT},
+         {AKEYCODE_F5, KeyboardCode::VKEY_F5},
+         {AKEYCODE_NUMPAD_0, KeyboardCode::VKEY_NUMPAD0},
+         {AKEYCODE_NUMPAD_DOT, KeyboardCode::VKEY_DECIMAL},
+         {AKEYCODE_CHANNEL_DOWN, KeyboardCode::VKEY_NEXT},
+         // Android keycodes mapped to the same key code.
+         {AKEYCODE_DPAD_CENTER, KeyboardCode::VKEY_RETURN},
+         {AKEYCODE_ENTER, KeyboardCode::VKEY_RETURN},
+         {AKEYCODE_MUTE, KeyboardCode::VKEY_VOLUME_MUTE},
+         {AKEYCODE_VOLUME_MUTE, KeyboardCode::VKEY_VOLUME_MUTE},
+         {AKEYCODE_MEDIA_PLAY, KeyboardCode::VKEY_MEDIA_PLAY_PAUSE},
+         {AKEYCODE_MEDIA_PLAY_PAUSE, KeyboardCode::VKEY_MEDIA_PLAY_PAUSE},
+         // Unknown
+         {AKEYCODE_UNKNOWN, KeyboardCode::VKEY_UNKNOWN}}};
+
+struct KeyboardCodeToAndroidKeyCode {
+  KeyboardCode keyboard_code;
+  int android_key_code;
+};
+
+constexpr std::array<KeyboardCodeToAndroidKeyCode, 18>
+    kKeyboardCodeToAndroidKeyCodeMap = {
+        {// Spot-check several key codes
+         {KeyboardCode::VKEY_BACK, AKEYCODE_DEL},
+         {KeyboardCode::VKEY_LSHIFT, AKEYCODE_SHIFT_LEFT},
+         {KeyboardCode::VKEY_BROWSER_BACK, AKEYCODE_BACK},
+         {KeyboardCode::VKEY_LEFT, AKEYCODE_DPAD_LEFT},
+         {KeyboardCode::VKEY_0, AKEYCODE_0},
+         {KeyboardCode::VKEY_Z, AKEYCODE_Z},
+         {KeyboardCode::VKEY_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN},
+         {KeyboardCode::VKEY_OEM_1, AKEYCODE_SEMICOLON},
+         {KeyboardCode::VKEY_OEM_2, AKEYCODE_SLASH},
+         {KeyboardCode::VKEY_INSERT, AKEYCODE_INSERT},
+         {KeyboardCode::VKEY_F5, AKEYCODE_F5},
+         {KeyboardCode::VKEY_NUMPAD0, AKEYCODE_NUMPAD_0},
+         {KeyboardCode::VKEY_DECIMAL, AKEYCODE_NUMPAD_DOT},
+         {KeyboardCode::VKEY_NEXT, AKEYCODE_CHANNEL_DOWN},
+         // Android keycodes mapped to the same key code.
+         {KeyboardCode::VKEY_RETURN, AKEYCODE_ENTER},
+         {KeyboardCode::VKEY_VOLUME_MUTE, AKEYCODE_VOLUME_MUTE},
+         {KeyboardCode::VKEY_MEDIA_PLAY_PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE},
+         // Unknown
+         {KeyboardCode::VKEY_UNKNOWN, AKEYCODE_UNKNOWN}}};
+
+}  // namespace
+
+TEST(KeyboardCodeConversionAndroidTest, AndroidToChrome) {
+  for (const auto& entry : kAndroidKeyCodeToKeyboardCodeMap) {
+    EXPECT_EQ(entry.keyboard_code,
+              KeyboardCodeFromAndroidKeyCode(entry.android_key_code));
+  }
+}
+
+TEST(KeyboardCodeConversionAndroidTest, ChromeToAndroid) {
+  for (const auto& entry : kKeyboardCodeToAndroidKeyCodeMap) {
+    EXPECT_EQ(entry.android_key_code,
+              AndroidKeyCodeFromKeyboardCode(entry.keyboard_code));
+  }
+
+  for (int i = 0; i < 256; i++) {
+    const KeyboardCode keyboard_code = static_cast<KeyboardCode>(i);
+    const int android_key_code = AndroidKeyCodeFromKeyboardCode(keyboard_code);
+    if (android_key_code == AKEYCODE_UNKNOWN) {
+      continue;
+    }
+    EXPECT_EQ(keyboard_code, KeyboardCodeFromAndroidKeyCode(android_key_code));
+  }
+}
+
+}  // namespace ui
diff --git a/ui/events/platform_event.h b/ui/events/platform_event.h
index 59057bb..cc037b27 100644
--- a/ui/events/platform_event.h
+++ b/ui/events/platform_event.h
@@ -15,6 +15,8 @@
 #include "base/win/windows_types.h"
 #elif BUILDFLAG(IS_APPLE)
 #include "base/apple/owned_objc.h"
+#elif BUILDFLAG(IS_ANDROID)
+#include "ui/events/android/platform_event_android.h"
 #endif
 
 namespace ui {
@@ -32,6 +34,8 @@
 using PlatformEvent = base::apple::OwnedNSEvent;
 #elif BUILDFLAG(IS_IOS)
 using PlatformEvent = base::apple::OwnedUIEvent;
+#elif BUILDFLAG(IS_ANDROID)
+using PlatformEvent = ui::PlatformEventAndroid;
 #else
 using PlatformEvent = void*;
 #endif
diff --git a/v8 b/v8
index 5ab97a6..6dc75f0 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 5ab97a63041bd352dc145b8311e6fcb7814ab690
+Subproject commit 6dc75f0da012c4a9f638b78eefa86876a8349e77