diff --git a/DEPS b/DEPS
index ff213fd..599934e 100644
--- a/DEPS
+++ b/DEPS
@@ -306,15 +306,15 @@
   # 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': '3a3475d12f220b795821eabae517ab7cb6f12c9f',
+  'skia_revision': '9d220ebe40a0e8537f3e37d8ac1fbe4ac4dfa43a',
   # 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': 'b057218023961f8b94b0313dd6ddbcc274c06e74',
+  'v8_revision': '13b0f9f24b88983f07952beb652e1bce97a4deb6',
   # 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': '35e49df77d01932715b8cd8dd3e1613cbd476561',
+  'angle_revision': 'bdd3a778370b833bb91659971efa001c584900a8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -322,7 +322,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': 'cb1cd2f12898d7cdc0d9435be2244ce27f88afe3',
+  'pdfium_revision': 'dda631d81103d0af8fa2fe4bd81e9da08435f989',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -377,11 +377,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'b142d415308e1f3ace94f0f39807bf0198ee004f',
+  'catapult_revision': 'd12e6887dd534569117c06f92e8c69c91e0ad12b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '510ec37c3f2bf8431f8c6f1a573d6826ed01d9e6',
+  'chromium_variations_revision': '62652a482c1bc8658057a7fa7b216f638d0dfaae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -397,7 +397,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '7781523a3fc8f16c45a382676e73b1f7f28a58e5',
+  'devtools_frontend_revision': 'c7e8227f786e657d8f82d6e9f1de859ed60280df',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -421,7 +421,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': '109e648f2f452424d2d1d0b1eba1e1b9fe036645',
+  'dawn_revision': '3c117aa551537c3e7cc0f8cbb05d85fe76d466fc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -465,7 +465,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'cros_components_revision': 'b1b1b0b6ff08289f3f5d960947aa12db68775d41',
+  'cros_components_revision': 'b7deff896ee3186e7d33a52ddde07da2400de2ad',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -500,7 +500,7 @@
   'libcxx_revision':       '1f70899ab6d9d2c3c455fa7adb3f3cbd7bfdf215',
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:7367b0df0a0aa25440303998d54045bda73935a5',
+  'gn_version': 'git_revision:85944ebc24a90ec1e489e85a46fdc68542c3146f',
 
   # ninja CIPD package version.
   # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
@@ -826,7 +826,7 @@
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '8fa01e615655f80075f9149063032d3e3d5956df',
+    'url': Var('chromium_git') + '/website.git' + '@' + '7e14119375ad198e276c3a2eecafb4f9b0970d1f',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1199,7 +1199,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'd4775b3834d55829a429cf165089e92261a9e426',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '14464a6787e9a358a6acdc532568e6fe3a347344',
     'condition': 'checkout_src_internal',
   },
 
@@ -1846,10 +1846,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7a6ef7301b5d84f751b483f9d5466b3696749c26',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '666950d6de30c9c26773208b0f861463b25ae37c',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '21edbe5d0dc7a506ff42b858969d16d0cbdd3a0b',
+    Var('webrtc_git') + '/src.git' + '@' + 'e6df126b798c0644010afeaddeb2e13053d8f192',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -4006,7 +4006,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'c8b84877296746df0c2ad8088c1e53d19b10c8bc',
+        'b8fd6d1953501218760e0f7e2f0485c44d4925c1',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index b89421d1..e7ff79f 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2793,11 +2793,6 @@
              "VirtualKeyboardRoundCorners",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Enable or disable Nacl for virtual keyboard on ChromeOS.
-BASE_FEATURE(kVirtualKeyboardRemoveNacl,
-             "VirtualKeyboardRemoveNacl",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Controls whether to allow enabling wake on WiFi features in shill.
 BASE_FEATURE(kWakeOnWifiAllowed,
              "WakeOnWifiAllowed",
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 53925f1..b45c7f1 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -558,8 +558,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kEducationEnrollmentOobeFlow);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMicMuteNotifications);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kMigrateOwnerKeyToPrivateSlot);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMinimumChromeVersion);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMojoDBusRelay);
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -793,8 +791,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSmdsSupport);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSnapGroup);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSnoopingProtection);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kStoreOwnerKeyInPrivateSlot);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kStylusBatteryStatus);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kStartAssistantAudioDecoderOnDemand);
@@ -863,8 +859,6 @@
 BASE_DECLARE_FEATURE(kVirtualKeyboardBorderedKey);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kVirtualKeyboardRoundCorners);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kVirtualKeyboardRemoveNacl);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kWakeOnWifiAllowed);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kWallpaperFastRefresh);
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/device_operator.ts b/ash/webui/camera_app_ui/resources/js/mojo/device_operator.ts
index 3876dea..37bd60ee 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/device_operator.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/device_operator.ts
@@ -10,6 +10,7 @@
 import * as state from '../state.js';
 import {
   CameraSuspendError,
+  CropRegionRect,
   ErrorLevel,
   ErrorType,
   Facing,
@@ -815,6 +816,24 @@
   }
 
   /**
+   * Sets the crop region for the configured stream on camera with |deviceId|.
+   */
+  async setCropRegion(deviceId: string, cropRegion: CropRegionRect):
+      Promise<void> {
+    const device = await this.getDevice(deviceId);
+    await device.setCropRegion(cropRegion);
+  }
+
+  /**
+   * Resets the crop region for the camera with |deviceId| to let the camera
+   * stream back to full frame.
+   */
+  async resetCropRegion(deviceId: string): Promise<void> {
+    const device = await this.getDevice(deviceId);
+    await device.resetCropRegion();
+  }
+
+  /**
    * Initializes the singleton instance.
    *
    * This should be called before all invocation of static getInstance() and
diff --git a/ash/webui/camera_app_ui/resources/js/type.ts b/ash/webui/camera_app_ui/resources/js/type.ts
index f1d3db5..c2a6c800 100644
--- a/ash/webui/camera_app_ui/resources/js/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/type.ts
@@ -505,4 +505,15 @@
   CANNOT_START = 'cannot-start',
 }
 
+/**
+ * A rectangle representing a crop region with size (width, height) and having
+ * the top-left coordinate at (x, y).
+ */
+export interface CropRegionRect {
+  height: number;
+  width: number;
+  x: number;
+  y: number;
+}
+
 export type Awaitable<T> = PromiseLike<T>|T;
diff --git a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
index 7ab994e..48d0270 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/fake_shortcut_provider.ts
@@ -33,11 +33,11 @@
   private preventProcessingAcceleratorsCallCount: number = 0;
   private addAcceleratorCallCount: number = 0;
   private removeAcceleratorCallCount: number = 0;
-  private lastRecordedUserAction: UserAction|undefined;
-  private lastRecordedMainCategory: AcceleratorCategory|undefined;
-  private lastRecoredEditDialogActions: EditDialogCompletedActions|undefined;
+  private lastRecordedUserAction: UserAction;
+  private lastRecordedMainCategory: AcceleratorCategory;
+  private lastRecoredEditDialogActions: EditDialogCompletedActions;
   private lastRecordedIsAdd: boolean = false;
-  private lastRecorededSubactions: Subactions|undefined;
+  private lastRecorededSubactions: Subactions;
 
   constructor() {
     this.methods = new FakeMethodResolver();
@@ -76,11 +76,6 @@
     this.preventProcessingAcceleratorsCallCount = 0;
     this.addAcceleratorCallCount = 0;
     this.removeAcceleratorCallCount = 0;
-    this.lastRecordedUserAction = undefined;
-    this.lastRecordedMainCategory = undefined;
-    this.lastRecoredEditDialogActions = undefined;
-    this.lastRecordedIsAdd = false;
-    this.lastRecorededSubactions = undefined;
     this.observables = new FakeObservables();
     this.registerObservables();
   }
@@ -192,11 +187,11 @@
     this.lastRecoredEditDialogActions = completed_actions;
   }
 
-  getLastEditDialogCompletedActions(): EditDialogCompletedActions|undefined {
+  getLastEditDialogCompletedActions(): EditDialogCompletedActions {
     return this.lastRecoredEditDialogActions;
   }
 
-  getLatestRecordedAction(): UserAction|undefined {
+  getLatestRecordedAction(): UserAction {
     return this.lastRecordedUserAction;
   }
 
@@ -204,7 +199,7 @@
     this.lastRecordedMainCategory = category;
   }
 
-  getLatestMainCategoryNavigated(): AcceleratorCategory|undefined {
+  getLatestMainCategoryNavigated(): AcceleratorCategory {
     return this.lastRecordedMainCategory;
   }
 
@@ -217,7 +212,7 @@
     return this.lastRecordedIsAdd;
   }
 
-  getLastRecordedSubactions(): Subactions|undefined {
+  getLastRecordedSubactions(): Subactions {
     return this.lastRecorededSubactions;
   }
 
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index f501cd92..93da1e4 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -90,10 +90,11 @@
 
 using chromeos::WindowStateType;
 
-// Three fixed position ratios of the divider, which means the divider can
-// always be moved to these three positions.
-constexpr float kFixedPositionRatios[] = {0.f, chromeos::kDefaultSnapRatio,
-                                          1.0f};
+// Five fixed position ratios of the divider, which means the divider can
+// always be moved to these five positions.
+constexpr float kFixedPositionRatios[] = {0.f, chromeos::kOneThirdSnapRatio,
+                                          chromeos::kDefaultSnapRatio,
+                                          chromeos::kTwoThirdSnapRatio, 1.0f};
 
 // The black scrim starts to fade in when the divider is moved past the two
 // optional positions (`chromeos::kOneThirdSnapRatio`,
@@ -781,7 +782,6 @@
   aura::Window* previous_snapped_window = nullptr;
   aura::Window* other_window = nullptr;
   if (snap_position == SnapPosition::kPrimary) {
-    other_window = secondary_window_;
     if (primary_window_ != window) {
       previous_snapped_window = primary_window_;
       StopObserving(SnapPosition::kPrimary);
@@ -793,18 +793,21 @@
       secondary_window_ = nullptr;
       default_snap_position_ = SnapPosition::kPrimary;
     }
+    // `other_window` must be set last, since we may have removed
+    // `secondary_window_`.
+    other_window = secondary_window_;
   } else if (snap_position == SnapPosition::kSecondary) {
-    other_window = primary_window_;
+    // See above comments.
     if (secondary_window_ != window) {
       previous_snapped_window = secondary_window_;
       StopObserving(SnapPosition::kSecondary);
       secondary_window_ = window;
     }
     if (primary_window_ == window) {
-      // See above comment.
       primary_window_ = nullptr;
       default_snap_position_ = SnapPosition::kSecondary;
     }
+    other_window = primary_window_;
   }
   StartObserving(window);
 
@@ -829,16 +832,14 @@
         std::make_unique<SplitViewDivider>(this, divider_position_);
   }
 
-  if (split_view_divider_) {
-    divider_position_ = GetClosestFixedDividerPosition();
-    split_view_divider_->UpdateDividerBounds();
-  }
-
+  // This must be done before we push `divider_position_` to the closest fixed
+  // ratio, since the minimum size will be respected there.
+  const int new_divider_position = GetClosestFixedDividerPosition();
   const bool total_size_exceeds_work_area =
       divider_position_ + kSplitviewDividerShortSideLength +
           GetMinimumWindowLength(other_window, IsLayoutHorizontal(window)) >
       GetDividerPositionUpperLimit(root_window_);
-  if (primary_window_ && secondary_window_ && total_size_exceeds_work_area) {
+  if (split_view_divider_ && other_window && total_size_exceeds_work_area) {
     // If `other_window` can't fit in the opposite position, set
     // `divider_snap_animation_` to Hide then Show, to give off the
     // impression of bouncing the divider back to `old_divider_position`.
@@ -846,12 +847,17 @@
     // bounce out then in.
     tablet_resize_mode_ = TabletResizeMode::kFast;
     divider_snap_animation_ = std::make_unique<DividerSnapAnimation>(
-        this, divider_position_, old_divider_position,
+        this, new_divider_position, old_divider_position,
         2 * kBouncingAnimationOneWayDuration, gfx::Tween::FAST_OUT_SLOW_IN_3);
     divider_snap_animation_->Hide();
     divider_snap_animation_->Show();
   }
 
+  if (split_view_divider_) {
+    divider_position_ = new_divider_position;
+    split_view_divider_->UpdateDividerBounds();
+  }
+
   base::RecordAction(base::UserMetricsAction("SplitView_SnapWindow"));
 }
 
@@ -1009,7 +1015,6 @@
   const bool is_divider_animating = IsDividerAnimating();
   if ((IsResizingWithDivider() || is_divider_animating) &&
       end_reason != EndReason::kRootWindowDestroyed) {
-    split_view_divider_->set_is_resizing_with_divider(false);
     if (is_divider_animating) {
       // Don't call StopAndShoveAnimatedDivider as it will call observers.
       StopSnapAnimation();
@@ -2226,7 +2231,6 @@
   // view.
   const bool is_divider_animating = IsDividerAnimating();
   if (IsResizingWithDivider() || is_divider_animating) {
-    split_view_divider_->set_is_resizing_with_divider(false);
     if (is_divider_animating) {
       StopAndShoveAnimatedDivider();
     }
@@ -2296,13 +2300,14 @@
       static_cast<float>(min_left_size) / divider_upper_limit;
   const float min_size_right_ratio =
       static_cast<float>(min_right_size) / divider_upper_limit;
-  if (min_size_left_ratio <= chromeos::kOneThirdSnapRatio) {
-    out_position_ratios->push_back(chromeos::kOneThirdSnapRatio);
+  if (min_size_left_ratio > chromeos::kOneThirdSnapRatio) {
+    // If `primary_window_` can't fit in 1/3, remove 0.33f divider position.
+    base::Erase(*out_position_ratios, chromeos::kOneThirdSnapRatio);
   }
-  if (min_size_right_ratio <= chromeos::kOneThirdSnapRatio) {
-    out_position_ratios->push_back(chromeos::kTwoThirdSnapRatio);
+  if (min_size_right_ratio > chromeos::kOneThirdSnapRatio) {
+    // If `secondary_window_` can't fit in 1/3, remove 0.67f divider position.
+    base::Erase(*out_position_ratios, chromeos::kTwoThirdSnapRatio);
   }
-
   // Remove 0.5f if a window cannot be snapped. We can get into this state by
   // snapping a window to two thirds.
   if (min_size_left_ratio > chromeos::kDefaultSnapRatio ||
@@ -2557,7 +2562,11 @@
 
 void SplitViewController::EndResizeWithDividerImpl() {
   DCHECK(InSplitViewMode());
-  DCHECK(!IsResizingWithDivider());
+  if (split_view_divider_) {
+    // TODO(b/315854755): Move `DividerSnapAnimation` to `SplitViewDivider` and
+    // see if we can remove this.
+    split_view_divider_->set_is_resizing_with_divider(false);
+  }
 
   EndTabletResizeImpl();
   presentation_time_recorder_.reset();
@@ -2639,9 +2648,9 @@
 void SplitViewController::OnTabletModeEnding() {
   split_view_type_ = SplitViewType::kClamshellType;
 
+  // `OnTabletModeEnding()` can also be called during test teardown.
   const bool is_divider_animating = IsDividerAnimating();
   if (IsResizingWithDivider() || is_divider_animating) {
-    split_view_divider_->set_is_resizing_with_divider(false);
     if (is_divider_animating) {
       StopAndShoveAnimatedDivider();
     }
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index b6b7147..28479c92 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -3326,8 +3326,9 @@
 }
 
 // Tests that, if two windows are snapped and one window has min size, trying to
-// partial split the other window opens Overview and updates bounds correctly.
-TEST_F(SplitViewControllerTest, SnapWindowWithMinSizeOpensOverview) {
+// partial split the other window starts a bounce animation.
+TEST_F(SplitViewControllerTest,
+       SnapWindowWithMinSizeStartsDividerSnapAnimation) {
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
@@ -3349,6 +3350,7 @@
   WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
                                            chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
+  ASSERT_TRUE(IsDividerAnimating());
   SkipDividerSnapAnimation();
   gfx::Rect divider_bounds =
       split_view_divider()->GetDividerBoundsInScreen(/*is_dragging=*/false);
@@ -3360,6 +3362,39 @@
             window2->bounds().width() + kSplitviewDividerShortSideLength / 2);
 }
 
+// Tests no crash on tablet <-> clamshell transition after a divider snap
+// animation is started.
+TEST_F(SplitViewControllerTest, NoCrashAfterDividerSnapAnimation) {
+  ui::ScopedAnimationDurationScaleMode animation_scale(
+      ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
+
+  // Snap 2 windows in split view. Set `window2` min length to be 0.4 of
+  // the work area so it can't fit in 1/3 split.
+  gfx::Rect work_area_bounds =
+      screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
+          window1.get());
+  aura::test::TestWindowDelegate* delegate2 =
+      static_cast<aura::test::TestWindowDelegate*>(window2->delegate());
+  delegate2->set_minimum_size(
+      gfx::Size(work_area_bounds.width() * 0.4f, work_area_bounds.height()));
+  WindowSnapWMEvent snap_primary(WM_EVENT_SNAP_PRIMARY);
+  WindowState::Get(window1.get())->OnWMEvent(&snap_primary);
+  WindowSnapWMEvent snap_secondary(WM_EVENT_SNAP_SECONDARY);
+  WindowState::Get(window2.get())->OnWMEvent(&snap_secondary);
+
+  // Since `window2` can't fit in 1/3, we start a divider snap animation.
+  WindowSnapWMEvent snap_primary_two_third(WM_EVENT_SNAP_PRIMARY,
+                                           chromeos::kTwoThirdSnapRatio);
+  WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_third);
+  ASSERT_TRUE(IsDividerAnimating());
+
+  // Transition to clamshell mode. Test no crash.
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
+}
+
 // Tests that resnapping a snapped window to its opposite snap position will
 // start the partial overview and divider will be at the correct position. See
 // crash at b/311216394.
@@ -3378,6 +3413,7 @@
   delegate2->set_minimum_size(
       gfx::Size(work_area_bounds.width() * 0.4f, work_area_bounds.height()));
 
+  // Snap `window1` to primary 2/3.
   WindowSnapWMEvent snap_primary_two_thirds(WM_EVENT_SNAP_PRIMARY,
                                             chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window1.get())->OnWMEvent(&snap_primary_two_thirds);
@@ -3390,6 +3426,8 @@
           ->split_view_overview_session();
   EXPECT_TRUE(split_view_overview_session);
 
+  // Select `window2` from overview. Since its minimum size is greater than 1/3,
+  // it gets snapped at 1/2.
   auto* item2 = GetOverviewItemForWindow(window2.get());
   auto* event_generator = GetEventGenerator();
   event_generator->MoveMouseTo(
@@ -3398,15 +3436,21 @@
 
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::State::kBothSnapped);
+  EXPECT_EQ(
+      work_area_bounds.width() * 0.5f - kSplitviewDividerShortSideLength / 2,
+      split_view_controller()->divider_position());
   EXPECT_EQ(work_area_bounds.width() * 0.5f,
             window1->bounds().width() + kSplitviewDividerShortSideLength / 2);
   EXPECT_EQ(work_area_bounds.width() * 0.5f,
             window2->bounds().width() + kSplitviewDividerShortSideLength / 2);
 
+  // Re-snap `window2` to primary 2/3.
   WindowSnapWMEvent snap_secondary_two_thirds(WM_EVENT_SNAP_PRIMARY,
                                               chromeos::kTwoThirdSnapRatio);
   WindowState::Get(window2.get())->OnWMEvent(&snap_secondary_two_thirds);
-  SkipDividerSnapAnimation();
+  EXPECT_NEAR(work_area_bounds.width() * 0.67f,
+              split_view_controller()->divider_position(),
+              kSplitviewDividerShortSideLength);
   EXPECT_NEAR(work_area_bounds.width() * 0.67f, window2->bounds().width(),
               kSplitviewDividerShortSideLength);
   EXPECT_TRUE(overview_controller->InOverviewSession());
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index 3af8250..4c76fee 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -38,8 +38,8 @@
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/PasswordGenerationIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/all_passwords_bottom_sheet/AllPasswordsBottomSheetViewTest.java",
-    "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java",
+    "javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_component/AccessorySheetViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabViewTest.java",
@@ -48,7 +48,6 @@
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryIntegrationTest.java",
-    "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java",
     "javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java",
   ]
 
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index 16b3f842..8bb1b88 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -84,10 +84,10 @@
     "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMediator.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryMetricsRecorder.java",
-    "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java",
-    "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryRecyclerViewMcp.java",
+    "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java",
+    "java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupCoordinator.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupMediator.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupProperties.java",
@@ -120,7 +120,6 @@
     "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessoryInfoView.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetCoordinator.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetMediator.java",
-    "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewBinder.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewBinder.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PromoCodeAccessoryInfoView.java",
     "java/src/org/chromium/chrome/browser/keyboard_accessory/utils/InsecureFillingDialogUtils.java",
@@ -136,13 +135,12 @@
     "java/res/layout/address_accessory_sheet.xml",
     "java/res/layout/all_passwords_bottom_sheet.xml",
     "java/res/layout/credit_card_accessory_sheet.xml",
-    "java/res/layout/keyboard_accessory_action_modern.xml",
+    "java/res/layout/keyboard_accessory.xml",
+    "java/res/layout/keyboard_accessory_action.xml",
     "java/res/layout/keyboard_accessory_buttons.xml",
-    "java/res/layout/keyboard_accessory_modern.xml",
     "java/res/layout/keyboard_accessory_sheet.xml",
     "java/res/layout/keyboard_accessory_sheet_tab_address_info.xml",
     "java/res/layout/keyboard_accessory_sheet_tab_credit_card_info.xml",
-    "java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml",
     "java/res/layout/keyboard_accessory_sheet_tab_legacy_title.xml",
     "java/res/layout/keyboard_accessory_sheet_tab_option_toggle.xml",
     "java/res/layout/keyboard_accessory_sheet_tab_password_info.xml",
@@ -151,8 +149,6 @@
     "java/res/layout/keyboard_accessory_suggestion.xml",
     "java/res/layout/password_accessory_passkey_chip.xml",
     "java/res/layout/password_accessory_sheet.xml",
-    "java/res/layout/password_accessory_sheet_label.xml",
-    "java/res/layout/password_accessory_sheet_legacy_option.xml",
     "java/res/layout/password_accessory_sheet_option.xml",
     "java/res/values/dimens.xml",
     "java/res/values/styles.xml",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_modern.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory.xml
similarity index 96%
rename from chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_modern.xml
rename to chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory.xml
index beb38b59..2475952e 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_modern.xml
+++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory.xml
@@ -5,7 +5,7 @@
 found in the LICENSE file.
 -->
 
-<org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryModernView
+<org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/keyboard_accessory"
@@ -47,4 +47,4 @@
 
     </LinearLayout>
 
-</org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryModernView>
+</org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryView>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_action_modern.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_action.xml
similarity index 100%
rename from chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_action_modern.xml
rename to chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_action.xml
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml
deleted file mode 100644
index ecbbcfe..0000000
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:gravity="center_vertical|start"
-    android:fillViewport="true"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:orientation="vertical">
-
-    <TextView
-        android:id="@+id/suggestion_text"
-        android:gravity="center_vertical|start"
-        android:fillViewport="true"
-        android:minHeight="@dimen/keyboard_accessory_suggestion_height"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
-
-    <TextView
-        android:id="@+id/password_text"
-        android:gravity="center_vertical|start"
-        android:fillViewport="true"
-        android:minHeight="@dimen/keyboard_accessory_suggestion_height"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
-
-</LinearLayout>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_label.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_label.xml
deleted file mode 100644
index 4a31d47..0000000
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_label.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:gravity="center_vertical|start"
-    android:fillViewport="true"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:orientation="vertical">
-
-    <View style="@style/HorizontalDivider"
-        android:layout_marginTop="0dp"
-        android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding" />
-
-    <org.chromium.ui.widget.TextViewWithLeading
-        android:id="@+id/tab_title"
-        android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
-        android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
-        android:paddingTop="@dimen/keyboard_accessory_suggestion_offset"
-        android:paddingBottom="@dimen/keyboard_accessory_suggestion_offset"
-        android:gravity="center_vertical|start"
-        android:textAppearance="@style/TextAppearance.TextLarge.Secondary"
-        android:minHeight="@dimen/keyboard_accessory_height"
-        app:leading="@dimen/text_size_large_leading"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_legacy_option.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_legacy_option.xml
deleted file mode 100644
index cce940bf..0000000
--- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/password_accessory_sheet_legacy_option.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/footer_command"
-    android:gravity="center_vertical|start"
-    android:fillViewport="true"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:paddingTop="0dp"
-    android:paddingBottom="0dp"
-    android:orientation="vertical">
-
-    <TextView
-        android:id="@+id/footer_text"
-        android:paddingStart="@dimen/keyboard_accessory_suggestion_padding"
-        android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding"
-        android:fillViewport="true"
-        android:minHeight="@dimen/keyboard_accessory_suggestion_height"
-        android:gravity="center_vertical|start"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:background="?android:attr/selectableItemBackground"/>
-
-</LinearLayout>
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
index 32ac3b1..3ff82d4 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
@@ -48,7 +48,7 @@
             AsyncViewStub barStub) {
         if (barStub == null || sheetStub == null) return; // The manual filling isn't needed.
         // TODO(crbug.com/1448820): Initialize in the xml resources file.
-        barStub.setLayoutResource(R.layout.keyboard_accessory_modern);
+        barStub.setLayoutResource(R.layout.keyboard_accessory);
         sheetStub.setLayoutResource(R.layout.keyboard_accessory_sheet);
         barStub.setShouldInflateOnBackgroundThread(true);
         sheetStub.setShouldInflateOnBackgroundThread(true);
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
index cc638544..48d4110 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -15,8 +15,8 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType;
 import org.chromium.chrome.browser.keyboard_accessory.R;
-import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryModernViewBinder.BarItemViewHolder;
 import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem;
+import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryViewBinder.BarItemViewHolder;
 import org.chromium.chrome.browser.keyboard_accessory.button_group_component.KeyboardAccessoryButtonGroupCoordinator;
 import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
 import org.chromium.chrome.browser.keyboard_accessory.data.Provider;
@@ -40,7 +40,7 @@
     private final KeyboardAccessoryMediator mMediator;
     private final KeyboardAccessoryButtonGroupCoordinator mButtonGroup;
     private final PropertyModel mModel;
-    private KeyboardAccessoryModernView mView;
+    private KeyboardAccessoryView mView;
 
     /**
      * The interface to notify consumers about keyboard accessories visibility. E.g: the animation
@@ -133,7 +133,7 @@
             KeyboardAccessoryButtonGroupCoordinator buttonGroup,
             BarVisibilityDelegate barVisibilityDelegate,
             AccessorySheetCoordinator.SheetVisibilityDelegate sheetVisibilityDelegate,
-            ViewProvider<KeyboardAccessoryModernView> viewProvider) {
+            ViewProvider<KeyboardAccessoryView> viewProvider) {
         mButtonGroup = buttonGroup;
         mModel = KeyboardAccessoryProperties.defaultModelBuilder().build();
         mMediator =
@@ -147,7 +147,7 @@
 
         mButtonGroup.setTabObserver(mMediator);
         LazyConstructionPropertyMcp.create(
-                mModel, VISIBLE, viewProvider, KeyboardAccessoryModernViewBinder::bind);
+                mModel, VISIBLE, viewProvider, KeyboardAccessoryViewBinder::bind);
         KeyboardAccessoryMetricsRecorder.registerKeyboardAccessoryModelMetricsObserver(mModel);
     }
 
@@ -165,7 +165,7 @@
                         BarItem::getViewType,
                         BarItemViewHolder::bind,
                         BarItemViewHolder::recycle),
-                KeyboardAccessoryModernViewBinder::create);
+                KeyboardAccessoryViewBinder::create);
     }
 
     public void closeActiveTab() {
@@ -234,7 +234,7 @@
         // TODO(fhorschig): Consider allow LazyConstructionPropertyMcp to propagate updates once the
         // view exists. Currently it doesn't, so we need this ugly explicit binding.
         if (mView != null) {
-            KeyboardAccessoryModernViewBinder.bind(mModel, mView, SKIP_CLOSING_ANIMATION);
+            KeyboardAccessoryViewBinder.bind(mModel, mView, SKIP_CLOSING_ANIMATION);
         }
     }
 
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
index c43129a..04e21332 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryProperties.java
@@ -51,7 +51,7 @@
     static final WritableBooleanPropertyKey HAS_SUGGESTIONS =
             new WritableBooleanPropertyKey("has_suggestions");
 
-    static final WritableObjectPropertyKey<KeyboardAccessoryModernView.AnimationListener>
+    static final WritableObjectPropertyKey<KeyboardAccessoryView.AnimationListener>
             ANIMATION_LISTENER = new WritableObjectPropertyKey<>("animation_listener");
 
     static PropertyModel.Builder defaultModelBuilder() {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
similarity index 98%
rename from chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java
rename to chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
index 6144e6df..0909cbfe 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernView.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryView.java
@@ -34,7 +34,7 @@
  * The Accessory sitting above the keyboard and below the content area. It is used for autofill
  * suggestions and manual entry points assisting the user in filling forms.
  */
-class KeyboardAccessoryModernView extends LinearLayout {
+class KeyboardAccessoryView extends LinearLayout {
     private static final int ARRIVAL_ANIMATION_DURATION_MS = 300;
     private static final float ARRIVAL_ANIMATION_BOUNCE_LENGTH_DIP = 200f;
     private static final float ARRIVAL_ANIMATION_TENSION = 1f;
@@ -153,7 +153,7 @@
     }
 
     /** Constructor for inflating from XML. */
-    public KeyboardAccessoryModernView(Context context, AttributeSet attrs) {
+    public KeyboardAccessoryView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
similarity index 97%
rename from chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
rename to chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
index 14a8421eb..e3a55e9 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewBinder.java
@@ -47,7 +47,7 @@
  * Observes {@link KeyboardAccessoryProperties} changes (like a newly available tab) and modifies
  * the view accordingly.
  */
-class KeyboardAccessoryModernViewBinder {
+class KeyboardAccessoryViewBinder {
     static BarItemViewHolder create(ViewGroup parent, @BarItem.Type int viewType) {
         switch (viewType) {
             case BarItem.Type.SUGGESTION:
@@ -55,7 +55,7 @@
             case BarItem.Type.TAB_LAYOUT:
                 return new SheetOpenerViewHolder(parent);
             case BarItem.Type.ACTION_BUTTON:
-                return new BarItemTextViewHolder(parent, R.layout.keyboard_accessory_action_modern);
+                return new BarItemTextViewHolder(parent, R.layout.keyboard_accessory_action);
             case BarItem.Type.ACTION_CHIP:
                 return new BarItemActionChipViewHolder(parent);
         }
@@ -241,11 +241,10 @@
      * Tries to bind the given property to the given view by using the value in the given model.
      *
      * @param model A {@link PropertyModel}.
-     * @param view A {@link KeyboardAccessoryModernView}.
+     * @param view A {@link KeyboardAccessoryView}.
      * @param propertyKey A {@link PropertyKey}.
      */
-    static void bind(
-            PropertyModel model, KeyboardAccessoryModernView view, PropertyKey propertyKey) {
+    static void bind(PropertyModel model, KeyboardAccessoryView view, PropertyKey propertyKey) {
         if (propertyKey == BAR_ITEMS) {
             view.setBarItemsAdapter(
                     KeyboardAccessoryCoordinator.createBarItemsAdapter(model.get(BAR_ITEMS)));
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupView.java
index 462a2c85..640bd9a 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupView.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupView.java
@@ -78,7 +78,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        // The parent, which is KeyboardAccessoryModernView's recycler view may measure
+        // The parent, which is KeyboardAccessoryView's recycler view may measure
         // StickyLastItemDecoration offsets before the buttons are added. Notify the parent to
         // recalculate the offset during each measurement.
         // TODO(crbug.com/1424789): Find a better alternative.
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetCoordinator.java
index 600f10f..3e59b37c 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetCoordinator.java
@@ -56,8 +56,7 @@
     @Override
     public void onTabCreated(ViewGroup view) {
         super.onTabCreated(view);
-        PasswordAccessorySheetModernViewBinder.initializeView(
-                (RecyclerView) view, mModel.get(ITEMS));
+        PasswordAccessorySheetViewBinder.initializeView((RecyclerView) view, mModel.get(ITEMS));
     }
 
     @Override
@@ -73,13 +72,14 @@
     }
 
     /**
-     * Creates an adapter to an {@link PasswordAccessorySheetViewBinder} that is wired
-     * up to a model change processor listening to the {@link AccessorySheetTabItemsModel}.
+     * Creates an adapter to an {@link PasswordAccessorySheetViewBinder} that is wired up to the
+     * model change processor which listens to the {@link AccessorySheetTabItemsModel}.
+     *
      * @param model the {@link AccessorySheetTabItemsModel} the adapter gets its data from.
-     * @return Returns a fully initialized and wired adapter to a PasswordAccessorySheetViewBinder.
+     * @return Returns an {@link PasswordAccessorySheetViewBinder} wired to a MCP.
      */
     static RecyclerViewAdapter<AccessorySheetTabViewBinder.ElementViewHolder, Void> createAdapter(
-            AccessorySheetTabItemsModel model) {
+            ListModel<AccessorySheetDataPiece> model) {
         return new RecyclerViewAdapter<>(
                 new SimpleRecyclerViewMcp<>(
                         model,
@@ -87,20 +87,4 @@
                         AccessorySheetTabViewBinder.ElementViewHolder::bind),
                 PasswordAccessorySheetViewBinder::create);
     }
-
-    /**
-     * Creates an adapter to an {@link PasswordAccessorySheetModernViewBinder} that is wired up to
-     * the model change processor which listens to the {@link AccessorySheetTabItemsModel}.
-     * @param model the {@link AccessorySheetTabItemsModel} the adapter gets its data from.
-     * @return Returns an {@link PasswordAccessorySheetModernViewBinder} wired to a MCP.
-     */
-    static RecyclerViewAdapter<AccessorySheetTabViewBinder.ElementViewHolder, Void>
-            createModernAdapter(ListModel<AccessorySheetDataPiece> model) {
-        return new RecyclerViewAdapter<>(
-                new SimpleRecyclerViewMcp<>(
-                        model,
-                        AccessorySheetDataPiece::getType,
-                        AccessorySheetTabViewBinder.ElementViewHolder::bind),
-                PasswordAccessorySheetModernViewBinder::create);
-    }
 }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewBinder.java
deleted file mode 100644
index 145cc9a8..0000000
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewBinder.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2018 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.keyboard_accessory.sheet_tabs;
-
-import static org.chromium.components.embedder_support.util.UrlUtilities.stripScheme;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.text.method.PasswordTransformationMethod;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import org.chromium.chrome.browser.keyboard_accessory.R;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
-import org.chromium.chrome.browser.keyboard_accessory.data.UserInfoField;
-import org.chromium.chrome.browser.keyboard_accessory.helper.FaviconHelper;
-import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabItemsModel.AccessorySheetDataPiece;
-import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabViewBinder.ElementViewHolder;
-import org.chromium.chrome.browser.keyboard_accessory.utils.InsecureFillingDialogUtils;
-import org.chromium.components.browser_ui.widget.chips.ChipView;
-import org.chromium.ui.modelutil.ListModel;
-
-/**
- * This stateless class provides methods to bind a {@link ListModel<AccessorySheetDataPiece>}
- * to the {@link RecyclerView} used as view of a tab for the accessory sheet component.
- */
-class PasswordAccessorySheetModernViewBinder {
-    static ElementViewHolder create(ViewGroup parent, @AccessorySheetDataPiece.Type int viewType) {
-        switch (viewType) {
-            case AccessorySheetDataPiece.Type.PASSKEY_SECTION:
-                return new PasskeyChipViewHolder(parent);
-            case AccessorySheetDataPiece.Type.PASSWORD_INFO:
-                return new PasswordInfoViewHolder(parent);
-            case AccessorySheetDataPiece.Type.TITLE:
-                return new AccessorySheetTabViewBinder.TitleViewHolder(
-                        parent, R.layout.keyboard_accessory_sheet_tab_title);
-            case AccessorySheetDataPiece.Type.FOOTER_COMMAND:
-            case AccessorySheetDataPiece.Type.OPTION_TOGGLE:
-                return AccessorySheetTabViewBinder.create(parent, viewType);
-        }
-        assert false : "Unhandled type of data piece: " + viewType;
-        return null;
-    }
-
-    /** Holds a clickable {@link ChipView} that represents a Passkey. */
-    static class PasskeyChipViewHolder
-            extends ElementViewHolder<KeyboardAccessoryData.PasskeySection, ViewGroup> {
-        PasskeyChipViewHolder(ViewGroup parent) {
-            super(parent, R.layout.password_accessory_passkey_chip);
-        }
-
-        @Override
-        protected void bind(KeyboardAccessoryData.PasskeySection passkeySection, ViewGroup view) {
-            ChipView chip = view.findViewById(R.id.keyboard_accessory_sheet_chip);
-            chip.getPrimaryTextView().setText(passkeySection.getDisplayName());
-            chip.getPrimaryTextView().setContentDescription(passkeySection.getDisplayName());
-            chip.getSecondaryTextView().setText(R.string.password_accessory_passkey_label);
-            chip.setOnClickListener((unused) -> passkeySection.triggerSelection());
-        }
-    }
-
-    /** Holds a TextView that represents a list entry. */
-    static class PasswordInfoViewHolder
-            extends ElementViewHolder<KeyboardAccessoryData.UserInfo, PasswordAccessoryInfoView> {
-        String mFaviconRequestOrigin;
-
-        PasswordInfoViewHolder(ViewGroup parent) {
-            super(parent, R.layout.keyboard_accessory_sheet_tab_password_info);
-        }
-
-        @Override
-        protected void bind(KeyboardAccessoryData.UserInfo info, PasswordAccessoryInfoView view) {
-            bindChipView(view.getUsername(), info.getFields().get(0), view.getContext());
-            bindChipView(view.getPassword(), info.getFields().get(1), view.getContext());
-
-            view.getTitle().setVisibility(info.isExactMatch() ? View.GONE : View.VISIBLE);
-            // Strip the trailing slash (for aesthetic reasons):
-            view.getTitle().setText(stripScheme(info.getOrigin()).replaceFirst("/$", ""));
-
-            // Set the default icon, then try to get a better one.
-            mFaviconRequestOrigin = info.getOrigin(); // Save the origin for returning callback.
-            FaviconHelper faviconHelper = FaviconHelper.create(view.getContext());
-            view.setIconForBitmap(faviconHelper.getDefaultIcon(info.getOrigin()));
-            faviconHelper.fetchFavicon(info.getOrigin(), d -> setIcon(view, info.getOrigin(), d));
-        }
-
-        private void setIcon(
-                PasswordAccessoryInfoView view, String requestOrigin, Drawable drawable) {
-            // Only set the icon if the origin hasn't changed since this view last requested an
-            // icon. Since the Views are recycled, an old callback can target a new view.
-            if (requestOrigin.equals(mFaviconRequestOrigin)) view.setIconForBitmap(drawable);
-        }
-
-        void bindChipView(ChipView chip, UserInfoField field, Context context) {
-            chip.getPrimaryTextView()
-                    .setTransformationMethod(
-                            field.isObfuscated() ? new PasswordTransformationMethod() : null);
-            chip.getPrimaryTextView().setText(field.getDisplayText());
-            chip.getPrimaryTextView().setContentDescription(field.getA11yDescription());
-            View.OnClickListener listener = null;
-            if (field.isSelectable()) {
-                listener = src -> field.triggerSelection();
-            } else if (field.isObfuscated()) {
-                listener = src -> InsecureFillingDialogUtils.showWarningDialog(context);
-            }
-            chip.setOnClickListener(listener);
-            chip.setClickable(listener != null);
-            chip.setEnabled(listener != null);
-        }
-    }
-
-    static void initializeView(RecyclerView view, AccessorySheetTabItemsModel model) {
-        view.setAdapter(PasswordAccessorySheetCoordinator.createModernAdapter(model));
-        view.addItemDecoration(new DynamicInfoViewBottomSpacer(PasswordAccessoryInfoView.class));
-    }
-}
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewBinder.java
index 014efd5..9dee9f9 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewBinder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewBinder.java
@@ -4,206 +4,117 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.sheet_tabs;
 
-import static org.chromium.ui.base.LocalizationUtils.isLayoutRtl;
+import static org.chromium.components.embedder_support.util.UrlUtilities.stripScheme;
 
 import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.text.method.PasswordTransformationMethod;
-import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 
-import androidx.annotation.Nullable;
-import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.chrome.browser.keyboard_accessory.R;
 import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.FooterCommand;
 import org.chromium.chrome.browser.keyboard_accessory.data.UserInfoField;
 import org.chromium.chrome.browser.keyboard_accessory.helper.FaviconHelper;
 import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabItemsModel.AccessorySheetDataPiece;
 import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabViewBinder.ElementViewHolder;
-import org.chromium.ui.HorizontalListDividerDrawable;
+import org.chromium.chrome.browser.keyboard_accessory.utils.InsecureFillingDialogUtils;
+import org.chromium.components.browser_ui.widget.chips.ChipView;
 import org.chromium.ui.modelutil.ListModel;
 
 /**
- * This stateless class provides methods to bind the items in a {@link ListModel <Item>}
- * to the {@link RecyclerView} used as view of the Password accessory sheet component.
+ * This stateless class provides methods to bind a {@link ListModel<AccessorySheetDataPiece>}
+ * to the {@link RecyclerView} used as view of a tab for the accessory sheet component.
  */
 class PasswordAccessorySheetViewBinder {
     static ElementViewHolder create(ViewGroup parent, @AccessorySheetDataPiece.Type int viewType) {
         switch (viewType) {
-            case AccessorySheetDataPiece.Type.TITLE:
-                return new PasswordsTitleViewHolder(parent);
+            case AccessorySheetDataPiece.Type.PASSKEY_SECTION:
+                return new PasskeyChipViewHolder(parent);
             case AccessorySheetDataPiece.Type.PASSWORD_INFO:
-                return new PasswordsInfoViewHolder(parent);
+                return new PasswordInfoViewHolder(parent);
+            case AccessorySheetDataPiece.Type.TITLE:
+                return new AccessorySheetTabViewBinder.TitleViewHolder(
+                        parent, R.layout.keyboard_accessory_sheet_tab_title);
             case AccessorySheetDataPiece.Type.FOOTER_COMMAND:
-                return new FooterCommandViewHolder(parent);
+            case AccessorySheetDataPiece.Type.OPTION_TOGGLE:
+                return AccessorySheetTabViewBinder.create(parent, viewType);
         }
         assert false : "Unhandled type of data piece: " + viewType;
         return null;
     }
 
-    /** Holds a the TextView with the title of the sheet and a divider for the accessory bar. */
-    static class PasswordsTitleViewHolder extends ElementViewHolder<String, LinearLayout> {
-        PasswordsTitleViewHolder(ViewGroup parent) {
-            super(parent, R.layout.password_accessory_sheet_label);
+    /** Holds a clickable {@link ChipView} that represents a Passkey. */
+    static class PasskeyChipViewHolder
+            extends ElementViewHolder<KeyboardAccessoryData.PasskeySection, ViewGroup> {
+        PasskeyChipViewHolder(ViewGroup parent) {
+            super(parent, R.layout.password_accessory_passkey_chip);
         }
 
         @Override
-        protected void bind(String displayText, LinearLayout view) {
-            TextView titleView = view.findViewById(R.id.tab_title);
-            titleView.setText(displayText);
-            titleView.setContentDescription(displayText);
+        protected void bind(KeyboardAccessoryData.PasskeySection passkeySection, ViewGroup view) {
+            ChipView chip = view.findViewById(R.id.keyboard_accessory_sheet_chip);
+            chip.getPrimaryTextView().setText(passkeySection.getDisplayName());
+            chip.getPrimaryTextView().setContentDescription(passkeySection.getDisplayName());
+            chip.getSecondaryTextView().setText(R.string.password_accessory_passkey_label);
+            chip.setOnClickListener((unused) -> passkeySection.triggerSelection());
         }
     }
 
-    /**
-     * Holds a TextView that represents a bottom command and is separated to the top by a divider.
-     */
-    static class FooterCommandViewHolder extends ElementViewHolder<FooterCommand, LinearLayout> {
-        public static class DynamicTopDivider extends RecyclerView.ItemDecoration {
-            private final int mAccessoryPadding;
-            private final int mDividerHeight;
+    /** Holds a TextView that represents a list entry. */
+    static class PasswordInfoViewHolder
+            extends ElementViewHolder<KeyboardAccessoryData.UserInfo, PasswordAccessoryInfoView> {
+        String mFaviconRequestOrigin;
 
-            DynamicTopDivider(Context context) {
-                var resources = context.getResources();
-                mAccessoryPadding =
-                        resources.getDimensionPixelOffset(
-                                R.dimen.keyboard_accessory_suggestion_padding);
-                mDividerHeight = resources.getDimensionPixelSize(R.dimen.divider_height);
-            }
-
-            @Override
-            public void getItemOffsets(
-                    Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
-                super.getItemOffsets(outRect, view, parent, state);
-                if (view.getId() != R.id.footer_command) return;
-                int previous = parent.indexOfChild(view) - 1;
-                if (previous < 0) return;
-                if (parent.getChildAt(previous).getId() == R.id.footer_command) return;
-                outRect.top = mAccessoryPadding + mDividerHeight;
-            }
-
-            @Override
-            public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
-                int attatchedChlidCount = parent.getChildCount();
-                int halfHeight = mAccessoryPadding / 2;
-                for (int i = 0; i < attatchedChlidCount - 1; ++i) {
-                    View currentView = parent.getChildAt(i);
-                    if (currentView.getId() == R.id.footer_command) break;
-
-                    View nextView = parent.getChildAt(i + 1);
-                    if (nextView.getId() != R.id.footer_command) continue;
-
-                    Drawable dividerDrawable =
-                            HorizontalListDividerDrawable.create(nextView.getContext());
-                    int top = currentView.getBottom() + halfHeight;
-                    int bottom = top + dividerDrawable.getIntrinsicHeight();
-                    dividerDrawable.setBounds(
-                            parent.getLeft() + parent.getPaddingLeft(),
-                            top,
-                            parent.getRight() - parent.getPaddingRight(),
-                            bottom);
-
-                    dividerDrawable.draw(canvas);
-                }
-            }
-        }
-
-        FooterCommandViewHolder(ViewGroup parent) {
-            super(parent, R.layout.password_accessory_sheet_legacy_option);
+        PasswordInfoViewHolder(ViewGroup parent) {
+            super(parent, R.layout.keyboard_accessory_sheet_tab_password_info);
         }
 
         @Override
-        protected void bind(FooterCommand footerCommand, LinearLayout layout) {
-            TextView view = layout.findViewById(R.id.footer_text);
-            view.setText(footerCommand.getDisplayText());
-            view.setContentDescription(footerCommand.getDisplayText());
-            view.setOnClickListener(v -> footerCommand.execute());
-            view.setClickable(true);
-        }
-    }
+        protected void bind(KeyboardAccessoryData.UserInfo info, PasswordAccessoryInfoView view) {
+            bindChipView(view.getUsername(), info.getFields().get(0), view.getContext());
+            bindChipView(view.getPassword(), info.getFields().get(1), view.getContext());
 
-    /** Holds a layout for a username and a password with a small icon. */
-    static class PasswordsInfoViewHolder
-            extends ElementViewHolder<KeyboardAccessoryData.UserInfo, LinearLayout> {
-        private final int mPadding;
-        private final int mIconSize;
+            view.getTitle().setVisibility(info.isExactMatch() ? View.GONE : View.VISIBLE);
+            // Strip the trailing slash (for aesthetic reasons):
+            view.getTitle().setText(stripScheme(info.getOrigin()).replaceFirst("/$", ""));
 
-        PasswordsInfoViewHolder(ViewGroup parent) {
-            super(parent, R.layout.keyboard_accessory_sheet_tab_legacy_password_info);
-            mPadding =
-                    itemView.getContext()
-                            .getResources()
-                            .getDimensionPixelSize(R.dimen.keyboard_accessory_suggestion_padding);
-            mIconSize =
-                    itemView.getContext()
-                            .getResources()
-                            .getDimensionPixelSize(R.dimen.keyboard_accessory_suggestion_icon_size);
+            // Set the default icon, then try to get a better one.
+            mFaviconRequestOrigin = info.getOrigin(); // Save the origin for returning callback.
+            FaviconHelper faviconHelper = FaviconHelper.create(view.getContext());
+            view.setIconForBitmap(faviconHelper.getDefaultIcon(info.getOrigin()));
+            faviconHelper.fetchFavicon(info.getOrigin(), d -> setIcon(view, info.getOrigin(), d));
         }
 
-        @Override
-        protected void bind(KeyboardAccessoryData.UserInfo info, LinearLayout layout) {
-            TextView username = layout.findViewById(R.id.suggestion_text);
-            TextView password = layout.findViewById(R.id.password_text);
-            bindTextView(username, info.getFields().get(0));
-            bindTextView(password, info.getFields().get(1));
-
-            // Set the default icon for username, then try to get a better one.
-            FaviconHelper faviconHelper = FaviconHelper.create(username.getContext());
-            setIconForBitmap(username, faviconHelper.getDefaultIcon(info.getOrigin()));
-            faviconHelper.fetchFavicon(info.getOrigin(), icon -> setIconForBitmap(username, icon));
-
-            ViewCompat.setPaddingRelative(username, mPadding, 0, mPadding, 0);
-            // Passwords have no icon, so increase the offset.
-            ViewCompat.setPaddingRelative(password, 2 * mPadding + mIconSize, 0, mPadding, 0);
+        private void setIcon(
+                PasswordAccessoryInfoView view, String requestOrigin, Drawable drawable) {
+            // Only set the icon if the origin hasn't changed since this view last requested an
+            // icon. Since the Views are recycled, an old callback can target a new view.
+            if (requestOrigin.equals(mFaviconRequestOrigin)) view.setIconForBitmap(drawable);
         }
 
-        private void bindTextView(TextView text, UserInfoField field) {
-            text.setTransformationMethod(
-                    field.isObfuscated() ? new PasswordTransformationMethod() : null);
-            // With transformation, the character set forces a LTR gravity. Therefore, invert it:
-            text.setGravity(
-                    Gravity.CENTER_VERTICAL
-                            | (isLayoutRtl() && field.isObfuscated()
-                                    ? Gravity.END
-                                    : Gravity.START));
-            text.setText(field.getDisplayText());
-            text.setContentDescription(field.getA11yDescription());
-            text.setOnClickListener(!field.isSelectable() ? null : src -> field.triggerSelection());
-            text.setClickable(true); // Ensures that "disabled" is announced.
-            text.setEnabled(field.isSelectable());
-            text.setBackground(getBackgroundDrawable(field.isSelectable()));
-        }
-
-        private @Nullable Drawable getBackgroundDrawable(boolean selectable) {
-            if (!selectable) return null;
-            TypedArray a =
-                    itemView.getContext()
-                            .obtainStyledAttributes(new int[] {R.attr.selectableItemBackground});
-            Drawable suggestionBackground = a.getDrawable(0);
-            a.recycle();
-            return suggestionBackground;
-        }
-
-        private void setIconForBitmap(TextView text, @Nullable Drawable icon) {
-            if (icon != null) {
-                icon.setBounds(0, 0, mIconSize, mIconSize);
+        void bindChipView(ChipView chip, UserInfoField field, Context context) {
+            chip.getPrimaryTextView()
+                    .setTransformationMethod(
+                            field.isObfuscated() ? new PasswordTransformationMethod() : null);
+            chip.getPrimaryTextView().setText(field.getDisplayText());
+            chip.getPrimaryTextView().setContentDescription(field.getA11yDescription());
+            View.OnClickListener listener = null;
+            if (field.isSelectable()) {
+                listener = src -> field.triggerSelection();
+            } else if (field.isObfuscated()) {
+                listener = src -> InsecureFillingDialogUtils.showWarningDialog(context);
             }
-            text.setCompoundDrawablePadding(mPadding);
-            text.setCompoundDrawablesRelative(icon, null, null, null);
+            chip.setOnClickListener(listener);
+            chip.setClickable(listener != null);
+            chip.setEnabled(listener != null);
         }
     }
 
     static void initializeView(RecyclerView view, AccessorySheetTabItemsModel model) {
         view.setAdapter(PasswordAccessorySheetCoordinator.createAdapter(model));
-        view.addItemDecoration(new FooterCommandViewHolder.DynamicTopDivider(view.getContext()));
+        view.addItemDecoration(new DynamicInfoViewBottomSpacer(PasswordAccessoryInfoView.class));
     }
 }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingUiCaptureTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingUiCaptureTest.java
index 5bd00c2..882af81 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingUiCaptureTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingUiCaptureTest.java
@@ -55,7 +55,7 @@
 
     @Test
     @MediumTest
-    @Feature({"KeyboardAccessoryModern", "LTR", "UiCatalogue"})
+    @Feature({"KeyboardAccessory", "LTR", "UiCatalogue"})
     public void testCaptureKeyboardAccessoryV2WithPasswords()
             throws InterruptedException, TimeoutException {
         mHelper.loadTestPage(false);
@@ -87,7 +87,7 @@
 
     @Test
     @MediumTest
-    @Feature({"KeyboardAccessoryModern", "RTL", "UiCatalogue"})
+    @Feature({"KeyboardAccessory", "RTL", "UiCatalogue"})
     public void testCaptureKeyboardAccessoryV2WithPasswordsRTL()
             throws InterruptedException, TimeoutException {
         mHelper.loadTestPage(true);
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
index 3141e9e..2a70bfd2 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryTestHelper.java
@@ -43,7 +43,7 @@
      * @return True iff the bar view is visible and animations have ended.
      */
     public static boolean accessoryViewFullyShown(Activity activity) {
-        KeyboardAccessoryModernView accessory = activity.findViewById(R.id.keyboard_accessory);
+        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
         return accessory != null
                 && accessory.isShown()
                 && !accessory.hasRunningAnimation()
@@ -73,7 +73,7 @@
      * @return True iff the bar view is hidden and animations have ended.
      */
     public static boolean accessoryViewFullyHidden(Activity activity) {
-        KeyboardAccessoryModernView accessory = activity.findViewById(R.id.keyboard_accessory);
+        KeyboardAccessoryView accessory = activity.findViewById(R.id.keyboard_accessory);
         return accessory == null || (!accessory.isShown() && !accessory.hasRunningAnimation());
     }
 }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
similarity index 97%
rename from chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
rename to chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
index a433787..9d93a09 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryViewTest.java
@@ -110,12 +110,12 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @SuppressWarnings("DoNotMock") // Mocks GURL
-public class KeyboardAccessoryModernViewTest {
+public class KeyboardAccessoryViewTest {
     private static final String CUSTOM_ICON_URL = "https://www.example.com/image.png";
     private static final Bitmap TEST_CARD_ART_IMAGE =
             Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
     private PropertyModel mModel;
-    private BlockingQueue<KeyboardAccessoryModernView> mKeyboardAccessoryView;
+    private BlockingQueue<KeyboardAccessoryView> mKeyboardAccessoryView;
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@@ -236,10 +236,10 @@
                                     .findViewById(R.id.keyboard_accessory_stub);
 
                     mKeyboardAccessoryView = new ArrayBlockingQueue<>(1);
-                    ViewProvider<KeyboardAccessoryModernView> provider =
+                    ViewProvider<KeyboardAccessoryView> provider =
                             AsyncViewProvider.of(viewStub, R.id.keyboard_accessory);
                     LazyConstructionPropertyMcp.create(
-                            mModel, VISIBLE, provider, KeyboardAccessoryModernViewBinder::bind);
+                            mModel, VISIBLE, provider, KeyboardAccessoryViewBinder::bind);
                     provider.whenLoaded(mKeyboardAccessoryView::add);
                 });
     }
@@ -255,7 +255,7 @@
                 () -> {
                     mModel.set(VISIBLE, true);
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
         assertEquals(view.getVisibility(), View.VISIBLE);
 
         // After hiding the view, the view should still exist but be invisible.
@@ -391,7 +391,7 @@
                     mModel.set(VISIBLE, true);
                     mModel.get(BAR_ITEMS).set(createAutofillChipAndTab("John", null));
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
         CriteriaHelper.pollUiThread(
                 () -> view.mBarItemsView.isShown() && view.mBarItemsView.getChildAt(1) != null);
         CriteriaHelper.pollUiThread(viewsAreRightAligned(view, view.mBarItemsView.getChildAt(1)));
@@ -592,7 +592,7 @@
                     mModel.set(VISIBLE, true);
                     mModel.get(BAR_ITEMS).set(createAutofillChipAndTab("John", null));
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
         CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
         assertThat(obfuscatedChildAt.get(), is(-1));
 
@@ -641,7 +641,7 @@
                     mModel.set(VISIBLE, true);
                     mModel.get(BAR_ITEMS).set(new BarItem[] {customIconItem, createSheetOpener()});
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
 
         CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
         CriteriaHelper.pollUiThread(
@@ -677,7 +677,7 @@
                     mModel.set(VISIBLE, true);
                     mModel.get(BAR_ITEMS).set(new BarItem[] {customIconItem, createSheetOpener()});
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
 
         CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
         CriteriaHelper.pollUiThread(
@@ -705,7 +705,7 @@
                     mModel.get(BAR_ITEMS)
                             .set(new BarItem[] {itemWithoutCustomIconUrl, createSheetOpener()});
                 });
-        KeyboardAccessoryModernView view = mKeyboardAccessoryView.take();
+        KeyboardAccessoryView view = mKeyboardAccessoryView.take();
 
         CriteriaHelper.pollUiThread(() -> view.mBarItemsView.getChildCount() > 0);
         CriteriaHelper.pollUiThread(
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
deleted file mode 100644
index 3a232fc..0000000
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright 2018 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.keyboard_accessory.sheet_tabs;
-
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.matcher.RootMatchers.isDialog;
-import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
-import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.text.method.PasswordTransformationMethod;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.StringRes;
-import androidx.appcompat.widget.SwitchCompat;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.test.filters.MediumTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Criteria;
-import org.chromium.base.test.util.CriteriaHelper;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.keyboard_accessory.AccessoryAction;
-import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType;
-import org.chromium.chrome.browser.keyboard_accessory.R;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.OptionToggle;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.PasskeySection;
-import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.UserInfo;
-import org.chromium.chrome.browser.keyboard_accessory.data.UserInfoField;
-import org.chromium.chrome.browser.keyboard_accessory.sheet_component.AccessorySheetCoordinator;
-import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabItemsModel.AccessorySheetDataPiece;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.components.browser_ui.widget.chips.ChipView;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/** View tests for the password accessory sheet. */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PasswordAccessorySheetModernViewTest {
-    private AccessorySheetTabItemsModel mModel;
-    private AtomicReference<RecyclerView> mView = new AtomicReference<>();
-
-    @Rule
-    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
-
-    @Before
-    public void setUp() throws InterruptedException {
-        mActivityTestRule.startMainActivityOnBlankPage();
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    mModel = new AccessorySheetTabItemsModel();
-
-                    AccessorySheetCoordinator accessorySheet =
-                            new AccessorySheetCoordinator(
-                                    mActivityTestRule
-                                            .getActivity()
-                                            .findViewById(R.id.keyboard_accessory_sheet_stub),
-                                    null);
-                    accessorySheet.setTabs(
-                            new KeyboardAccessoryData.Tab[] {
-                                new KeyboardAccessoryData.Tab(
-                                        "Passwords",
-                                        null,
-                                        null,
-                                        R.layout.password_accessory_sheet,
-                                        AccessoryTabType.ALL,
-                                        new KeyboardAccessoryData.Tab.Listener() {
-                                            @Override
-                                            public void onTabCreated(ViewGroup view) {
-                                                mView.set((RecyclerView) view);
-                                                AccessorySheetTabViewBinder.initializeView(
-                                                        mView.get(), null);
-                                                PasswordAccessorySheetModernViewBinder
-                                                        .initializeView(mView.get(), mModel);
-                                            }
-
-                                            @Override
-                                            public void onTabShown() {}
-                                        })
-                            });
-                    accessorySheet.setHeight(
-                            mActivityTestRule
-                                    .getActivity()
-                                    .getResources()
-                                    .getDimensionPixelSize(
-                                            R.dimen.keyboard_accessory_sheet_height));
-                    accessorySheet.show();
-                });
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get(), notNullValue()));
-    }
-
-    @After
-    public void tearDown() {
-        mView.set(null);
-    }
-
-    @Test
-    @MediumTest
-    public void testAddingCaptionsToTheModelRendersThem() {
-        assertThat(mView.get().getChildCount(), is(0));
-
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    "Passwords", AccessorySheetDataPiece.Type.TITLE));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-        View title = mView.get().findViewById(R.id.tab_title);
-        assertThat(title, is(not(nullValue())));
-        assertThat(title, instanceOf(TextView.class));
-        assertThat(((TextView) title).getText(), is("Passwords"));
-    }
-
-    @Test
-    @MediumTest
-    public void testAddingUserInfoToTheModelRendersClickableActions() throws ExecutionException {
-        final AtomicReference<Boolean> clicked = new AtomicReference<>(false);
-        assertThat(mView.get().getChildCount(), is(0));
-
-        UserInfo testInfo = new UserInfo("", false);
-        testInfo.addField(
-                new UserInfoField(
-                        "Name Suggestion",
-                        "Name Suggestion",
-                        "",
-                        false,
-                        item -> clicked.set(true)));
-        testInfo.addField(
-                new UserInfoField(
-                        "Password Suggestion",
-                        "Password Suggestion",
-                        "",
-                        true,
-                        item -> clicked.set(true)));
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    testInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-
-        assertThat(getNameSuggestion().getPrimaryTextView().getText(), is("Name Suggestion"));
-        assertThat(
-                getPasswordSuggestion().getPrimaryTextView().getText(), is("Password Suggestion"));
-        assertThat(
-                getPasswordSuggestion().getPrimaryTextView().getTransformationMethod(),
-                instanceOf(PasswordTransformationMethod.class));
-
-        TestThreadUtils.runOnUiThreadBlocking(getNameSuggestion()::performClick);
-        assertThat(clicked.get(), is(true));
-        clicked.set(false);
-        TestThreadUtils.runOnUiThreadBlocking(getPasswordSuggestion()::performClick);
-        assertThat(clicked.get(), is(true));
-    }
-
-    @Test
-    @MediumTest
-    public void testAddingPasskeySectionToTheModelRendersClickableActions()
-            throws ExecutionException {
-        final AtomicReference<Boolean> clicked = new AtomicReference<>(false);
-        assertThat(mView.get().getChildCount(), is(0));
-
-        final PasskeySection kTestPasskey =
-                new PasskeySection("Passkey User", () -> clicked.set(true));
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    kTestPasskey, AccessorySheetDataPiece.Type.PASSKEY_SECTION));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-
-        assertThat(
-                getPasskeyChipAt(0).getPrimaryTextView().getText(),
-                is(kTestPasskey.getDisplayName()));
-        assertThat(
-                getPasskeyChipAt(0).getSecondaryTextView().getText(),
-                is(getString(R.string.password_accessory_passkey_label)));
-
-        TestThreadUtils.runOnUiThreadBlocking(getPasskeyChipAt(0)::performClick);
-        assertThat(clicked.get(), is(true));
-    }
-
-    @Test
-    @MediumTest
-    public void testAddingUserInfoWithObfuscatedTextAndNullCallbackRendersDialog()
-            throws ExecutionException {
-        final AtomicReference<Boolean> clicked = new AtomicReference<>(false);
-        assertThat(mView.get().getChildCount(), is(0));
-
-        UserInfo usernameEnabled = new UserInfo("", false);
-        usernameEnabled.addField(
-                new UserInfoField("username1", "username1", "", false, item -> clicked.set(true)));
-        usernameEnabled.addField(
-                new UserInfoField("pa55w0rd", "Password for username1", "", true, null));
-
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    usernameEnabled, AccessorySheetDataPiece.Type.PASSWORD_INFO));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-
-        assertThat(getNameSuggestion().getPrimaryTextView().getText(), is("username1"));
-        assertThat(getPasswordSuggestion().getPrimaryTextView().getText(), is("pa55w0rd"));
-        assertThat(
-                getPasswordSuggestion().getPrimaryTextView().getTransformationMethod(),
-                instanceOf(PasswordTransformationMethod.class));
-
-        TestThreadUtils.runOnUiThreadBlocking(getNameSuggestion()::performClick);
-        assertThat(clicked.get(), is(true));
-        TestThreadUtils.runOnUiThreadBlocking(getPasswordSuggestion()::performClick);
-        assertInsecureFillingDialog();
-    }
-
-    @Test
-    @MediumTest
-    public void testAddingUserInfoTitlesAreRenderedIfNotEmpty() {
-        assertThat(mView.get().getChildCount(), is(0));
-        final UserInfoField kUnusedInfoField =
-                new UserInfoField("Unused Name", "Unused Password", "", false, cb -> {});
-
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    UserInfo sameOriginInfo = new UserInfo("", true);
-                    sameOriginInfo.addField(kUnusedInfoField);
-                    sameOriginInfo.addField(kUnusedInfoField);
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    sameOriginInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO));
-
-                    UserInfo pslOriginInfo = new UserInfo("other.origin.eg", false);
-                    pslOriginInfo.addField(kUnusedInfoField);
-                    pslOriginInfo.addField(kUnusedInfoField);
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    pslOriginInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(2)));
-
-        assertThat(getUserInfoAt(0).getTitle().isShown(), is(false));
-        assertThat(getUserInfoAt(1).getTitle().isShown(), is(true));
-        assertThat(getUserInfoAt(1).getTitle().getText(), is("other.origin.eg"));
-    }
-
-    @Test
-    @MediumTest
-    public void testOptionToggleRenderedIfNotEmpty() throws ExecutionException {
-        assertThat(mView.get().getChildCount(), is(0));
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    OptionToggle toggle =
-                            new OptionToggle(
-                                    "Save passwords for this site",
-                                    false,
-                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
-                                    result -> {});
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-        View title = mView.get().findViewById(R.id.option_toggle_title);
-        assertThat(title, is(not(nullValue())));
-        assertThat(title, instanceOf(TextView.class));
-        assertThat(((TextView) title).getText(), is("Save passwords for this site"));
-
-        View subtitle = mView.get().findViewById(R.id.option_toggle_subtitle);
-        assertThat(subtitle, is(not(nullValue())));
-        assertThat(subtitle, instanceOf(TextView.class));
-        assertThat(subtitle, withText(R.string.text_off));
-
-        View switchView = mView.get().findViewById(R.id.option_toggle_switch);
-        assertThat(switchView, is(not(nullValue())));
-        assertThat(switchView, instanceOf(SwitchCompat.class));
-        assertFalse(((SwitchCompat) switchView).isChecked());
-    }
-
-    @Test
-    @MediumTest
-    public void testClickingDisabledToggleInvokesCallbackToEnable() throws ExecutionException {
-        AtomicReference<Boolean> toggleEnabled = new AtomicReference<>();
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    OptionToggle toggle =
-                            new OptionToggle(
-                                    "Save passwords for this site",
-                                    false,
-                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
-                                    toggleEnabled::set);
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-        TestThreadUtils.runOnUiThreadBlocking(
-                mView.get().findViewById(R.id.option_toggle)::performClick);
-        assertTrue(toggleEnabled.get());
-    }
-
-    @Test
-    @MediumTest
-    public void testClickingEnabledToggleInvokesCallbackToDisable() throws ExecutionException {
-        AtomicReference<Boolean> toggleEnabled = new AtomicReference<>();
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    OptionToggle toggle =
-                            new OptionToggle(
-                                    "Save passwords for this site",
-                                    true,
-                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
-                                    toggleEnabled::set);
-                    mModel.add(
-                            new AccessorySheetDataPiece(
-                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
-                });
-
-        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
-        TestThreadUtils.runOnUiThreadBlocking(
-                mView.get().findViewById(R.id.option_toggle)::performClick);
-
-        assertFalse(toggleEnabled.get());
-    }
-
-    private String getString(@StringRes int strId) {
-        return mView.get().getResources().getString(strId);
-    }
-
-    private ChipView getPasskeyChipAt(int index) {
-        assertThat(mView.get().getChildCount(), is(greaterThan(index)));
-        assertThat(mView.get().getChildAt(index), instanceOf(ViewGroup.class));
-        LinearLayout passkeySection = (LinearLayout) mView.get().getChildAt(index);
-        return passkeySection.findViewById(R.id.keyboard_accessory_sheet_chip);
-    }
-
-    private PasswordAccessoryInfoView getUserInfoAt(int index) {
-        assertThat(mView.get().getChildCount(), is(greaterThan(index)));
-        assertThat(mView.get().getChildAt(index), instanceOf(PasswordAccessoryInfoView.class));
-        return (PasswordAccessoryInfoView) mView.get().getChildAt(index);
-    }
-
-    private ChipView getNameSuggestion() {
-        View view = getUserInfoAt(0).findViewById(R.id.suggestion_text);
-        assertThat(view, is(not(nullValue())));
-        assertThat(view, instanceOf(ChipView.class));
-        return (ChipView) view;
-    }
-
-    private ChipView getPasswordSuggestion() {
-        View view = getUserInfoAt(0).findViewById(R.id.password_text);
-        assertThat(view, is(not(nullValue())));
-        assertThat(view, instanceOf(ChipView.class));
-        return (ChipView) view;
-    }
-
-    private void assertInsecureFillingDialog() {
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    onView(withText(R.string.passwords_not_secure_filling))
-                            .inRoot(isDialog())
-                            .check(matches(isDisplayed()));
-                    onView(withText(R.string.passwords_not_secure_filling_details))
-                            .inRoot(isDialog())
-                            .check(matches(isDisplayed()));
-                });
-    }
-}
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java
index eda5ff84..e605c0f 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java
@@ -4,13 +4,21 @@
 
 package org.chromium.chrome.browser.keyboard_accessory.sheet_tabs;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isDialog;
 import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.text.method.PasswordTransformationMethod;
 import android.view.View;
@@ -18,7 +26,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import androidx.annotation.LayoutRes;
+import androidx.annotation.StringRes;
+import androidx.appcompat.widget.SwitchCompat;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.MediumTest;
 
@@ -32,15 +41,19 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.keyboard_accessory.AccessoryAction;
 import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType;
 import org.chromium.chrome.browser.keyboard_accessory.R;
 import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData;
+import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.OptionToggle;
+import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.PasskeySection;
 import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.UserInfo;
 import org.chromium.chrome.browser.keyboard_accessory.data.UserInfoField;
 import org.chromium.chrome.browser.keyboard_accessory.sheet_component.AccessorySheetCoordinator;
 import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AccessorySheetTabItemsModel.AccessorySheetDataPiece;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.browser_ui.widget.chips.ChipView;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.concurrent.ExecutionException;
@@ -56,18 +69,13 @@
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
-    /**
-     * This helper method inflates the accessory sheet and loads the given layout as minimalistic
-     * Tab. The passed callback then allows access to the inflated layout.
-     *
-     * @param layout The layout to be inflated.
-     * @param listener Is called with the inflated layout when the Accessory Sheet initializes it.
-     */
-    private void openLayoutInAccessorySheet(
-            @LayoutRes int layout, KeyboardAccessoryData.Tab.Listener listener) {
+    @Before
+    public void setUp() throws InterruptedException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     mModel = new AccessorySheetTabItemsModel();
+
                     AccessorySheetCoordinator accessorySheet =
                             new AccessorySheetCoordinator(
                                     mActivityTestRule
@@ -80,9 +88,21 @@
                                         "Passwords",
                                         null,
                                         null,
-                                        layout,
+                                        R.layout.password_accessory_sheet,
                                         AccessoryTabType.ALL,
-                                        listener)
+                                        new KeyboardAccessoryData.Tab.Listener() {
+                                            @Override
+                                            public void onTabCreated(ViewGroup view) {
+                                                mView.set((RecyclerView) view);
+                                                AccessorySheetTabViewBinder.initializeView(
+                                                        mView.get(), null);
+                                                PasswordAccessorySheetViewBinder
+                                                        .initializeView(mView.get(), mModel);
+                                            }
+
+                                            @Override
+                                            public void onTabShown() {}
+                                        })
                             });
                     accessorySheet.setHeight(
                             mActivityTestRule
@@ -92,26 +112,6 @@
                                             R.dimen.keyboard_accessory_sheet_height));
                     accessorySheet.show();
                 });
-    }
-
-    @Before
-    public void setUp() throws InterruptedException {
-        mActivityTestRule.startMainActivityOnBlankPage();
-        openLayoutInAccessorySheet(
-                R.layout.password_accessory_sheet,
-                new KeyboardAccessoryData.Tab.Listener() {
-                    @Override
-                    public void onTabCreated(ViewGroup view) {
-                        mView.set((RecyclerView) view);
-                        // Reuse coordinator code to create and wire the adapter. No mediator
-                        // involved.
-                        AccessorySheetTabViewBinder.initializeView(mView.get(), null);
-                        PasswordAccessorySheetViewBinder.initializeView(mView.get(), mModel);
-                    }
-
-                    @Override
-                    public void onTabShown() {}
-                });
         CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get(), notNullValue()));
     }
 
@@ -169,10 +169,11 @@
 
         CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
 
-        assertThat(getNameSuggestion().getText(), is("Name Suggestion"));
-        assertThat(getPasswordSuggestion().getText(), is("Password Suggestion"));
+        assertThat(getNameSuggestion().getPrimaryTextView().getText(), is("Name Suggestion"));
         assertThat(
-                getPasswordSuggestion().getTransformationMethod(),
+                getPasswordSuggestion().getPrimaryTextView().getText(), is("Password Suggestion"));
+        assertThat(
+                getPasswordSuggestion().getPrimaryTextView().getTransformationMethod(),
                 instanceOf(PasswordTransformationMethod.class));
 
         TestThreadUtils.runOnUiThreadBlocking(getNameSuggestion()::performClick);
@@ -182,21 +183,221 @@
         assertThat(clicked.get(), is(true));
     }
 
-    private TextView getNameSuggestion() {
-        assertThat(mView.get().getChildAt(0), instanceOf(LinearLayout.class));
-        LinearLayout layout = (LinearLayout) mView.get().getChildAt(0);
-        View view = layout.findViewById(R.id.suggestion_text);
-        assertThat(view, is(not(nullValue())));
-        assertThat(view, instanceOf(TextView.class));
-        return (TextView) view;
+    @Test
+    @MediumTest
+    public void testAddingPasskeySectionToTheModelRendersClickableActions()
+            throws ExecutionException {
+        final AtomicReference<Boolean> clicked = new AtomicReference<>(false);
+        assertThat(mView.get().getChildCount(), is(0));
+
+        final PasskeySection kTestPasskey =
+                new PasskeySection("Passkey User", () -> clicked.set(true));
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    kTestPasskey, AccessorySheetDataPiece.Type.PASSKEY_SECTION));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
+
+        assertThat(
+                getPasskeyChipAt(0).getPrimaryTextView().getText(),
+                is(kTestPasskey.getDisplayName()));
+        assertThat(
+                getPasskeyChipAt(0).getSecondaryTextView().getText(),
+                is(getString(R.string.password_accessory_passkey_label)));
+
+        TestThreadUtils.runOnUiThreadBlocking(getPasskeyChipAt(0)::performClick);
+        assertThat(clicked.get(), is(true));
     }
 
-    private TextView getPasswordSuggestion() {
-        assertThat(mView.get().getChildAt(0), instanceOf(LinearLayout.class));
-        LinearLayout layout = (LinearLayout) mView.get().getChildAt(0);
-        View view = layout.findViewById(R.id.password_text);
+    @Test
+    @MediumTest
+    public void testAddingUserInfoWithObfuscatedTextAndNullCallbackRendersDialog()
+            throws ExecutionException {
+        final AtomicReference<Boolean> clicked = new AtomicReference<>(false);
+        assertThat(mView.get().getChildCount(), is(0));
+
+        UserInfo usernameEnabled = new UserInfo("", false);
+        usernameEnabled.addField(
+                new UserInfoField("username1", "username1", "", false, item -> clicked.set(true)));
+        usernameEnabled.addField(
+                new UserInfoField("pa55w0rd", "Password for username1", "", true, null));
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    usernameEnabled, AccessorySheetDataPiece.Type.PASSWORD_INFO));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
+
+        assertThat(getNameSuggestion().getPrimaryTextView().getText(), is("username1"));
+        assertThat(getPasswordSuggestion().getPrimaryTextView().getText(), is("pa55w0rd"));
+        assertThat(
+                getPasswordSuggestion().getPrimaryTextView().getTransformationMethod(),
+                instanceOf(PasswordTransformationMethod.class));
+
+        TestThreadUtils.runOnUiThreadBlocking(getNameSuggestion()::performClick);
+        assertThat(clicked.get(), is(true));
+        TestThreadUtils.runOnUiThreadBlocking(getPasswordSuggestion()::performClick);
+        assertInsecureFillingDialog();
+    }
+
+    @Test
+    @MediumTest
+    public void testAddingUserInfoTitlesAreRenderedIfNotEmpty() {
+        assertThat(mView.get().getChildCount(), is(0));
+        final UserInfoField kUnusedInfoField =
+                new UserInfoField("Unused Name", "Unused Password", "", false, cb -> {});
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    UserInfo sameOriginInfo = new UserInfo("", true);
+                    sameOriginInfo.addField(kUnusedInfoField);
+                    sameOriginInfo.addField(kUnusedInfoField);
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    sameOriginInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO));
+
+                    UserInfo pslOriginInfo = new UserInfo("other.origin.eg", false);
+                    pslOriginInfo.addField(kUnusedInfoField);
+                    pslOriginInfo.addField(kUnusedInfoField);
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    pslOriginInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(2)));
+
+        assertThat(getUserInfoAt(0).getTitle().isShown(), is(false));
+        assertThat(getUserInfoAt(1).getTitle().isShown(), is(true));
+        assertThat(getUserInfoAt(1).getTitle().getText(), is("other.origin.eg"));
+    }
+
+    @Test
+    @MediumTest
+    public void testOptionToggleRenderedIfNotEmpty() throws ExecutionException {
+        assertThat(mView.get().getChildCount(), is(0));
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    OptionToggle toggle =
+                            new OptionToggle(
+                                    "Save passwords for this site",
+                                    false,
+                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
+                                    result -> {});
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
+        View title = mView.get().findViewById(R.id.option_toggle_title);
+        assertThat(title, is(not(nullValue())));
+        assertThat(title, instanceOf(TextView.class));
+        assertThat(((TextView) title).getText(), is("Save passwords for this site"));
+
+        View subtitle = mView.get().findViewById(R.id.option_toggle_subtitle);
+        assertThat(subtitle, is(not(nullValue())));
+        assertThat(subtitle, instanceOf(TextView.class));
+        assertThat(subtitle, withText(R.string.text_off));
+
+        View switchView = mView.get().findViewById(R.id.option_toggle_switch);
+        assertThat(switchView, is(not(nullValue())));
+        assertThat(switchView, instanceOf(SwitchCompat.class));
+        assertFalse(((SwitchCompat) switchView).isChecked());
+    }
+
+    @Test
+    @MediumTest
+    public void testClickingDisabledToggleInvokesCallbackToEnable() throws ExecutionException {
+        AtomicReference<Boolean> toggleEnabled = new AtomicReference<>();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    OptionToggle toggle =
+                            new OptionToggle(
+                                    "Save passwords for this site",
+                                    false,
+                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
+                                    toggleEnabled::set);
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
+        TestThreadUtils.runOnUiThreadBlocking(
+                mView.get().findViewById(R.id.option_toggle)::performClick);
+        assertTrue(toggleEnabled.get());
+    }
+
+    @Test
+    @MediumTest
+    public void testClickingEnabledToggleInvokesCallbackToDisable() throws ExecutionException {
+        AtomicReference<Boolean> toggleEnabled = new AtomicReference<>();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    OptionToggle toggle =
+                            new OptionToggle(
+                                    "Save passwords for this site",
+                                    true,
+                                    AccessoryAction.TOGGLE_SAVE_PASSWORDS,
+                                    toggleEnabled::set);
+                    mModel.add(
+                            new AccessorySheetDataPiece(
+                                    toggle, AccessorySheetDataPiece.Type.OPTION_TOGGLE));
+                });
+
+        CriteriaHelper.pollUiThread(() -> Criteria.checkThat(mView.get().getChildCount(), is(1)));
+        TestThreadUtils.runOnUiThreadBlocking(
+                mView.get().findViewById(R.id.option_toggle)::performClick);
+
+        assertFalse(toggleEnabled.get());
+    }
+
+    private String getString(@StringRes int strId) {
+        return mView.get().getResources().getString(strId);
+    }
+
+    private ChipView getPasskeyChipAt(int index) {
+        assertThat(mView.get().getChildCount(), is(greaterThan(index)));
+        assertThat(mView.get().getChildAt(index), instanceOf(ViewGroup.class));
+        LinearLayout passkeySection = (LinearLayout) mView.get().getChildAt(index);
+        return passkeySection.findViewById(R.id.keyboard_accessory_sheet_chip);
+    }
+
+    private PasswordAccessoryInfoView getUserInfoAt(int index) {
+        assertThat(mView.get().getChildCount(), is(greaterThan(index)));
+        assertThat(mView.get().getChildAt(index), instanceOf(PasswordAccessoryInfoView.class));
+        return (PasswordAccessoryInfoView) mView.get().getChildAt(index);
+    }
+
+    private ChipView getNameSuggestion() {
+        View view = getUserInfoAt(0).findViewById(R.id.suggestion_text);
         assertThat(view, is(not(nullValue())));
-        assertThat(view, instanceOf(TextView.class));
-        return (TextView) view;
+        assertThat(view, instanceOf(ChipView.class));
+        return (ChipView) view;
+    }
+
+    private ChipView getPasswordSuggestion() {
+        View view = getUserInfoAt(0).findViewById(R.id.password_text);
+        assertThat(view, is(not(nullValue())));
+        assertThat(view, instanceOf(ChipView.class));
+        return (ChipView) view;
+    }
+
+    private void assertInsecureFillingDialog() {
+        CriteriaHelper.pollInstrumentationThread(
+                () -> {
+                    onView(withText(R.string.passwords_not_secure_filling))
+                            .inRoot(isDialog())
+                            .check(matches(isDisplayed()));
+                    onView(withText(R.string.passwords_not_secure_filling_details))
+                            .inRoot(isDialog())
+                            .check(matches(isDisplayed()));
+                });
     }
 }
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
index b9afefa..85ca741 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryControllerTest.java
@@ -70,7 +70,7 @@
     @Mock private ListObservable.ListObserver<Void> mMockActionListObserver;
     @Mock private KeyboardAccessoryCoordinator.BarVisibilityDelegate mMockBarVisibilityDelegate;
     @Mock private AccessorySheetCoordinator.SheetVisibilityDelegate mMockSheetVisibilityDelegate;
-    @Mock private KeyboardAccessoryModernView mMockView;
+    @Mock private KeyboardAccessoryView mMockView;
     @Mock private KeyboardAccessoryButtonGroupCoordinator mMockButtonGroup;
     @Mock private KeyboardAccessoryCoordinator.TabSwitchingDelegate mMockTabSwitchingDelegate;
     @Mock private AutofillDelegate mMockAutofillDelegate;
@@ -560,7 +560,7 @@
     }
 
     @Test
-    public void testModelChangesUpdatesTheContentDescriptionInModernView() {
+    public void testModelChangesUpdatesTheContentDescription() {
         PropertyProvider<AutofillSuggestion[]> autofillSuggestionProvider =
                 new PropertyProvider<>(AUTOFILL_SUGGESTION);
 
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
index e6e53080..9e2e1637 100644
--- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
+++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
@@ -150,7 +150,7 @@
     }
 
     @Test
-    public void testUsesTabTitleOnlyForEmptyListsForModernDesign() {
+    public void testUsesTabTitleOnlyForEmptyLists() {
         final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>();
         final AccessorySheetData testData =
                 new AccessorySheetData(AccessoryTabType.PASSWORDS, "No passwords for this", "");
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
index 0199806..70fd243 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -120,8 +120,8 @@
 
     /**
      * @return Whether the Start Surface feature flag is enabled.
-     * @Deprecated Use {@link
-     * org.chromium.chrome.browser.tasks.ReturnToChromeUtil#isStartSurfaceEnabled} instead.
+     * @deprecated Use {@link
+     *     org.chromium.chrome.browser.tasks.ReturnToChromeUtil#isStartSurfaceEnabled} instead.
      */
     public static boolean isStartSurfaceFlagEnabled() {
         return ChromeFeatureList.sStartSurfaceAndroid.isEnabled() && !SysUtils.isLowEndDevice();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java
index 39b044db..13fc263 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabProvider.java
@@ -54,10 +54,11 @@
          * A notification that the observer has switched to observing a different tab. This can be
          * called a first time with the {@code hint} parameter set to true, indicating that a new
          * tab is going to be selected.
+         *
          * @param tab The tab that the observer is now observing. This can be null.
          * @param hint Whether the change event is a hint that a tab change is likely. If true, the
-         *             provided tab may still be frozen and is not yet selected.
-         * @Deprecated - hint is unused, override this method without the hint parameter.
+         *     provided tab may still be frozen and is not yet selected.
+         * @deprecated - hint is unused, override this method without the hint parameter.
          */
         protected void onObservingDifferentTab(Tab tab, boolean hint) {}
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 39988c451..5cae320a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -2052,8 +2052,9 @@
 
     /**
      * Gets the {@link TabContentManager} instance which holds snapshots of the tabs in this model.
+     *
      * @return The thumbnail cache, possibly null.
-     * @Deprecated in favor of getTabContentManagerSupplier().
+     * @deprecated in favor of getTabContentManagerSupplier().
      */
     @Deprecated
     public TabContentManager getTabContentManager() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
index 54ab609..902ced8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
@@ -392,7 +392,7 @@
     }
 
     /**
-     * @Return Whether the button is hovered on.
+     * @return Whether the button is hovered on.
      */
     public boolean isHovered() {
         return mIsHovered;
@@ -408,14 +408,14 @@
     }
 
     /**
-     * @Return Whether the button is pressed from mouse.
+     * @return Whether the button is pressed from mouse.
      */
     public boolean isPressedFromMouse() {
         return mIsPressed && mIsPressedFromMouse;
     }
 
     /**
-     * @Return Whether hover background should be applied to the button.
+     * @return Whether hover background should be applied to the button.
      */
     public boolean getShouldApplyHoverBackground() {
         return isHovered() || isPressedFromMouse();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index d15a8fec..6b95ba9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -601,8 +601,8 @@
     }
 
     /**
-     * @Return The start padding needed for model selector button to ensure there is enough space
-     * for touch target.
+     * @return The start padding needed for model selector button to ensure there is enough space
+     *     for touch target.
      */
     private float getButtonStartPaddingForTouchTarget() {
         if (mModelSelectorButton.isVisible()) {
diff --git a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_handler_unittest.cc b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_handler_unittest.cc
index ac24fb612..ecb1f4d2 100644
--- a/chrome/browser/accessibility/media_app/ax_media_app_untrusted_handler_unittest.cc
+++ b/chrome/browser/accessibility/media_app/ax_media_app_untrusted_handler_unittest.cc
@@ -97,12 +97,12 @@
   EXPECT_FALSE(handler_->IsOcrServiceEnabled());
   EXPECT_FALSE(fake_media_app_.IsOcrServiceEnabled());
 
-  screen_ai::ScreenAIInstallState::GetInstance()->SetState(
+  screen_ai::ScreenAIInstallState::GetInstance()->SetStateForTesting(
       screen_ai::ScreenAIInstallState::State::kReady);
   EXPECT_TRUE(handler_->IsOcrServiceEnabled());
   EXPECT_TRUE(fake_media_app_.IsOcrServiceEnabled());
 
-  screen_ai::ScreenAIInstallState::GetInstance()->SetState(
+  screen_ai::ScreenAIInstallState::GetInstance()->SetStateForTesting(
       screen_ai::ScreenAIInstallState::State::kNotDownloaded);
   EXPECT_FALSE(handler_->IsOcrServiceEnabled());
   EXPECT_FALSE(fake_media_app_.IsOcrServiceEnabled());
diff --git a/chrome/browser/accessibility/pdf_ocr_controller.cc b/chrome/browser/accessibility/pdf_ocr_controller.cc
index e5a6d4c8..0847ad1 100644
--- a/chrome/browser/accessibility/pdf_ocr_controller.cc
+++ b/chrome/browser/accessibility/pdf_ocr_controller.cc
@@ -197,6 +197,11 @@
 }
 
 void PdfOcrController::SendPdfOcrAlwaysActiveToAll(bool is_always_active) {
+  if (is_always_active) {
+    CHECK_EQ(ScreenAIInstallState::GetInstance()->get_state(),
+             ScreenAIInstallState::State::kReady);
+  }
+
   std::vector<content::WebContents*> html_web_contents_vector =
       GetPdfHtmlWebContentses(profile_);
   // Iterate over all WebContentses associated with PDF Viewer Mimehandlers and
diff --git a/chrome/browser/apps/app_service/app_install/app_install_service_ash.cc b/chrome/browser/apps/app_service/app_install/app_install_service_ash.cc
index 6ba45d6..e9ab5c1 100644
--- a/chrome/browser/apps/app_service/app_install/app_install_service_ash.cc
+++ b/chrome/browser/apps/app_service/app_install/app_install_service_ash.cc
@@ -155,7 +155,7 @@
                 base::BindOnce(
                     [](base::WeakPtr<ash::app_install::AppInstallDialog> dialog,
                        bool dialog_accepted) {
-                      dialog->SetInstallSuccess(true);
+                      dialog->SetInstallComplete(nullptr);
                     },
                     dialog));
             return AppInstallResult::kUnknown;
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
index ff9d301..383ac05 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
@@ -243,8 +243,11 @@
                                 ->GetMediaStreamCaptureIndicator()
                                 .get());
 
-  notification_display_service_.Observe(
-      NotificationDisplayServiceFactory::GetForProfile(profile()));
+  // NotificationDisplayService could be null in some tests.
+  if (auto* notification_display_service =
+          NotificationDisplayServiceFactory::GetForProfile(profile())) {
+    notification_display_service_.Observe(notification_display_service);
+  }
 
   profile_pref_change_registrar_.Init(profile()->GetPrefs());
   profile_pref_change_registrar_.Add(
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index d39645b..6cf1a9b 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -5144,6 +5144,7 @@
     "app_list/search/test/test_search_provider.h",
     "app_list/search/util/ftrl_optimizer_unittest.cc",
     "app_list/search/util/keyword_cache_unittest.cc",
+    "app_list/search/util/manatee_unittest.cc",
     "app_list/search/util/mrfu_cache_unittest.cc",
     "app_list/search/util/persistent_proto_unittest.cc",
     "app_list/search/util/score_normalizer_unittest.cc",
diff --git a/chrome/browser/ash/app_list/search/util/manatee.cc b/chrome/browser/ash/app_list/search/util/manatee.cc
new file mode 100644
index 0000000..4ca4572
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/util/manatee.cc
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/app_list/search/util/manatee.h"
+
+#include <numeric>
+#include <optional>
+#include <vector>
+
+namespace app_list {
+
+std::optional<double> GetWordSimilarity(const std::vector<double>& vector1,
+                                        const std::vector<double>& vector2) {
+  if (vector1.size() != vector2.size()) {
+    return std::nullopt;
+  }
+  return std::inner_product(vector1.begin(), vector1.end(), vector2.begin(), 0);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ash/app_list/search/util/manatee.h b/chrome/browser/ash/app_list/search/util/manatee.h
new file mode 100644
index 0000000..bbc4095
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/util/manatee.h
@@ -0,0 +1,18 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_APP_LIST_SEARCH_UTIL_MANATEE_H_
+#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_UTIL_MANATEE_H_
+
+#include <optional>
+#include <vector>
+
+namespace app_list {
+
+std::optional<double> GetWordSimilarity(const std::vector<double>& vector1,
+                                        const std::vector<double>& vector2);
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_MANATEE_H_
diff --git a/chrome/browser/ash/app_list/search/util/manatee_unittest.cc b/chrome/browser/ash/app_list/search/util/manatee_unittest.cc
new file mode 100644
index 0000000..4f502b4
--- /dev/null
+++ b/chrome/browser/ash/app_list/search/util/manatee_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/app_list/search/util/manatee.h"
+
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace app_list::test {
+
+TEST(ManateeTest, GetWordSimilarityPositiveVectors) {
+  // Test for successful dot product calculation of two
+  // positive input vectors
+
+  std::vector<double> v1{1.0, 2.0, 3.0};
+  std::vector<double> v2{4.0, 5.0, 6.0};
+  absl::optional<double> result = GetWordSimilarity(v1, v2);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_DOUBLE_EQ(32.0, result.value());
+}
+
+TEST(ManateeTest, GetWordSimilarityMismatchingSize) {
+  // Test for correct handling of input vectors
+  // with mismatching size
+
+  std::vector<double> v1{1.0, 2.0, 3.0};
+  std::vector<double> v2{4.0, 5.0, 6.0, 7.0};
+  absl::optional<double> result = GetWordSimilarity(v1, v2);
+  ASSERT_FALSE(result.has_value());
+}
+
+TEST(ManateeTest, GetWordSimilarityEmptyVectors) {
+  // Test for correct handling of empty input vectors
+
+  std::vector<double> v1{};
+  std::vector<double> v2{};
+  absl::optional<double> result = GetWordSimilarity(v1, v2);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_DOUBLE_EQ(0.0, result.value());
+}
+
+TEST(ManateeTest, GetWordSimilarityZeroVectors) {
+  // Test for correct dot product with a vector of
+  // all zero values
+
+  std::vector<double> v1{1.0, 2.0, 3.0};
+  std::vector<double> v2{0.0, 0.0, 0.0};
+  absl::optional<double> result = GetWordSimilarity(v1, v2);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_DOUBLE_EQ(0.0, result.value());
+}
+
+}  // namespace app_list::test
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
index 1b54105..af4f7d8 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.h
@@ -7,6 +7,7 @@
 
 #include "ash/components/arc/mojom/app.mojom.h"
 #include "ash/constants/ash_features.h"
+#include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_multi_source_observation.h"
 #include "base/scoped_observation.h"
diff --git a/chrome/browser/ash/arc/input_overlay/touch_injector.h b/chrome/browser/ash/arc/input_overlay/touch_injector.h
index ade046d19..ea0915c 100644
--- a/chrome/browser/ash/arc/input_overlay/touch_injector.h
+++ b/chrome/browser/ash/arc/input_overlay/touch_injector.h
@@ -9,6 +9,7 @@
 #include <optional>
 #include <vector>
 
+#include "base/containers/flat_map.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
diff --git a/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.cc b/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.cc
index 25200dd..0825afa 100644
--- a/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.cc
+++ b/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.cc
@@ -9,7 +9,6 @@
 #include "ash/constants/ash_switches.h"
 #include "base/check.h"
 #include "base/command_line.h"
-#include "base/environment.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/crosapi/fake_device_ownership_waiter.h"
@@ -17,35 +16,21 @@
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 namespace ash {
 
 bool KioskAshBrowserTestStarter::HasLacrosArgument() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      ash::switches::kLacrosChromePath);
+  return ash_browser_test_starter_.HasLacrosArgument();
 }
 
 void KioskAshBrowserTestStarter::PrepareEnvironmentForKioskLacros() {
-  DCHECK(HasLacrosArgument());
-  std::unique_ptr<base::Environment> env(base::Environment::Create());
-  ASSERT_TRUE(scoped_temp_dir_xdg_.CreateUniqueTempDir());
-  env->SetVar("XDG_RUNTIME_DIR", scoped_temp_dir_xdg_.GetPath().AsUTF8Unsafe());
+  CHECK(ash_browser_test_starter_.PrepareEnvironmentForLacros());
 
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      ash::switches::kAshEnableWaylandServer);
-
-  std::vector<std::string> lacros_args = {
-      // Disable gpu process in Lacros since hardware accelerated rendering is
-      // not possible yet in Ash X11 backend. See details in crbug/1478369.
-      "--disable-gpu",
-      // Disable gpu sandbox in Lacros since it fails in Linux emulator
-      // environment.
-      // See details in crbug/1483530.
-      "--disable-gpu-sandbox"};
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      ash::switches::kLacrosChromeAdditionalArgs,
-      base::JoinString(lacros_args, "####"));
+  // The `kDisableLacrosKeepAliveForTesting` switch is set by
+  // `AshBrowserTestStarter`, but kiosk launch relies on `KeepAlive`, so remove
+  // it again.
+  base::CommandLine::ForCurrentProcess()->RemoveSwitch(
+      switches::kDisableLacrosKeepAliveForTesting);
 }
 
 void KioskAshBrowserTestStarter::SetLacrosAvailabilityPolicy() {
@@ -60,9 +45,7 @@
 }
 
 void KioskAshBrowserTestStarter::SetUpBrowserManager() {
-  DCHECK(HasLacrosArgument());
-  crosapi::BrowserManager::Get()->set_device_ownership_waiter_for_testing(
-      std::make_unique<crosapi::FakeDeviceOwnershipWaiter>());
+  ash_browser_test_starter_.SetUpBrowserManager();
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.h b/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.h
index dc00718c..fdf6e32 100644
--- a/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.h
+++ b/chrome/browser/ash/login/app_mode/test/kiosk_ash_browser_test_starter.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ASH_LOGIN_APP_MODE_TEST_KIOSK_ASH_BROWSER_TEST_STARTER_H_
 #define CHROME_BROWSER_ASH_LOGIN_APP_MODE_TEST_KIOSK_ASH_BROWSER_TEST_STARTER_H_
 
-#include "base/files/scoped_temp_dir.h"
+#include "chrome/test/base/chromeos/ash_browser_test_starter.h"
 
 namespace ash {
 
@@ -27,7 +27,7 @@
   void SetUpBrowserManager();
 
  private:
-  base::ScopedTempDir scoped_temp_dir_xdg_;
+  ::test::AshBrowserTestStarter ash_browser_test_starter_;
 };
 
 }  // namespace ash
diff --git a/chrome/browser/ash/login/lock/screen_locker_unittest.cc b/chrome/browser/ash/login/lock/screen_locker_unittest.cc
index 69250893..8118fd6b 100644
--- a/chrome/browser/ash/login/lock/screen_locker_unittest.cc
+++ b/chrome/browser/ash/login/lock/screen_locker_unittest.cc
@@ -206,11 +206,30 @@
 // the device.
 TEST_F(ScreenLockerUnitTest, VerifyAshIsNotifiedOfScreenLocked) {
   CreateSessionForUser(/*is_public_account=*/false);
-
   EXPECT_EQ(0, test_session_controller_.lock_animation_complete_call_count());
+
+  // Show the lock screen.
   ScreenLocker::Show();
   base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(ScreenLocker::default_screen_locker());
+  EXPECT_TRUE(ScreenLocker::default_screen_locker()->locked());
   EXPECT_EQ(1, test_session_controller_.lock_animation_complete_call_count());
+
+  // Hide the lock screen.
+  ScreenLocker::Hide();
+  // Needed to perform internal cleanup scheduled in ScreenLocker::Hide()
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(ScreenLocker::default_screen_locker());
+}
+
+// Tests that `GetUsersToShow()` returns a list with one user when the user is
+// regular.
+TEST_F(ScreenLockerUnitTest, GetUsersToShowRegular) {
+  CreateSessionForUser(/*is_public_account=*/false);
+
+  ScreenLocker::Show();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(ScreenLocker::default_screen_locker()->GetUsersToShow().size(), 1u);
   ScreenLocker::Hide();
   // Needed to perform internal cleanup scheduled in ScreenLocker::Hide()
   base::RunLoop().RunUntilIdle();
@@ -218,7 +237,7 @@
 
 // Tests that `GetUsersToShow()` returns an empty list when the user is a
 // Managed Guest Session.
-TEST_F(ScreenLockerUnitTest, GetUsersToShow) {
+TEST_F(ScreenLockerUnitTest, GetUsersToShowPublicAccount) {
   CreateSessionForUser(/*is_public_account=*/true);
 
   ScreenLocker::Show();
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.cc b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.cc
index 874a9a0..eb44bd6 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.cc
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.cc
@@ -29,6 +29,33 @@
 
 namespace policy {
 
+namespace {
+
+// Returns the accessible name for the learn more link of the given block
+// `reason`.
+std::u16string GetAccessibleLearnMoreLinkNameForBlockReason(
+    policy::FilesPolicyDialog::BlockReason reason) {
+  switch (reason) {
+    case FilesPolicyDialog::BlockReason::kDlp:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_DATA_CONTROLS_ACCESSIBLE_NAME);
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_SENSITIVE_DATA_PROTECTION_ACCESSIBLE_NAME);
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_MALWARE_PROTECTION_ACCESSIBLE_NAME);
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectorsUnknownScanResult:
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectorsEncryptedFile:
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectorsLargeFile:
+    case FilesPolicyDialog::BlockReason::kEnterpriseConnectors:
+      // Currently these block reasons cannot have a learn more link.
+      return std::u16string();
+  }
+}
+
+}  // namespace
+
 FilesPolicyDialogFactory* factory_;
 
 // static
@@ -73,6 +100,9 @@
     settings.learn_more_url_ = GURL(dlp::kDlpLearnMoreUrl);
   }
 
+  settings.accessible_learn_more_link_name_ =
+      GetAccessibleLearnMoreLinkNameForBlockReason(reason);
+
   return settings;
 }
 
@@ -94,6 +124,9 @@
     settings.learn_more_url_ = GURL(dlp::kDlpLearnMoreUrl);
   }
 
+  settings.accessible_learn_more_link_name_ =
+      GetAccessibleLearnMoreLinkNameForBlockReason(reason);
+
   return settings;
 }
 
@@ -110,7 +143,9 @@
   return bypass_requires_justification_ ==
              other.bypass_requires_justification_ &&
          message_ == other.message_ &&
-         learn_more_url_ == other.learn_more_url_ && files_ == other.files_;
+         learn_more_url_ == other.learn_more_url_ && files_ == other.files_ &&
+         accessible_learn_more_link_name_ ==
+             other.accessible_learn_more_link_name_;
 }
 
 bool FilesPolicyDialog::Info::operator!=(const Info& other) const {
@@ -157,6 +192,10 @@
   }
 }
 
+std::u16string FilesPolicyDialog::Info::GetAccessibleLearnMoreLinkName() const {
+  return accessible_learn_more_link_name_;
+}
+
 bool FilesPolicyDialog::Info::HasCustomDetails() const {
   return DoesBypassRequireJustification() || HasCustomMessage() ||
          is_custom_learn_more_url_;
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h
index 4ffcf5f..33cb45b2 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog.h
@@ -126,6 +126,10 @@
     // Overrides the default learn more URL.
     void SetLearnMoreURL(const std::optional<GURL>& url);
 
+    // Returns an accessible learn more link name, if available. An empty string
+    // otherwise.
+    std::u16string GetAccessibleLearnMoreLinkName() const;
+
     // Returns whether at least one of the default values (e.g., message, learn
     // more URL, etc...) has been overridden with a custom value.
     bool HasCustomDetails() const;
@@ -149,6 +153,10 @@
     // Whether `learn_more_url_` is a custom url.
     bool is_custom_learn_more_url_ = false;
 
+    // Learn more link name providing more info for users using a ChromeVox
+    // reader.
+    std::u16string accessible_learn_more_link_name_;
+
     // Default, admin defined learn more URL, or none of them.
     std::optional<GURL> learn_more_url_;
   };
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.cc b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.cc
index 0718bda..cc01bc704 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.cc
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.cc
@@ -109,6 +109,7 @@
 }
 
 void AddLearnMoreLink(const std::u16string& text,
+                      const std::u16string& accessible_name,
                       const GURL& url,
                       views::View* view) {
   views::Link* learn_more_link =
@@ -120,6 +121,7 @@
   learn_more_link->SetEnabledColor(
       ash::ColorProvider::Get()->GetContentLayerColor(
           ash::ColorProvider::ContentLayerType::kTextColorURL));
+  learn_more_link->SetAccessibleName(accessible_name);
 }
 
 }  // namespace policy::files_dialog_utils
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.h b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.h
index be63bd7..39efcce 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.h
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_dialog_utils.h
@@ -27,6 +27,7 @@
 
 // Appends a learn more link to the given `view`.
 void AddLearnMoreLink(const std::u16string& text,
+                      const std::u16string& accessible_name,
                       const GURL& url,
                       views::View* view);
 
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.cc b/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.cc
index d8e082b2..368a1eb 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.cc
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.cc
@@ -55,18 +55,19 @@
 }
 
 // Returns learn more links associated with the given `reasons`.
-std::set<GURL> GetLearnMoreLinks(
+std::vector<std::pair<GURL, std::u16string>> GetLearnMoreLinks(
     const std::vector<FilesPolicyDialog::BlockReason>& reasons,
     const std::map<FilesPolicyDialog::BlockReason, FilesPolicyDialog::Info>&
         dialog_info_map) {
-  std::set<GURL> links;
+  std::vector<std::pair<GURL, std::u16string>> links;
   for (FilesPolicyDialog::BlockReason reason : reasons) {
     auto it = dialog_info_map.find(reason);
     if (it == dialog_info_map.end() ||
         !it->second.GetLearnMoreURL().has_value()) {
       continue;
     }
-    links.insert(it->second.GetLearnMoreURL().value());
+    links.emplace_back(it->second.GetLearnMoreURL().value(),
+                       it->second.GetAccessibleLearnMoreLinkName());
   }
   return links;
 }
@@ -102,7 +103,7 @@
     int view_id,
     const std::u16string& message,
     const std::vector<DlpConfidentialFile>& files,
-    const std::set<GURL>& learn_more_urls)
+    const std::vector<std::pair<GURL, std::u16string>>& learn_more_urls)
     : view_id(view_id),
       message(message),
       files(files),
@@ -127,9 +128,10 @@
   // Single error dialog.
   if (sections_.size() == 1) {
     const auto& section = sections_.front();
-    for (const auto& url : section.learn_more_urls) {
+    for (const auto& [url, accessible_name] : section.learn_more_urls) {
       files_dialog_utils::AddLearnMoreLink(
-          l10n_util::GetStringUTF16(IDS_LEARN_MORE), url, upper_panel_);
+          l10n_util::GetStringUTF16(IDS_LEARN_MORE), accessible_name, url,
+          upper_panel_);
     }
     for (const auto& file : section.files) {
       AddConfidentialRow(file.icon, file.title);
@@ -260,7 +262,7 @@
           ash::TypographyToken::kCrosBody1));
 
   // Add the learn more link if provided.
-  for (const GURL& url : section.learn_more_urls) {
+  for (const auto& [url, accessible_name] : section.learn_more_urls) {
     views::View* learn_more_row =
         scroll_view_container_->AddChildView(std::make_unique<views::View>());
     learn_more_row->SetLayoutManager(std::make_unique<views::BoxLayout>(
@@ -268,7 +270,8 @@
         gfx::Insets::TLBR(0, 16, 10, 16), 0));
 
     files_dialog_utils::AddLearnMoreLink(
-        l10n_util::GetStringUTF16(IDS_LEARN_MORE), url, learn_more_row);
+        l10n_util::GetStringUTF16(IDS_LEARN_MORE), accessible_name, url,
+        learn_more_row);
   }
 
   for (const auto& file : section.files) {
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.h b/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.h
index dcecd5e..a584b5d20 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.h
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.h
@@ -35,10 +35,11 @@
  private:
   // Holds all the information of a section of the dialog.
   struct BlockedFilesSection {
-    BlockedFilesSection(int view_id,
-                        const std::u16string& message,
-                        const std::vector<DlpConfidentialFile>& files,
-                        const std::set<GURL>& learn_more_urls);
+    BlockedFilesSection(
+        int view_id,
+        const std::u16string& message,
+        const std::vector<DlpConfidentialFile>& files,
+        const std::vector<std::pair<GURL, std::u16string>>& learn_more_urls);
     ~BlockedFilesSection();
 
     BlockedFilesSection(const BlockedFilesSection& other);
@@ -55,10 +56,10 @@
     // The blocked files.
     std::vector<DlpConfidentialFile> files;
 
-    // Learn more URLs displayed to the user. Because a section may hold files
-    // blocked for different reasons, each of which defining its own learn more
-    // URL, we use a set to collect distinct URLs only.
-    std::set<GURL> learn_more_urls;
+    // Learn more URLs displayed to the user and their accessible name read out
+    // by ChromeVox. A section may hold files blocked for different reasons,
+    // each of which defining its own learn more URL.
+    std::vector<std::pair<GURL, std::u16string>> learn_more_urls;
   };
 
   // PolicyDialogBase overrides:
diff --git a/chrome/browser/ash/policy/dlp/dialogs/files_policy_warn_dialog.cc b/chrome/browser/ash/policy/dlp/dialogs/files_policy_warn_dialog.cc
index c53cbba..215f12be 100644
--- a/chrome/browser/ash/policy/dlp/dialogs/files_policy_warn_dialog.cc
+++ b/chrome/browser/ash/policy/dlp/dialogs/files_policy_warn_dialog.cc
@@ -140,6 +140,7 @@
   if (dialog_info_.GetLearnMoreURL().has_value()) {
     files_dialog_utils::AddLearnMoreLink(
         l10n_util::GetStringUTF16(IDS_LEARN_MORE),
+        dialog_info.GetAccessibleLearnMoreLinkName(),
         dialog_info_.GetLearnMoreURL().value(), upper_panel_);
   }
   MaybeAddConfidentialRows();
@@ -337,6 +338,10 @@
   justification_field_->SetID(
       PolicyDialogBase::kEnterpriseConnectorsJustificationTextareaId);
   justification_field_->SetAccessibleName(justification_label_text);
+  justification_field_->SetAccessibleDescription(l10n_util::GetStringFUTF16(
+      IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION,
+      base::NumberToString16(0),
+      base::NumberToString16(kMaxBypassJustificationLength)));
   justification_field_->SetController(this);
   justification_field_->SetBackgroundColor(SK_ColorTRANSPARENT);
   justification_field_->SetPreferredSize(
@@ -367,6 +372,10 @@
         IDS_DEEP_SCANNING_DIALOG_BYPASS_JUSTIFICATION_TEXT_LIMIT_LABEL,
         base::NumberToString16(new_contents.size()),
         base::NumberToString16(kMaxBypassJustificationLength)));
+    justification_field_->SetAccessibleDescription(l10n_util::GetStringFUTF16(
+        IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION,
+        base::NumberToString16(new_contents.size()),
+        base::NumberToString16(kMaxBypassJustificationLength)));
   }
 
   if (new_contents.size() == 0 ||
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
index f3eeb60a..094f137 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
@@ -159,6 +159,19 @@
   return kSystemURLsMap.contains(url.spec());
 }
 
+// Return converted `level`. It is converted to kBlock if it is `kWarn` and the
+// destination is a system app to avoid spamming the user with warning requests
+// for browsing a folder with warned (image) files.
+DlpRulesManager::Level ConvertSystemAppWarning(
+    DlpRulesManager::Level level,
+    const DlpFileDestination& destination) {
+  if (level == DlpRulesManager::Level::kWarn && destination.url() &&
+      IsSystemAppURL(*destination.url())) {
+    return DlpRulesManager::Level::kBlock;
+  }
+  return level;
+}
+
 }  // namespace
 
 // static
@@ -535,6 +548,8 @@
       }
     }
 
+    level = ConvertSystemAppWarning(level, destination);
+
     switch (level) {
       case DlpRulesManager::Level::kBlock: {
         files_levels.emplace_back(file, ::dlp::RestrictionLevel::LEVEL_BLOCK);
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
index 0e73d08c..a9d30bf 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
@@ -1372,6 +1372,42 @@
               base::BucketsAre(base::Bucket(dlp::FileAction::kTransfer, 0)));
 }
 
+// Warnings to Files app and image loader should be converted to blocks to avoid
+// mass warnings when browsing a folder with warned images.
+TEST_F(DlpFilesControllerAshTest, BlockWarningFilesOnSystemApps) {
+  const auto file = DlpFilesControllerAsh::FileDaemonInfo(
+      kInode1, kCrtime1, base::FilePath(kFilePath1), kExampleUrl1,
+      kReferrerUrl1);
+
+  base::MockOnceCallback<void(
+      const std::vector<std::pair<FileDaemonInfo, ::dlp::RestrictionLevel>>&)>
+      result_callback;
+
+  EXPECT_CALL(
+      result_callback,
+      Run(testing::ElementsAre(testing::Pair(
+          testing::FieldsAre(kInode1, kCrtime1, base::FilePath(kFilePath1),
+                             kExampleUrl1, kReferrerUrl1),
+          ::dlp::RestrictionLevel::LEVEL_BLOCK))))
+      .Times(2);
+
+  EXPECT_CALL(*rules_manager_, IsRestrictedDestination)
+      .Times(2)
+      .WillRepeatedly(
+          testing::DoAll(testing::SetArgPointee<3>(kExampleSourcePattern1),
+                         testing::SetArgPointee<4>(kFileManagerUrl),
+                         testing::SetArgPointee<5>(kRuleMetadata1),
+                         testing::Return(DlpRulesManager::Level::kWarn)));
+
+  files_controller_->IsFilesTransferRestricted(
+      /*task_id=*/1234, {file}, DlpFileDestination(GURL(kFileManagerUrl)),
+      dlp::FileAction::kTransfer, result_callback.Get());
+
+  files_controller_->IsFilesTransferRestricted(
+      /*task_id=*/1234, {file}, DlpFileDestination(GURL(kImageLoaderUrl)),
+      dlp::FileAction::kTransfer, result_callback.Get());
+}
+
 TEST_F(DlpFilesControllerAshTest, IsFilesTransferRestricted_MyFiles) {
   const auto histogram_tester = base::HistogramTester();
 
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
index 28e10b9..6c9d31a 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.cc
@@ -289,11 +289,12 @@
 };
 
 remoting::mojom::SupportSessionParamsPtr GetSessionParameters(
-    const SessionParameters& parameters) {
+    const SessionParameters& parameters,
+    std::string_view oauth_token) {
   auto result = remoting::mojom::SupportSessionParams::New();
   result->user_name = parameters.user_name;
   result->authorized_helper = parameters.admin_email;
-  result->oauth_access_token = parameters.oauth_token;
+  result->oauth_access_token = oauth_token;
 
   return result;
 }
@@ -400,8 +401,11 @@
 class CrdAdminSessionController::NewSessionLauncher : public SessionLauncher {
  public:
   NewSessionLauncher(RemotingServiceProxy& remoting_service,
+                     std::unique_ptr<CrdOAuthTokenFetcher> oauth_token_fetcher,
                      const SessionParameters& parameters)
-      : remoting_service_(remoting_service), parameters_(parameters) {}
+      : remoting_service_(remoting_service),
+        oauth_token_fetcher_(std::move(oauth_token_fetcher)),
+        parameters_(parameters) {}
 
   void Launch(SessionLaunchedCallback on_session_launched) override {
     on_session_launched_ = std::move(on_session_launched);
@@ -410,9 +414,23 @@
 
  private:
   void Start() {
+    CRD_VLOG(3) << "Fetching OAuth token for CRD session";
+    oauth_token_fetcher_->Start(base::BindOnce(
+        &NewSessionLauncher::ConnectToSession, weak_factory_.GetWeakPtr()));
+  }
+
+  void ConnectToSession(std::optional<std::string> oauth_token) {
+    if (!oauth_token.has_value()) {
+      CRD_LOG(WARNING) << "Failed to fetch OAuth token for CRD session";
+      ReportLaunchFailure(
+          ExtendedStartCrdSessionResultCode::kFailureNoOauthToken);
+      return;
+    }
+
     CRD_VLOG(3) << "Starting CRD session with parameters " << parameters_;
     remoting_service_->StartSession(
-        GetSessionParameters(parameters_), GetEnterpriseParameters(parameters_),
+        GetSessionParameters(parameters_, oauth_token.value()),
+        GetEnterpriseParameters(parameters_),
         base::BindOnce(&NewSessionLauncher::OnSessionStartResponse,
                        weak_factory_.GetWeakPtr()));
   }
@@ -439,6 +457,7 @@
 
   SessionLaunchedCallback on_session_launched_;
   raw_ref<RemotingServiceProxy> remoting_service_;
+  std::unique_ptr<CrdOAuthTokenFetcher> oauth_token_fetcher_;
   const SessionParameters parameters_;
 
   base::WeakPtrFactory<NewSessionLauncher> weak_factory_{this};
@@ -594,7 +613,7 @@
   oauth_token_for_test_ = token;
 }
 
-void CrdAdminSessionController::ClearOAuthTokenForTesting() {
+void CrdAdminSessionController::FailOAuthTokenFetchForTesting() {
   CHECK_IS_TEST();
   oauth_token_for_test_.reset();
 }
@@ -649,8 +668,10 @@
   active_session_->AddOwnedObserver(std::make_unique<SessionDurationObserver>(
       std::move(session_finished_callback)));
 
-  active_session_->Launch(
-      std::make_unique<NewSessionLauncher>(*remoting_service_, parameters));
+  active_session_->Launch(std::make_unique<NewSessionLauncher>(
+      *remoting_service_,
+      CreateOAuthTokenFetcher(GetOAuthService(), oauth_token_for_test_),
+      parameters));
 }
 
 std::unique_ptr<CrdAdminSessionController::CrdHostSession>
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.h b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.h
index 4f88ed4..6b5055e9 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller.h
@@ -86,7 +86,7 @@
   StartCrdSessionJobDelegate& GetDelegate();
 
   void SetOAuthTokenForTesting(std::string_view token);
-  void ClearOAuthTokenForTesting();
+  void FailOAuthTokenFetchForTesting();
 
  private:
   class CrdHostSession;
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
index 83476ea..f404c736 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_admin_session_controller_unittest.cc
@@ -408,6 +408,11 @@
   mojo::Remote<SupportHostObserver>& observer_remote() { return observer_; }
 
  private:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    session_controller().SetOAuthTokenForTesting("test-oauth-token");
+  }
+
   void TearDown() override {
     session_controller_.Shutdown();
     AshTestBase::TearDown();
@@ -431,14 +436,13 @@
       public testing::WithParamInterface<bool> {};
 
 TEST_F(CrdAdminSessionControllerTest, ShouldPassOAuthTokenToRemotingService) {
-  SessionParameters parameters;
-  parameters.oauth_token = "<the-oauth-token>";
+  session_controller().SetOAuthTokenForTesting("<the-oauth-token>");
 
   SupportSessionParamsPtr actual_parameters;
   EXPECT_CALL(remoting_service(), StartSession)
       .WillOnce(SaveParamAndInvokeCallback(&actual_parameters));
 
-  delegate().StartCrdHostAndGetCode(parameters, success_callback(),
+  delegate().StartCrdHostAndGetCode(SessionParameters{}, success_callback(),
                                     error_callback(),
                                     session_finished_callback());
 
@@ -605,6 +609,32 @@
   EXPECT_EQ("the-access-code", response.access_code());
 }
 
+TEST_F(CrdAdminSessionControllerTest,
+       ShouldStartSessionIfAccessCodeFetchSucceeds) {
+  session_controller().SetOAuthTokenForTesting("test-oauth-token");
+
+  StartCrdHostAndBindObserver();
+
+  EXPECT_TRUE(delegate().HasActiveSession());
+}
+
+TEST_F(CrdAdminSessionControllerTest, ShouldReportErrorIfAccessCodeFetchFails) {
+  session_controller().FailOAuthTokenFetchForTesting();
+
+  EXPECT_NO_CALLS(remoting_service(), StartSession);
+
+  delegate().StartCrdHostAndGetCode(SessionParameters{}, success_callback(),
+                                    error_callback(),
+                                    session_finished_callback());
+
+  Response response = WaitForResponse();
+  ASSERT_TRUE(response.HasError());
+  EXPECT_EQ(ExtendedStartCrdSessionResultCode::kFailureNoOauthToken,
+            response.result_code());
+
+  EXPECT_FALSE(delegate().HasActiveSession());
+}
+
 TEST_F(CrdAdminSessionControllerTest, ShouldReportErrorWhenClientDisconnects) {
   SupportHostObserver& observer = StartCrdHostAndBindObserver();
 
@@ -984,7 +1014,6 @@
       SessionId id = kValidSessionId) {
     EXPECT_CALL(remoting_service(), GetReconnectableSessionId)
         .WillOnce(ReplyWithSessionId(id));
-    controller.SetOAuthTokenForTesting("test-oauth-token");
     EXPECT_CALL(remoting_service(), ReconnectToSession)
         .WillOnce([&](remoting::SessionId, const std::string&,
                       StartSupportSessionCallback callback) {
@@ -1035,7 +1064,7 @@
        ShouldHandleOauthTokenFailureWhileReconnecting) {
   EnableFeature(kEnableCrdAdminRemoteAccessV2);
 
-  session_controller().ClearOAuthTokenForTesting();
+  session_controller().FailOAuthTokenFetchForTesting();
 
   // First we should query for the reconnectable session id.
   EXPECT_CALL(remoting_service(), GetReconnectableSessionId)
@@ -1148,7 +1177,7 @@
   EXPECT_CALL(remoting_service(), GetReconnectableSessionId)
       .WillOnce(ReplyWithSessionId(kValidSessionId));
 
-  session_controller().ClearOAuthTokenForTesting();
+  session_controller().FailOAuthTokenFetchForTesting();
 
   Init(session_controller());
   // The session is destroyed asynchronously.
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.cc b/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.cc
index 8143121..bcc4560 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.cc
@@ -130,9 +130,9 @@
 
 void SupportHostObserverProxy::ReportHostStopped(
     ExtendedStartCrdSessionResultCode result,
-    const std::string& error_message) {
+    std::string_view error_message) {
   for (auto& observer : observers_) {
-    observer.OnHostStopped(result, error_message);
+    observer.OnHostStopped(result, std::string{error_message});
   }
 }
 
diff --git a/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.h b/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.h
index 5f2430b..7e5103b 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/crd_support_host_observer_proxy.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/observer_list.h"
@@ -56,7 +57,7 @@
   void OnInvalidDomainError() override;
 
   void ReportHostStopped(ExtendedStartCrdSessionResultCode result,
-                         const std::string& error_message);
+                         std::string_view error_message);
 
  private:
   void OnMojomConnectionDropped();
diff --git a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
index d9ab944..cce78b8 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.cc
@@ -25,7 +25,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_logging.h"
-#include "chrome/browser/ash/policy/remote_commands/crd/crd_oauth_token_fetcher.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_uma_logger.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
@@ -131,17 +130,6 @@
   return DeviceOAuth2TokenServiceFactory::Get();
 }
 
-std::unique_ptr<CrdOAuthTokenFetcher> CreateOAuthTokenFetcher(
-    DeviceOAuth2TokenService* service,
-    std::optional<std::string> oauth_token_for_test) {
-  if (service) {
-    return std::make_unique<RealCrdOAuthTokenFetcher>(CHECK_DEREF(service));
-  } else {
-    CHECK_IS_TEST();
-    return std::make_unique<FakeCrdOAuthTokenFetcher>(oauth_token_for_test);
-  }
-}
-
 std::string GetRobotAccountUserName(const DeviceOAuth2TokenService* service) {
   CoreAccountId account_id = CHECK_DEREF(service).GetRobotAccountId();
 
@@ -184,11 +172,8 @@
 
 DeviceCommandStartCrdSessionJob::DeviceCommandStartCrdSessionJob(
     Delegate& delegate,
-    std::string_view robot_account_id,
-    std::optional<std::string> oauth_token)
-    : oauth_token_for_test_(oauth_token),
-      delegate_(delegate),
-      robot_account_id_(robot_account_id) {
+    std::string_view robot_account_id)
+    : delegate_(delegate), robot_account_id_(robot_account_id) {
   CHECK_IS_TEST();
 }
 
@@ -262,14 +247,9 @@
 
   // First perform managed network check,
   CheckManagedNetworkASync(
-      // Then fetch the OAuth token
-      base::BindOnce(
-          &DeviceCommandStartCrdSessionJob::FetchOAuthTokenASync,
-          weak_factory_.GetWeakPtr(),
-          // And finally start the CRD host.
-          base::BindOnce(
-              &DeviceCommandStartCrdSessionJob::StartCrdHostAndGetCode,
-              weak_factory_.GetWeakPtr())));
+      // Then start the CRD host.
+      base::BindOnce(&DeviceCommandStartCrdSessionJob::StartCrdHostAndGetCode,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void DeviceCommandStartCrdSessionJob::CheckManagedNetworkASync(
@@ -295,25 +275,9 @@
       std::move(on_success), GetErrorCallback()));
 }
 
-void DeviceCommandStartCrdSessionJob::FetchOAuthTokenASync(
-    OAuthTokenCallback done_callback) {
-  DCHECK_EQ(oauth_token_fetcher_, nullptr);
-
-  oauth_token_fetcher_ =
-      CreateOAuthTokenFetcher(GetOAuthService(), oauth_token_for_test_);
-  oauth_token_fetcher_->Start(std::move(done_callback));
-}
-
-void DeviceCommandStartCrdSessionJob::StartCrdHostAndGetCode(
-    std::optional<std::string> oauth_token) {
-  if (!oauth_token.has_value()) {
-    return FinishWithError(
-        ExtendedStartCrdSessionResultCode::kFailureNoOauthToken, "");
-  }
-
-  CRD_VLOG(1) << "Received OAuth token, now retrieving CRD access code";
+void DeviceCommandStartCrdSessionJob::StartCrdHostAndGetCode() {
+  CRD_VLOG(1) << "Starting CRD host and retrieving CRD access code";
   SessionParameters parameters;
-  parameters.oauth_token = std::move(oauth_token).value();
   parameters.user_name = robot_account_id_;
   parameters.terminate_upon_input = ShouldTerminateUponInput();
   parameters.show_confirmation_dialog = ShouldShowConfirmationDialog();
diff --git a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.h b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.h
index 461cf4c..44ff935 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_DEVICE_COMMAND_START_CRD_SESSION_JOB_H_
 #define CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_CRD_DEVICE_COMMAND_START_CRD_SESSION_JOB_H_
 
-#include <memory>
 #include <optional>
 #include <string>
 #include <string_view>
@@ -20,8 +19,6 @@
 
 namespace policy {
 
-class CrdOAuthTokenFetcher;
-
 // Remote command that would start Chrome Remote Desktop host and return auth
 // code. This command is usable only for devices running Kiosk sessions, for
 // Affiliated Users and for Managed Guest Sessions.
@@ -32,11 +29,8 @@
   explicit DeviceCommandStartCrdSessionJob(Delegate& delegate);
   // Constructor used in unit tests. By using this constructor we avoid the need
   // for a `DeviceOAuth2TokenService` to exist.
-  // `oauth_token` will be used as the fetched OAuth token (or the fetch will
-  // fail if no value is provided).
   DeviceCommandStartCrdSessionJob(Delegate& delegate,
-                                  std::string_view robot_account_id,
-                                  std::optional<std::string> oauth_token);
+                                  std::string_view robot_account_id);
   ~DeviceCommandStartCrdSessionJob() override;
 
   DeviceCommandStartCrdSessionJob(const DeviceCommandStartCrdSessionJob&) =
@@ -51,12 +45,8 @@
   void TerminateImpl() override;
 
  private:
-  using OAuthTokenCallback =
-      base::OnceCallback<void(std::optional<std::string>)>;
-
   void CheckManagedNetworkASync(base::OnceClosure on_success);
-  void FetchOAuthTokenASync(OAuthTokenCallback done_callback);
-  void StartCrdHostAndGetCode(std::optional<std::string> oauth_token);
+  void StartCrdHostAndGetCode();
   void FinishWithSuccess(const std::string& access_code);
   // Finishes command with error code and optional message.
   void FinishWithError(ExtendedStartCrdSessionResultCode result_code,
@@ -76,8 +66,6 @@
 
   Delegate::ErrorCallback GetErrorCallback();
 
-  std::unique_ptr<CrdOAuthTokenFetcher> oauth_token_fetcher_;
-
   // The callback that will be called when the access code was successfully
   // obtained or when this command failed.
   CallbackWithResult result_callback_;
@@ -99,10 +87,6 @@
 
   // -- End of command parameters --
 
-  // Fake OAuth token that will be used once the next time we need to fetch an
-  // oauth token.
-  std::optional<std::string> oauth_token_for_test_;
-
   // The Delegate is used to interact with chrome services and CRD host.
   const raw_ref<Delegate> delegate_;
 
diff --git a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
index 5e74da9..5cf98924 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/device_command_start_crd_session_job_unittest.cc
@@ -21,8 +21,8 @@
 #include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h"
 #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/crd_remote_command_utils.h"
-#include "chrome/browser/ash/policy/remote_commands/fake_cros_network_config.h"
 #include "chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h"
+#include "chrome/browser/ash/policy/remote_commands/fake_cros_network_config.h"
 #include "chrome/browser/ash/policy/remote_commands/user_session_type_test_util.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/browser/prefs/browser_prefs.h"
@@ -60,7 +60,6 @@
 
 constexpr RemoteCommandJob::UniqueIDType kUniqueID = 123456789;
 
-constexpr char kTestOAuthToken[] = "test-oauth-token";
 // Common template used in all UMA histograms for session result logs.
 constexpr char kHistogramResultTemplate[] =
     "Enterprise.DeviceRemoteCommand.Crd.%s.%s.Result";
@@ -268,19 +267,14 @@
     user_activity_detector_->set_last_activity_time_for_test(value);
   }
 
-  void SetOAuthToken(std::string_view value) { oauth_token_ = value; }
-
   void SetRobotAccountUserName(std::string_view user_name) {
     robot_account_id_ = user_name;
   }
 
-  void ClearOAuthToken() { oauth_token_ = std::nullopt; }
-
   FakeStartCrdSessionJobDelegate& delegate() { return delegate_; }
 
   DeviceCommandStartCrdSessionJob CreateJob() {
-    return DeviceCommandStartCrdSessionJob{delegate_, robot_account_id_,
-                                           oauth_token_};
+    return DeviceCommandStartCrdSessionJob{delegate_, robot_account_id_};
   }
 
   Result RunJobAndWaitForResult(const Payload& payload = Payload()) {
@@ -343,7 +337,6 @@
 
   // Parameters passed to the constructor of `DeviceCommandStartCrdSessionJob`
   // when the job is created.
-  std::optional<std::string> oauth_token_ = kTestOAuthToken;
   std::string robot_account_id_ = "robot@account.com";
 
   // Automatically installed as a singleton upon creation.
@@ -397,15 +390,6 @@
 }
 
 TEST_F(DeviceCommandStartCrdSessionJobTest,
-       ShouldSucceedIfAccessTokenCanBeFetched) {
-  LogInAsKioskUser();
-
-  SetOAuthToken(kTestOAuthToken);
-
-  EXPECT_SUCCESS(RunJobAndWaitForResult());
-}
-
-TEST_F(DeviceCommandStartCrdSessionJobTest,
        ShouldTerminateActiveSessionAndThenSucceed) {
   LogInAsKioskUser();
 
@@ -509,32 +493,16 @@
                StartCrdSessionResultCode::FAILURE_UNSUPPORTED_USER_TYPE);
 }
 
-TEST_F(DeviceCommandStartCrdSessionJobTest,
-       ShouldFailIfWeCantFetchTheOAuthToken) {
-  LogInAsKioskUser();
-  ClearOAuthToken();
-
-  EXPECT_ERROR(RunJobAndWaitForResult(),
-               StartCrdSessionResultCode::FAILURE_NO_OAUTH_TOKEN, "");
-}
-
 TEST_F(DeviceCommandStartCrdSessionJobTest, ShouldFailIfCrdHostReportsAnError) {
   LogInAsKioskUser();
 
-  delegate().MakeAccessCodeFetchFail();
+  delegate().FailWithError(
+      ExtendedStartCrdSessionResultCode::kFailureCrdHostError);
 
   EXPECT_ERROR(RunJobAndWaitForResult(),
                StartCrdSessionResultCode::FAILURE_CRD_HOST_ERROR);
 }
 
-TEST_F(DeviceCommandStartCrdSessionJobTest, ShouldPassOAuthTokenToDelegate) {
-  LogInAsKioskUser();
-  SetOAuthToken("the-oauth-token");
-
-  EXPECT_SUCCESS(RunJobAndWaitForResult());
-  EXPECT_EQ("the-oauth-token", delegate().session_parameters().oauth_token);
-}
-
 TEST_F(DeviceCommandStartCrdSessionJobTest,
        ShouldPassRobotAccountNameToDelegate) {
   LogInAsKioskUser();
@@ -816,7 +784,8 @@
   base::HistogramTester histogram_tester;
   LogInAsKioskUser();
 
-  ClearOAuthToken();
+  delegate().FailWithError(
+      ExtendedStartCrdSessionResultCode::kFailureNoOauthToken);
   RunJobAndWaitForResult();
 
   histogram_tester.ExpectUniqueSample(
@@ -834,7 +803,9 @@
   base::HistogramTester histogram_tester;
   LogInAsKioskUser();
 
-  delegate().MakeAccessCodeFetchFail();
+  delegate().FailWithError(
+      ExtendedStartCrdSessionResultCode::kFailureCrdHostError);
+
   RunJobAndWaitForResult();
 
   histogram_tester.ExpectUniqueSample(
diff --git a/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.cc b/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.cc
index 9125454..76c38d80 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.cc
+++ b/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.cc
@@ -45,12 +45,11 @@
   received_session_parameters_ = parameters;
   session_finished_callback_ = std::move(session_finished_callback);
 
-  if (access_code_success_) {
-    std::move(success_callback).Run(kTestAccessCode);
+  if (error_) {
+    std::move(error_callback).Run(error_.value(), "");
+    error_.reset();
   } else {
-    std::move(error_callback)
-        .Run(ExtendedStartCrdSessionResultCode::kFailureCrdHostError,
-             std::string());
+    std::move(success_callback).Run(kTestAccessCode);
   }
 }
 
diff --git a/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h b/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h
index 2845104..9f60195 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/fake_start_crd_session_job_delegate.h
@@ -20,7 +20,9 @@
   ~FakeStartCrdSessionJobDelegate() override;
 
   void SetHasActiveSession(bool value) { has_active_session_ = value; }
-  void MakeAccessCodeFetchFail() { access_code_success_ = false; }
+  void FailWithError(ExtendedStartCrdSessionResultCode error) {
+    error_ = error;
+  }
   void TerminateCrdSession(const base::TimeDelta& session_duration);
 
   // Returns if TerminateSession() was called to terminate the active session.
@@ -41,8 +43,8 @@
 
  private:
   bool has_active_session_ = false;
-  bool access_code_success_ = true;
   bool terminate_session_called_ = false;
+  std::optional<ExtendedStartCrdSessionResultCode> error_;
   std::optional<SessionParameters> received_session_parameters_;
   std::optional<SessionEndCallback> session_finished_callback_;
 };
diff --git a/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h b/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
index 637e3ab..bea2092 100644
--- a/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
+++ b/chrome/browser/ash/policy/remote_commands/crd/start_crd_session_job_delegate.h
@@ -34,7 +34,6 @@
     SessionParameters(SessionParameters&&);
     SessionParameters& operator=(SessionParameters&&);
 
-    std::string oauth_token = "";
     std::string user_name = "";
     std::optional<std::string> admin_email;
     bool terminate_upon_input = false;
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 3074b63..3efbcb2b 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -658,7 +658,7 @@
   AutofillProfile::CreateInferredLabels(
       std::vector<const AutofillProfile*>(profiles.begin(), profiles.end()),
       address_only ? absl::make_optional(suggested_fields) : absl::nullopt,
-      excluded_field, minimal_fields_shown,
+      {excluded_field}, minimal_fields_shown,
       g_browser_process->GetApplicationLocale(), &labels);
 
   return base::android::ToJavaArrayOfStrings(env, labels);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index d524249..16e58312d 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -676,8 +676,12 @@
       variations::VariationsIdsProvider::GetInstance());
   metrics->GetSyntheticTrialRegistry()->AddObserver(
       variations::SyntheticTrialsActiveGroupIdProvider::GetInstance());
+  // TODO(crbug.com/1505638): Investiagte the reason why the mojo connection
+  // is often created and closed for the same render process on lacros-chrome.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
   synthetic_trial_syncer_ = content::SyntheticTrialSyncer::Create(
       metrics->GetSyntheticTrialRegistry());
+#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
   // Now that field trials have been created, initializes metrics recording.
   metrics->InitializeMetricsRecordingState();
 
diff --git a/chrome/browser/download/save_package_file_picker.cc b/chrome/browser/download/save_package_file_picker.cc
index 6e58edf..56fc2de 100644
--- a/chrome/browser/download/save_package_file_picker.cc
+++ b/chrome/browser/download/save_package_file_picker.cc
@@ -222,7 +222,11 @@
         ui::SelectFileDialog::SELECT_SAVEAS_FILE, std::u16string(),
         suggested_path_copy, &file_type_info, file_type_index,
         default_extension_copy,
-        platform_util::GetTopLevel(web_contents->GetNativeView()), nullptr);
+        platform_util::GetTopLevel(web_contents->GetNativeView()),
+        /*params=*/nullptr, /*caller=*/
+        web_contents
+            ? &web_contents->GetPrimaryMainFrame()->GetLastCommittedURL()
+            : nullptr);
     return;
   }
 
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 17e3b3e..65ac6f0 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -1732,6 +1732,7 @@
   auto request = std::get<0>(add_file_cb.Take());
   EXPECT_EQ(1, request.add_file_requests().size());
   EXPECT_EQ(full_file_name.value(), request.add_file_requests(0).file_path());
+  EXPECT_EQ(request.add_file_requests(0).source_url(), url.spec());
 
   base::ScopedAllowBlockingForTesting allow_blocking;
   EXPECT_TRUE(base::PathExists(full_file_name));
@@ -1760,6 +1761,7 @@
   auto request = std::get<0>(add_file_cb.Take());
   EXPECT_EQ(1, request.add_file_requests().size());
   EXPECT_EQ(full_file_name.value(), request.add_file_requests(0).file_path());
+  EXPECT_EQ(request.add_file_requests(0).source_url(), url.spec());
 
   base::ScopedAllowBlockingForTesting allow_blocking;
   EXPECT_TRUE(base::PathExists(full_file_name));
diff --git a/chrome/browser/extensions/api/printing/printing_test_utils.cc b/chrome/browser/extensions/api/printing/printing_test_utils.cc
index cf5da7c..977764482 100644
--- a/chrome/browser/extensions/api/printing/printing_test_utils.cc
+++ b/chrome/browser/extensions/api/printing/printing_test_utils.cc
@@ -218,6 +218,7 @@
 ConstructPrinterCapabilities() {
   auto capabilities =
       std::make_unique<printing::PrinterSemanticCapsAndDefaults>();
+  capabilities->bw_model = printing::mojom::ColorModel::kGray;
   capabilities->color_model = printing::mojom::ColorModel::kColor;
   capabilities->duplex_default = printing::mojom::DuplexMode::kSimplex;
   capabilities->duplex_modes.push_back(printing::mojom::DuplexMode::kSimplex);
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 7bd394b3..86928ba 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -538,9 +538,6 @@
   features.Append(GenerateFeatureFlag(
       "japanesefunctionrow",
       base::FeatureList::IsEnabled(ash::features::kJapaneseFunctionRow)));
-  features.Append(GenerateFeatureFlag(
-      "virtualkeyboardremovenacl",
-      base::FeatureList::IsEnabled(ash::features::kVirtualKeyboardRemoveNacl)));
 
   results.Set("features", std::move(features));
 
diff --git a/chrome/browser/lacros/browser_test_util.cc b/chrome/browser/lacros/browser_test_util.cc
index 77ac9f30..d38b898d 100644
--- a/chrome/browser/lacros/browser_test_util.cc
+++ b/chrome/browser/lacros/browser_test_util.cc
@@ -61,9 +61,11 @@
 }
 
 bool WaitForWindow(const std::string& id, bool exists) {
-  CHECK(IsTestControllerAvailable(
-      crosapi::mojom::TestController::MethodMinVersions::
-          kDoesWindowExistMinVersion));
+  if (!IsTestControllerAvailable(
+          crosapi::mojom::TestController::MethodMinVersions::
+              kDoesWindowExistMinVersion)) {
+    return false;
+  }
   base::RunLoop outer_loop;
   bool actual_exists = false;
   auto wait_for_window = base::BindRepeating(
@@ -95,9 +97,11 @@
 }
 
 bool WaitForElement(const std::string& id, bool exists) {
-  CHECK(IsTestControllerAvailable(
-      crosapi::mojom::TestController::MethodMinVersions::
-          kDoesElementExistMinVersion));
+  if (!IsTestControllerAvailable(
+          crosapi::mojom::TestController::MethodMinVersions::
+              kDoesElementExistMinVersion)) {
+    return false;
+  }
   base::RunLoop outer_loop;
   bool actual_exists = false;
   auto wait_for_element = base::BindRepeating(
@@ -143,9 +147,11 @@
 }
 
 bool WaitForShelfItem(const std::string& id, bool exists) {
-  CHECK(IsTestControllerAvailable(
-      crosapi::mojom::TestController::MethodMinVersions::
-          kDoesItemExistInShelfMinVersion));
+  if (!IsTestControllerAvailable(
+          crosapi::mojom::TestController::MethodMinVersions::
+              kDoesItemExistInShelfMinVersion)) {
+    return false;
+  }
   base::RunLoop outer_loop;
   bool actual_exists = false;
   auto wait_for_shelf_item = base::BindRepeating(
@@ -220,9 +226,11 @@
 // |window|. The AuraObserver only waits for the up-event to start processing
 // before quitting the run loop.
 bool SendAndWaitForMouseClick(aura::Window* window) {
-  CHECK(
-      IsTestControllerAvailable(crosapi::mojom::TestController::
-                                    MethodMinVersions::kClickWindowMinVersion));
+  if (!IsTestControllerAvailable(
+          crosapi::mojom::TestController::MethodMinVersions::
+              kClickWindowMinVersion)) {
+    return false;
+  }
   DCHECK(window->IsRootWindow());
   std::string id = lacros_window_utility::GetRootWindowUniqueId(window);
 
diff --git a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.cc
index c534478..410f0b4 100644
--- a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.cc
@@ -24,6 +24,12 @@
 
 #define HISTOGRAM_PREFIX "PageLoad.Clients.GoogleSearch."
 
+const char kHistogramGWSNavigationStartToFinalRequestStart[] =
+    HISTOGRAM_PREFIX "NavigationTiming.NavigationStartToFinalRequestStart";
+const char kHistogramGWSNavigationStartToFinalResponseStart[] =
+    HISTOGRAM_PREFIX "NavigationTiming.NavigationStartToFinalResponseStart";
+const char kHistogramGWSNavigationStartToFinalLoaderCallback[] =
+    HISTOGRAM_PREFIX "NavigationTiming.NavigationStartToFinalLoaderCallback";
 const char kHistogramGWSNavigationStartToFirstRequestStart[] =
     HISTOGRAM_PREFIX "NavigationTiming.NavigationStartToFirstRequestStart";
 const char kHistogramGWSNavigationStartToFirstResponseStart[] =
@@ -148,4 +154,12 @@
   PAGE_LOAD_HISTOGRAM(
       internal::kHistogramGWSNavigationStartToFirstLoaderCallback,
       timing.first_loader_callback_time - navigation_start_time);
+  PAGE_LOAD_HISTOGRAM(internal::kHistogramGWSNavigationStartToFinalRequestStart,
+                      timing.final_request_start_time - navigation_start_time);
+  PAGE_LOAD_HISTOGRAM(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart,
+      timing.final_response_start_time - navigation_start_time);
+  PAGE_LOAD_HISTOGRAM(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback,
+      timing.final_loader_callback_time - navigation_start_time);
 }
diff --git a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.h
index c4d867f..feef11b 100644
--- a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer.h
@@ -12,6 +12,9 @@
 namespace internal {
 // Exposed for tests.
 
+extern const char kHistogramGWSNavigationStartToFinalRequestStart[];
+extern const char kHistogramGWSNavigationStartToFinalResponseStart[];
+extern const char kHistogramGWSNavigationStartToFinalLoaderCallback[];
 extern const char kHistogramGWSNavigationStartToFirstRequestStart[];
 extern const char kHistogramGWSNavigationStartToFirstResponseStart[];
 extern const char kHistogramGWSNavigationStartToFirstLoaderCallback[];
diff --git a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer_unittest.cc
index 9abc8e1..9fcde9e7d 100644
--- a/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/gws_page_load_metrics_observer_unittest.cc
@@ -85,6 +85,18 @@
   tester()->histogram_tester().ExpectBucketCount(
       internal::kHistogramGWSNavigationStartToFirstLoaderCallback, 1, 1);
   tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 1, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 1, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 1, 1);
+  tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSParseStart, 1);
   tester()->histogram_tester().ExpectBucketCount(
       internal::kHistogramGWSParseStart, 1, 1);
@@ -121,6 +133,12 @@
   tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSNavigationStartToFirstLoaderCallback, 0);
   tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 0);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 0);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 0);
+  tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSParseStart, 0);
   tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSFirstContentfulPaint, 0);
@@ -152,6 +170,12 @@
   tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSNavigationStartToFirstLoaderCallback, 0);
   tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 0);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 0);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 0);
+  tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSParseStart, 0);
   tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSFirstContentfulPaint, 0);
@@ -192,6 +216,18 @@
   tester()->histogram_tester().ExpectBucketCount(
       internal::kHistogramGWSNavigationStartToFirstLoaderCallback, 0, 1);
   tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalRequestStart, 0, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalResponseStart, 0, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramGWSNavigationStartToFinalLoaderCallback, 0, 1);
+  tester()->histogram_tester().ExpectTotalCount(
       internal::kHistogramGWSParseStart, 1);
   tester()->histogram_tester().ExpectBucketCount(
       internal::kHistogramGWSParseStart, 0, 1);
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
index 44fce061..c072793 100644
--- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h"
 
+#include "base/trace_event/base_tracing.h"
 #include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
 #include "chrome/browser/predictors/predictors_features.h"
@@ -205,6 +206,35 @@
 }
 
 void LcpCriticalPathPredictorPageLoadMetricsObserver::
+    AppendFetchedSubresourceUrl(const GURL& subresource_url,
+                                const base::TimeDelta& subresource_load_start) {
+  if (!lcpp_data_inputs_) {
+    lcpp_data_inputs_.emplace();
+  }
+  if (lcpp_data_inputs_->subresource_urls.empty()) {
+    base::UmaHistogramMediumTimes(
+        "Blink.LCPP.NavigationToStartPreload.MainFrame.FirstSubresource.Time",
+        subresource_load_start);
+    const base::TimeTicks navigation_start = GetDelegate().GetNavigationStart();
+    TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
+        "loading", "NavigationToStartFirstPreload", TRACE_ID_LOCAL(this),
+        navigation_start, "url", subresource_url);
+    TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
+        "loading", "NavigationToStartFirstPreload", TRACE_ID_LOCAL(this),
+        navigation_start + subresource_load_start);
+  }
+  base::UmaHistogramMediumTimes(
+      "Blink.LCPP.NavigationToStartPreload.MainFrame.EachSubresource.Time",
+      subresource_load_start);
+  if (!lcpp_data_inputs_->subresource_urls.contains(subresource_url)) {
+    lcpp_data_inputs_->subresource_urls.emplace(subresource_url,
+                                                subresource_load_start);
+  }
+  // TODO(https://crbug.com/1501673): Save subresource_urls into the LCPP
+  // database.
+}
+
+void LcpCriticalPathPredictorPageLoadMetricsObserver::
     SetLcpInfluencerScriptUrls(
         const std::vector<GURL>& lcp_influencer_scripts) {
   if (!lcpp_data_inputs_) {
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
index 337389a..7e1495f 100644
--- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
@@ -85,6 +85,9 @@
       const std::vector<GURL>& lcp_influencer_scripts);
   // Append fetched font URLs to the list to be passed to LCPP.
   void AppendFetchedFontUrl(const GURL& font_url);
+  void AppendFetchedSubresourceUrl(
+      const GURL& subresource_url,
+      const base::TimeDelta& subresource_load_start);
 
  private:
   // PageLoadMetricsObserver implementation:
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
index 74b1905f..4304d2b 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
@@ -99,4 +99,48 @@
   plmo->AppendFetchedFontUrl(font_url);
 }
 
+void LCPCriticalPathPredictorHost::NotifyFetchedSubresource(
+    const GURL& subresource_url,
+    base::TimeDelta subresource_load_start) {
+  if (!base::FeatureList::IsEnabled(
+          blink::features::kHttpDiskCachePrewarming)) {
+    ReportBadMessageAndDeleteThis(
+        "NotifyFetchedSubresource can be called "
+        "only if kHttpDiskCachePrewarming is enabled.");
+    return;
+  }
+  if (!subresource_url.SchemeIsHTTPOrHTTPS()) {
+    ReportBadMessageAndDeleteThis("url scheme must be HTTP or HTTPS.");
+    return;
+  }
+  if (subresource_load_start.is_negative()) {
+    ReportBadMessageAndDeleteThis(
+        "subresource load start must not be negative value.");
+    return;
+  }
+  static size_t max_url_length = base::checked_cast<size_t>(
+      blink::features::kHttpDiskCachePrewarmingMaxUrlLength.Get());
+  if (subresource_url.spec().length() > max_url_length) {
+    // The size can be different between KURL and GURL, not reporting
+    // bad message.
+    return;
+  }
+  // Due to an unresolved bug (crbug.com/1335845), GetForPage can return
+  // nullptr.
+  auto* page_data =
+      LcpCriticalPathPredictorPageLoadMetricsObserver::PageData::GetForPage(
+          render_frame_host().GetPage());
+  if (!page_data) {
+    return;
+  }
+  // `LcpCriticalPathPredictorPageLoadMetricsObserver::OnCommit()` stores
+  // `LcpCriticalPathPredictorPageLoadMetricsObserver` in `PageData` as a weak
+  // pointer. This weak pointer can be deleted at any time.
+  auto* plmo = page_data->GetLcpCriticalPathPredictorPageLoadMetricsObserver();
+  if (!plmo) {
+    return;
+  }
+  plmo->AppendFetchedSubresourceUrl(subresource_url, subresource_load_start);
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
index 34af374..1614834 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
@@ -45,6 +45,9 @@
   void SetLcpInfluencerScriptUrls(
       const std::vector<GURL>& lcp_influencer_scripts) override;
   void NotifyFetchedFont(const GURL& font_url) override;
+  void NotifyFetchedSubresource(
+      const GURL& subresource_url,
+      base::TimeDelta subresource_load_start) override;
 };
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h
index 3307bff..3af1326 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h
@@ -50,6 +50,10 @@
   // This field keeps the number of font URLs without omitting due to
   // reaching `kLCPPFontURLPredictorMaxUrlCountPerOrigin` or deduplication.
   size_t font_url_count = 0;
+  // This field keeps the subresource URLs as a key, and the TimeDelta as a
+  // value. TimeDelta stores the duration from navigation start to resource
+  // loading start time.
+  std::map<GURL, base::TimeDelta> subresource_urls;
 };
 
 bool UpdateLcppDataWithLcppDataInputs(const LoadingPredictorConfig& config,
diff --git a/chrome/browser/printing/web_api/web_printing_browsertest.cc b/chrome/browser/printing/web_api/web_printing_browsertest.cc
index 219ae75e7..5dec9b6 100644
--- a/chrome/browser/printing/web_api/web_printing_browsertest.cc
+++ b/chrome/browser/printing/web_api/web_printing_browsertest.cc
@@ -236,6 +236,8 @@
       "separate-documents-uncollated-copies",
       "separate-documents-collated-copies"
     ],
+    "printColorModeDefault": "monochrome",
+    "printColorModeSupported": [ "monochrome", "color" ],
     "printerName": "name",
     "sidesDefault": "one-sided",
     "sidesSupported": [ "one-sided" ]
diff --git a/chrome/browser/printing/web_api/web_printing_mojom_traits.cc b/chrome/browser/printing/web_api/web_printing_mojom_traits.cc
index 14c5a32..4155a9c 100644
--- a/chrome/browser/printing/web_api/web_printing_mojom_traits.cc
+++ b/chrome/browser/printing/web_api/web_printing_mojom_traits.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/bindings/type_converter.h"
+#include "printing/mojom/print.mojom-shared.h"
 #include "third_party/blink/public/mojom/printing/web_printing.mojom.h"
 
 namespace mojo {
@@ -18,6 +19,26 @@
 // multiple-document-handling:
 using MultipleDocumentHandling =
     blink::mojom::WebPrintingMultipleDocumentHandling;
+
+// print-color-mode:
+using PrintColorMode = blink::mojom::WebPrintColorMode;
+using printing::mojom::ColorModel;
+
+// This is not typemapped via EnumTraits<> due to issues with handling `auto`
+// PrintColorMode (which doesn't represent a color model and hence has to be
+// processed separately).
+// As for specializing a TypeConverter<> -- since this function is not exposed
+// publicly, we'd like to avoid potential ODR violations if someone decides to
+// implement a converter between these two types elsewhere.
+ColorModel PrintColorModeToColorModel(PrintColorMode print_color_mode) {
+  switch (print_color_mode) {
+    case PrintColorMode::kColor:
+      return ColorModel::kColorModeColor;
+    case PrintColorMode::kMonochrome:
+      return ColorModel::kColorModeMonochrome;
+  }
+}
+
 }  // namespace
 
 // static
@@ -86,6 +107,9 @@
         break;
     }
   }
+  if (auto print_color_mode = data.print_color_mode()) {
+    settings->set_color(PrintColorModeToColorModel(*print_color_mode));
+  }
 
   *out = std::move(settings);
   return true;
diff --git a/chrome/browser/printing/web_api/web_printing_mojom_traits.h b/chrome/browser/printing/web_api/web_printing_mojom_traits.h
index 46bab93..03589a2 100644
--- a/chrome/browser/printing/web_api/web_printing_mojom_traits.h
+++ b/chrome/browser/printing/web_api/web_printing_mojom_traits.h
@@ -48,6 +48,10 @@
       const std::unique_ptr<printing::PrintSettings>& ptr) {
     NOTREACHED_NORETURN();
   }
+  static const std::optional<blink::mojom::WebPrintColorMode>& print_color_mode(
+      const std::unique_ptr<printing::PrintSettings>& ptr) {
+    NOTREACHED_NORETURN();
+  }
   static const std::optional<blink::mojom::WebPrintingSides>& sides(
       const std::unique_ptr<printing::PrintSettings>& ptr) {
     NOTREACHED_NORETURN();
diff --git a/chrome/browser/printing/web_api/web_printing_service_chromeos.cc b/chrome/browser/printing/web_api/web_printing_service_chromeos.cc
index df17d0996..093f66f 100644
--- a/chrome/browser/printing/web_api/web_printing_service_chromeos.cc
+++ b/chrome/browser/printing/web_api/web_printing_service_chromeos.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "printing/backend/print_backend.h"
 #include "printing/metafile_skia.h"
+#include "printing/print_settings.h"
 #include "printing/printed_document.h"
 
 namespace printing {
@@ -35,6 +36,14 @@
   return response ? response->capabilities : std::nullopt;
 }
 
+bool IsDuplexModeKnown(mojom::DuplexMode duplex_mode) {
+  return duplex_mode != mojom::DuplexMode::kUnknownDuplexMode;
+}
+
+bool IsColorModelKnown(mojom::ColorModel color_model) {
+  return color_model != mojom::ColorModel::kUnknownColorModel;
+}
+
 bool ValidatePrintJobTemplateAttributesAgainstPrinterAttributes(
     const PrintSettings& pjt_attributes,
     const PrinterSemanticCapsAndDefaults& printer_attributes) {
@@ -45,14 +54,37 @@
   if (pjt_attributes.collate() && !printer_attributes.collate_capable) {
     return false;
   }
-  if (pjt_attributes.duplex_mode() != mojom::DuplexMode::kUnknownDuplexMode &&
+  // Checks that printer supports color printing if requested so.
+  if (IsColorModelKnown(pjt_attributes.color()) &&
+      ::printing::IsColorModelSelected(pjt_attributes.color()).value() &&
+      !IsColorModelKnown(printer_attributes.color_model)) {
+    return false;
+  }
+  if (IsDuplexModeKnown(pjt_attributes.duplex_mode()) &&
       !base::Contains(printer_attributes.duplex_modes,
                       pjt_attributes.duplex_mode())) {
     return false;
   }
+  if (!IsDuplexModeKnown(pjt_attributes.duplex_mode()) &&
+      !IsDuplexModeKnown(printer_attributes.duplex_default)) {
+    return false;
+  }
   return true;
 }
 
+void UpdatePrintJobTemplateAttributesWithPrinterDefaults(
+    PrintSettings* pjt_attributes,
+    const PrinterSemanticCapsAndDefaults& printer_attributes) {
+  if (!IsDuplexModeKnown(pjt_attributes->duplex_mode())) {
+    pjt_attributes->set_duplex_mode(printer_attributes.duplex_default);
+  }
+  if (!IsColorModelKnown(pjt_attributes->color())) {
+    pjt_attributes->set_color(printer_attributes.color_default
+                                  ? mojom::ColorModel::kColorModeColor
+                                  : mojom::ColorModel::kColorModeMonochrome);
+  }
+}
+
 }  // namespace
 
 WebPrintingServiceChromeOS::WebPrintingServiceChromeOS(
@@ -129,6 +161,9 @@
         blink::mojom::WebPrintError::kPrintJobTemplateAttributesMismatch));
     return;
   }
+  // Update selected fields to printer defaults if they're not specified.
+  UpdatePrintJobTemplateAttributesWithPrinterDefaults(pjt_attributes.get(),
+                                                      *printer_attributes);
 
   pdf_flattener_->ReadAndFlattenPdf(
       std::move(document),
diff --git a/chrome/browser/printing/web_api/web_printing_type_converters.cc b/chrome/browser/printing/web_api/web_printing_type_converters.cc
index d6d4b41a..ded030c2 100644
--- a/chrome/browser/printing/web_api/web_printing_type_converters.cc
+++ b/chrome/browser/printing/web_api/web_printing_type_converters.cc
@@ -57,6 +57,19 @@
   }
 }
 
+void ProcessPrintColorMode(const PrinterSemanticCapsAndDefaults& caps,
+                           blink::mojom::WebPrinterAttributes* attributes) {
+  attributes->print_color_mode_default =
+      caps.color_default ? blink::mojom::WebPrintColorMode::kColor
+                         : blink::mojom::WebPrintColorMode::kMonochrome;
+  attributes->print_color_mode_supported.push_back(
+      blink::mojom::WebPrintColorMode::kMonochrome);
+  if (caps.color_model != mojom::ColorModel::kUnknownColorModel) {
+    attributes->print_color_mode_supported.push_back(
+        blink::mojom::WebPrintColorMode::kColor);
+  }
+}
+
 void ProcessSides(const PrinterSemanticCapsAndDefaults& caps,
                   blink::mojom::WebPrinterAttributes* attributes) {
   if (caps.duplex_default != mojom::DuplexMode::kUnknownDuplexMode) {
@@ -74,7 +87,6 @@
                                        attributes->sides_supported)) {
     attributes->sides_default.reset();
     attributes->sides_supported.clear();
-    return;
   }
 }
 
@@ -91,6 +103,7 @@
 
   printing::ProcessCopies(capabilities, attributes.get());
   printing::ProcessMultipleDocumentHandling(capabilities, attributes.get());
+  printing::ProcessPrintColorMode(capabilities, attributes.get());
   printing::ProcessSides(capabilities, attributes.get());
 
   return attributes;
diff --git a/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts b/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
index a6d6748..d8a7f14 100644
--- a/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
+++ b/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
@@ -78,7 +78,7 @@
     const installButton = this.$<CrButtonElement>('.install-button')!;
     assert(installButton);
     installButton.addEventListener(
-        'click', this.onInstallButtonClick.bind(this));
+        'click', this.onInstallButtonClick.bind(this), {once: true});
   }
 
   private onCancelButtonClick(): void {
@@ -100,17 +100,25 @@
       new Promise(resolve => setTimeout(resolve, 2000)),
     ]);
 
+    installButton.disabled = false;
     if (install_result) {
       // TODO(crbug.com/1488697): Localize string.
       installButton.textContent = 'Open app';
       installButton.classList.replace('installing', 'installed');
+      installButton.addEventListener(
+          'click', this.onOpenAppButtonClick.bind(this));
     } else {
-      // TODO(crbug.com/1488697): Proper error display.
+      // TODO(crbug.com/1488697): Proper error display and/or allow install to
+      // be attempted again.
       installButton.textContent = loadTimeData.getString('install');
       installButton.classList.replace('installing', 'install');
-      installButton.disabled = false;
     }
   }
+
+  private async onOpenAppButtonClick() {
+    this.proxy.handler.launchApp();
+    this.proxy.handler.closeDialog();
+  }
 }
 
 customElements.define(AppInstallDialogElement.is, AppInstallDialogElement);
diff --git a/chrome/browser/screen_ai/screen_ai_install_state.cc b/chrome/browser/screen_ai/screen_ai_install_state.cc
index 25d1e316..45eaabea 100644
--- a/chrome/browser/screen_ai/screen_ai_install_state.cc
+++ b/chrome/browser/screen_ai/screen_ai_install_state.cc
@@ -191,11 +191,18 @@
 }
 
 void ScreenAIInstallState::SetState(State state) {
+  // TODO(crbug.com/1508404): Remove after crash root cause is found.
+  if ((state == State::kDownloaded || state == State::kReady) &&
+      !IsComponentAvailable()) {
+    base::debug::DumpWithoutCrashing();
+    state = State::kFailed;
+  }
+
   if (state == state_) {
     // Failed and ready state can be repeated as they come from different
     // profiles. Downloading can be repeated in ChromeOS tests that call
     // LoginManagerTest::AddUser() and reset UserSessionInitializer.
-    // TODO(crbug.com/1278249): While the case is highly unexpected, add more
+    // TODO(crbug.com/1443341): While the case is highly unexpected, add more
     // control logic if state is changed from failed to ready or vice versa.
     DCHECK(state == State::kReady || state == State::kFailed ||
            state == State::kDownloading);
@@ -243,6 +250,9 @@
 
 void ScreenAIInstallState::SetStateForTesting(State state) {
   state_ = state;
+  for (ScreenAIInstallState::Observer* observer : observers_) {
+    observer->StateChanged(state_);
+  }
 }
 
 }  // namespace screen_ai
diff --git a/chrome/browser/screen_ai/screen_ai_service_router.cc b/chrome/browser/screen_ai/screen_ai_service_router.cc
index 9057a4f..c2b7679 100644
--- a/chrome/browser/screen_ai/screen_ai_service_router.cc
+++ b/chrome/browser/screen_ai/screen_ai_service_router.cc
@@ -7,6 +7,8 @@
 #include <utility>
 
 #include "base/containers/flat_map.h"
+#include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -141,22 +143,32 @@
 
 void ScreenAIServiceRouter::LaunchIfNotRunning() {
   ScreenAIInstallState::GetInstance()->SetLastUsageTime();
+  auto* state_instance = ScreenAIInstallState::GetInstance();
+  screen_ai::ScreenAIInstallState::State install_state =
+      state_instance->get_state();
 
   if (screen_ai_service_factory_.is_bound() ||
-      screen_ai::ScreenAIInstallState::GetInstance()->get_state() ==
-          screen_ai::ScreenAIInstallState::State::kFailed) {
+      install_state == screen_ai::ScreenAIInstallState::State::kFailed) {
     return;
   }
 
-  auto* screen_ai_install = ScreenAIInstallState::GetInstance();
+  // TODO(crbug.com/1508404): Remove after crash root cause is found, or replace
+  // above.
+  if (install_state != screen_ai::ScreenAIInstallState::State::kDownloaded &&
+      install_state != screen_ai::ScreenAIInstallState::State::kReady) {
+    base::debug::Alias(&install_state);
+    base::debug::DumpWithoutCrashing();
+    return;
+  }
+
   // Callers of the service should ensure that the component is downloaded
   // before promising it to the users and triggering its launch.
-  CHECK(screen_ai_install->IsComponentAvailable())
+  CHECK(state_instance->IsComponentAvailable())
       << "ScreenAI service launch triggered when component is not "
          "available.";
 
 #if BUILDFLAG(IS_WIN)
-  base::FilePath library_path = screen_ai_install->get_component_binary_path();
+  base::FilePath library_path = state_instance->get_component_binary_path();
   std::vector<base::FilePath> preload_libraries = {library_path};
 #endif  // BUILDFLAG(IS_WIN)
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 228f161d7..3bb8677 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2494,6 +2494,8 @@
       "../ash/app_list/search/util/ftrl_optimizer.h",
       "../ash/app_list/search/util/keyword_cache.cc",
       "../ash/app_list/search/util/keyword_cache.h",
+      "../ash/app_list/search/util/manatee.cc",
+      "../ash/app_list/search/util/manatee.h",
       "../ash/app_list/search/util/mrfu_cache.cc",
       "../ash/app_list/search/util/mrfu_cache.h",
       "../ash/app_list/search/util/persistent_proto.h",
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java
index b389b7e..4ce8e80b 100644
--- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java
+++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java
@@ -42,7 +42,9 @@
         return new EdgeToEdgeControllerImpl(activity, tabObservableSupplier, null);
     }
 
-    /** @Return whether the feature is enabled or not. */
+    /**
+     * @return whether the feature is enabled or not.
+     */
     public static boolean isEnabled() {
         // Make sure we test SDK version before checking the Feature so Field Trials only collect
         // from qualifying devices.
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
index 817baa9..bccc0ec 100644
--- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -294,14 +294,9 @@
 
   // Choose something from the bookmark submenu and make sure it makes it back
   // to the delegate as well.
-  size_t bookmarks_model_index = 0;
-  for (size_t i = 0; i < item_count; ++i) {
-    if (model.GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
-      // The bookmarks submenu comes after the Tabs and Downloads items.
-      bookmarks_model_index = i + (features::IsChromeRefresh2023() ? 3 : 2);
-      break;
-    }
-  }
+  size_t bookmarks_model_index =
+      model.GetIndexOfCommandId(IDC_BOOKMARKS_MENU).value();
+
   EXPECT_GT(bookmarks_model_index, 0u);
   ui::MenuModel* bookmarks_model =
       model.GetSubmenuModelAt(bookmarks_model_index);
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index 582d0ed8..b6b4efc3 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -53,6 +53,7 @@
 #include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_features.h"
 
 using ::testing::ElementsAre;
 
@@ -615,43 +616,83 @@
 
   RecentTabsSubMenuModel model(nullptr, browser());
 
-  // Expected menu items:
-  std::vector<ModelData> kData = {
-      {ui::MenuModel::TYPE_COMMAND, true},    // History
-      {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
-      {ui::MenuModel::TYPE_COMMAND, false},   // Recently closed
-      {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
-      {ui::MenuModel::TYPE_TITLE, false},     // <section header for session 3>
-      {ui::MenuModel::TYPE_COMMAND, true},    // <tab for session 3>
-      {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
-      {ui::MenuModel::TYPE_TITLE, false},     // <section header for session 2>
-      {ui::MenuModel::TYPE_COMMAND, true},    // <tab for session 2>
-      {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
-      {ui::MenuModel::TYPE_TITLE, false},     // <section header for session 1>
-      {ui::MenuModel::TYPE_COMMAND, true},    // <tab for session 1>
-      // max sessions is 3, so only the 3 most recent sessions will show.
-  };
+  std::vector<ModelData> kData;
+  // Once chrome refresh is launched this if condition can be removed.
+  if (!features::IsChromeRefresh2023()) {
+    kData = {
+        {ui::MenuModel::TYPE_COMMAND, true},    // History
+        {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+        {ui::MenuModel::TYPE_COMMAND, false},   // Recently closed
+        {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+        {ui::MenuModel::TYPE_TITLE, false},   // <section header for session 3>
+        {ui::MenuModel::TYPE_COMMAND, true},  // <tab for session 3>
+        {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+        {ui::MenuModel::TYPE_TITLE, false},   // <section header for session 2>
+        {ui::MenuModel::TYPE_COMMAND, true},  // <tab for session 2>
+        {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+        {ui::MenuModel::TYPE_TITLE, false},   // <section header for session 1>
+        {ui::MenuModel::TYPE_COMMAND, true},  // <tab for session 1>
+        // max sessions is 3, so only the 3 most recent sessions will show.
+    };
 
-  if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
-    kData.insert(kData.begin() + 1,
-                 {ui::MenuModel::TYPE_COMMAND, true});  // History Cluster
-  }
+    if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
+      kData.insert(kData.begin() + 1,
+                   {ui::MenuModel::TYPE_COMMAND, true});  // History Cluster
+    }
 
-  VerifyModel(model, kData);
+    VerifyModel(model, kData);
 
-  if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
-    EXPECT_THAT(base::span<const std::u16string>(
-                    recent_tabs_builder.GetTabTitlesSortedByRecency())
-                    .subspan(0, 3),
-                ElementsAre(model.GetLabelAt(6), model.GetLabelAt(9),
-                            model.GetLabelAt(12)));
+    if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
+      EXPECT_THAT(base::span<const std::u16string>(
+                      recent_tabs_builder.GetTabTitlesSortedByRecency())
+                      .subspan(0, 3),
+                  ElementsAre(model.GetLabelAt(6), model.GetLabelAt(9),
+                              model.GetLabelAt(12)));
+
+    } else {
+      EXPECT_THAT(base::span<const std::u16string>(
+                      recent_tabs_builder.GetTabTitlesSortedByRecency())
+                      .subspan(0, 3),
+                  ElementsAre(model.GetLabelAt(5), model.GetLabelAt(8),
+                              model.GetLabelAt(11)));
+    }
 
   } else {
-    EXPECT_THAT(base::span<const std::u16string>(
-                    recent_tabs_builder.GetTabTitlesSortedByRecency())
-                    .subspan(0, 3),
-                ElementsAre(model.GetLabelAt(5), model.GetLabelAt(8),
-                            model.GetLabelAt(11)));
+    kData = {{ui::MenuModel::TYPE_COMMAND, true},    // History
+             {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+             {ui::MenuModel::TYPE_COMMAND, false},   // Recently closed
+             {ui::MenuModel::TYPE_SEPARATOR, true},  // <separator>
+             {ui::MenuModel::TYPE_TITLE, false},     // Your devices
+             {ui::MenuModel::TYPE_SUBMENU, true},
+             {ui::MenuModel::TYPE_SUBMENU, true},
+             {ui::MenuModel::TYPE_SUBMENU, true},
+             {ui::MenuModel::TYPE_SUBMENU, true}};
+
+    if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
+      kData.insert(kData.begin() + 1,
+                   {ui::MenuModel::TYPE_COMMAND, true});  // History Cluster
+    }
+
+    VerifyModel(model, kData);
+
+    if (base::FeatureList::IsEnabled(features::kSidePanelPinning)) {
+      EXPECT_THAT(base::span<const std::u16string>(
+                      recent_tabs_builder.GetTabTitlesSortedByRecency())
+                      .subspan(0, 4),
+                  ElementsAre(model.GetSubmenuModelAt(6)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(7)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(8)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(9)->GetLabelAt(0)));
+
+    } else {
+      EXPECT_THAT(base::span<const std::u16string>(
+                      recent_tabs_builder.GetTabTitlesSortedByRecency())
+                      .subspan(0, 4),
+                  ElementsAre(model.GetSubmenuModelAt(5)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(6)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(7)->GetLabelAt(0),
+                              model.GetSubmenuModelAt(8)->GetLabelAt(0)));
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/permissions/chip_controller.cc b/chrome/browser/ui/views/permissions/chip_controller.cc
index b813608..261896e0 100644
--- a/chrome/browser/ui/views/permissions/chip_controller.cc
+++ b/chrome/browser/ui/views/permissions/chip_controller.cc
@@ -473,13 +473,6 @@
   }
 }
 
-void ChipController::OnOcclusionStateChanged(bool occluded) {
-  if (GetBubbleWidget()) {
-    // Disable the prompt if it's occluded by a picture-in-picture window.
-    GetBubbleWidget()->GetContentsView()->SetEnabled(!occluded);
-  }
-}
-
 void ChipController::HideChip() {
   if (!chip_->GetVisible())
     return;
@@ -561,7 +554,6 @@
     parent_was_visible_when_activation_changed_ =
         prompt_bubble_widget->GetPrimaryWindowWidget()->IsVisible();
     prompt_bubble_widget->AddObserver(this);
-    occlusion_observation_.Observe(prompt_bubble_widget);
   }
 }
 
diff --git a/chrome/browser/ui/views/permissions/chip_controller.h b/chrome/browser/ui/views/permissions/chip_controller.h
index 908302366..76c1b020b 100644
--- a/chrome/browser/ui/views/permissions/chip_controller.h
+++ b/chrome/browser/ui/views/permissions/chip_controller.h
@@ -11,8 +11,6 @@
 #include "base/check_is_test.h"
 #include "base/functional/callback_helpers.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_observer.h"
-#include "chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h"
 #include "chrome/browser/ui/views/location_bar/omnibox_chip_button.h"
 #include "components/permissions/permission_prompt.h"
 #include "components/permissions/permission_request_manager.h"
@@ -40,8 +38,7 @@
 class ChipController : public permissions::PermissionRequestManager::Observer,
                        public views::WidgetObserver,
                        public BubbleOwnerDelegate,
-                       public OmniboxChipButton::Observer,
-                       public PictureInPictureOcclusionObserver {
+                       public OmniboxChipButton::Observer {
  public:
   ChipController(Browser* browser_, OmniboxChipButton* chip_view);
 
@@ -82,9 +79,6 @@
   void OnExpandAnimationEnded() override;
   void OnCollapseAnimationEnded() override;
 
-  // PictureInPictureOcclusionObserver:
-  void OnOcclusionStateChanged(bool occluded) override;
-
   // Initializes the permission prompt model as well as the permission request
   // manager and observes the prompt bubble.
   void InitializePermissionPrompt(
@@ -243,8 +237,6 @@
   base::ScopedObservation<OmniboxChipButton, OmniboxChipButton::Observer>
       observation_{this};
 
-  ScopedPictureInPictureOcclusionObservation occlusion_observation_{this};
-
   base::WeakPtrFactory<ChipController> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc b/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc
index 8b1c8a66..5246a536 100644
--- a/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc
+++ b/chrome/browser/ui/views/permissions/permission_chip_interactive_test.cc
@@ -8,8 +8,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
-#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h"
-#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -45,7 +43,6 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/permissions_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
-#include "media/base/media_switches.h"
 #include "net/dns/mock_host_resolver.h"
 #include "permission_prompt_chip.h"
 #include "ui/accessibility/ax_action_data.h"
@@ -1648,71 +1645,3 @@
 
   EXPECT_TRUE(content::EvalJs(main_rfh, kCheckNotifications).value.GetBool());
 }
-
-class PictureInPictureOcclusionTrackingEnabledPermissionChipInteractiveTest
-    : public PermissionChipInteractiveTest {
- public:
-  PictureInPictureOcclusionTrackingEnabledPermissionChipInteractiveTest() {
-    scoped_feature_list_.InitWithFeatures(
-        {media::kPictureInPictureOcclusionTracking}, {});
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(
-    PictureInPictureOcclusionTrackingEnabledPermissionChipInteractiveTest,
-    ShouldHideChipWhenOccludedByAPictureInPictureWindow) {
-  RequestPermission(permissions::RequestType::kGeolocation);
-  base::RunLoop().RunUntilIdle();
-
-  // Chip should be visible. Click it to open the prompt.
-  EXPECT_TRUE(GetChip()->GetVisible());
-  ClickOnChip(GetChip());
-
-  views::View* prompt_view =
-      GetChipController()->GetBubbleWidget()->GetContentsView();
-  ASSERT_NE(prompt_view, nullptr);
-
-  // Create a picture-in-picture widget that does not occlude the prompt.
-  gfx::Rect prompt_widget_bounds =
-      prompt_view->GetWidget()->GetWindowBoundsInScreen();
-  gfx::Rect non_occluding_bounds =
-      gfx::Rect(prompt_widget_bounds.right() + 1, 0, 100, 100);
-  views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
-  init_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  init_params.bounds = non_occluding_bounds;
-  auto pip_widget = std::make_unique<views::Widget>(std::move(init_params));
-  pip_widget->Show();
-  PictureInPictureWindowManager::GetInstance()
-      ->GetOcclusionTracker()
-      ->OnPictureInPictureWidgetOpened(pip_widget.get());
-
-  // The prompt should be enabled, as it's not occluded.
-  EXPECT_TRUE(prompt_view->GetEnabled());
-
-  // Move the picture-in-picture window to occlude the prompt.
-  pip_widget->SetBounds(prompt_widget_bounds);
-
-  // The prompt should be disabled. We may need to wait for that to happen.
-  if (prompt_view->GetEnabled()) {
-    base::RunLoop wait_loop;
-    auto subscription =
-        prompt_view->AddEnabledChangedCallback(wait_loop.QuitClosure());
-    wait_loop.Run();
-  }
-  EXPECT_FALSE(prompt_view->GetEnabled());
-
-  // Move the picture-in-picture window to no longer occlude the prompt.
-  pip_widget->SetBounds(non_occluding_bounds);
-
-  // The prompt should be enabled again. We may need to wait for that to happen.
-  if (!prompt_view->GetEnabled()) {
-    base::RunLoop wait_loop;
-    auto subscription =
-        prompt_view->AddEnabledChangedCallback(wait_loop.QuitClosure());
-    wait_loop.Run();
-  }
-  EXPECT_TRUE(prompt_view->GetEnabled());
-}
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
index 886aa57..8addff3 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble.cc
@@ -48,7 +48,6 @@
 
   disallowed_custom_cursors_scope_ =
       delegate()->GetAssociatedWebContents()->CreateDisallowCustomCursorScope();
-  occlusion_observation_.Observe(prompt_bubble->GetWidget());
 }
 
 void PermissionPromptBubble::CleanUpPromptBubble() {
@@ -142,10 +141,3 @@
   return static_cast<const PermissionPromptBubbleBaseView*>(
       prompt_bubble_tracker_.view());
 }
-
-void PermissionPromptBubble::OnOcclusionStateChanged(bool occluded) {
-  // Disable the prompt if it's occluded by a picture-in-picture window.
-  if (GetPromptBubble()) {
-    GetPromptBubble()->GetWidget()->GetContentsView()->SetEnabled(!occluded);
-  }
-}
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble.h b/chrome/browser/ui/views/permissions/permission_prompt_bubble.h
index 278ebaf..a1bd0b6 100644
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble.h
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble.h
@@ -6,8 +6,6 @@
 #define CHROME_BROWSER_UI_VIEWS_PERMISSIONS_PERMISSION_PROMPT_BUBBLE_H_
 
 #include "chip_controller.h"
-#include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_observer.h"
-#include "chrome/browser/picture_in_picture/scoped_picture_in_picture_occlusion_observation.h"
 #include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h"
 #include "chrome/browser/ui/views/permissions/permission_prompt_desktop.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -19,8 +17,7 @@
 }
 
 class PermissionPromptBubble : public PermissionPromptDesktop,
-                               public views::WidgetObserver,
-                               public PictureInPictureOcclusionObserver {
+                               public views::WidgetObserver {
  public:
   PermissionPromptBubble(Browser* browser,
                          content::WebContents* web_contents,
@@ -44,9 +41,6 @@
 
   views::Widget* GetPromptBubbleWidgetForTesting() override;
 
-  // PictureInPictureOcclusionObserver:
-  void OnOcclusionStateChanged(bool occluded) override;
-
  private:
   PermissionPromptBubbleBaseView* GetPromptBubble();
   const PermissionPromptBubbleBaseView* GetPromptBubble() const;
@@ -61,8 +55,6 @@
 
   base::ScopedClosureRunner disallowed_custom_cursors_scope_;
 
-  ScopedPictureInPictureOcclusionObservation occlusion_observation_{this};
-
   base::WeakPtrFactory<PermissionPromptBubble> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc b/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc
index ff9447ce..017bcf3 100644
--- a/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc
+++ b/chrome/browser/ui/views/side_panel/search_companion/companion_page_browsertest.cc
@@ -1152,8 +1152,9 @@
             GetLastLinkOpenedMetadataFromPostMessage());
 }
 
+// TODO(crbug.com/1511189): Flaky test.
 IN_PROC_BROWSER_TEST_F(CompanionPageBrowserTest,
-                       PageTitleNotifiesViaPostMessage) {
+                       DISABLED_PageTitleNotifiesViaPostMessage) {
   EnablePco(true);
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       browser(), GURL("data:text/html;charset=utf-8,"
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
index 08a006f..eec882a8 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
@@ -751,16 +751,9 @@
 
 // The hover card should stop showing memory usage data after navigating to
 // another site since the data is now out of date
-// TODO(crbug.com/1483255): Flaky on mac
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_HoverCardStopShowingMemoryOnNavigation \
-  DISABLED_HoverCardStopShowingMemoryOnNavigation
-#else
-#define MAYBE_HoverCardStopShowingMemoryOnNavigation \
-  HoverCardStopShowingMemoryOnNavigation
-#endif
+// TODO(crbug.com/1483255): Re-enable after resolving flakiness.
 IN_PROC_BROWSER_TEST_P(TabHoverCardFadeFooterInteractiveUiTest,
-                       MAYBE_HoverCardStopShowingMemoryOnNavigation) {
+                       DISABLED_HoverCardStopShowingMemoryOnNavigation) {
   RunTestSequence(
       InstrumentTab(kFirstTabContents, 0),
       NavigateWebContents(kFirstTabContents, GetTestingURL("a.com")),
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
index 8e081a39..6e3afb42 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_browsertest.cc
@@ -1681,6 +1681,20 @@
   ASSERT_EQ(blue, EvalJs(web_contents, get_background_color));
 }
 
+// Verifies that draggable and non draggable regions defined by the app-region
+// CSS property are collected.
+IN_PROC_BROWSER_TEST_F(WebAppFrameToolbarBrowserTest_WindowControlsOverlay,
+                       DraggableRegionsEnabled) {
+  InstallAndLaunchWebApp();
+  ToggleWindowControlsOverlayAndWait();
+
+  absl::optional<SkRegion> draggable_region =
+      helper()->browser_view()->browser()->app_controller()->draggable_region();
+
+  EXPECT_TRUE(draggable_region.has_value());
+  EXPECT_FALSE(draggable_region.value().isEmpty());
+}
+
 #if !BUILDFLAG(IS_ANDROID)
 class WebAppFrameToolbarBrowserTest_AdditionalWindowingControls
     : public WebAppFrameToolbarBrowserTest {
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
index 9b110ff..8ed48f7 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -4569,7 +4569,9 @@
   enabled_features.push_back(blink::features::kDesktopPWAsTabStrip);
   enabled_features.push_back(features::kDesktopPWAsTabStripSettings);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // TODO(crbug.com/1462253): Also test with Lacros flags enabled.
+  // WebAppIntegrationTest runs in Ash only when Lacros is disabled.
+  // If Lacros is enabled, WebAppIntegrationTest runs in Lacros with crosapi
+  // enabled.
   base::Extend(disabled_features, ash::standalone_browser::GetFeatureRefs());
 #endif
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index f736e53..c12c2ce 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/chrome_render_frame.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/themes/autogenerated_theme_util.h"
 #include "chrome/grit/generated_resources.h"
@@ -37,9 +38,12 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/models/image_model.h"
@@ -129,6 +133,7 @@
       has_tab_strip_(has_tab_strip),
       theme_provider_(
           ThemeService::CreateBoundThemeProvider(browser_->profile(), this)) {
+  CHECK(browser->tab_strip_model()->empty());
   browser->tab_strip_model()->AddObserver(this);
 }
 
@@ -609,9 +614,27 @@
 void AppBrowserController::OnTabInserted(content::WebContents* contents) {
   if (!contents->GetVisibleURL().is_empty() && initial_url_.is_empty())
     SetInitialURL(contents->GetVisibleURL());
+
+  // Collect draggable app regions if the app supports Window Controls Overlay
+  // or Borderless mode.
+  if (AppUsesWindowControlsOverlay() || AppUsesBorderlessMode()) {
+    content::RenderFrameHost* host = contents->GetPrimaryMainFrame();
+    DCHECK(host);
+    mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> client;
+    host->GetRemoteAssociatedInterfaces()->GetInterface(&client);
+    client->SetSupportsAppRegion(true);
+  }
 }
 
-void AppBrowserController::OnTabRemoved(content::WebContents* contents) {}
+void AppBrowserController::OnTabRemoved(content::WebContents* contents) {
+  // Stop collecting draggable app regions when the web contents is removed
+  // since it may be reparented to a tab in the browser.
+  content::RenderFrameHost* host = contents->GetPrimaryMainFrame();
+  DCHECK(host);
+  mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame> client;
+  host->GetRemoteAssociatedInterfaces()->GetInterface(&client);
+  client->SetSupportsAppRegion(false);
+}
 
 ui::ImageModel AppBrowserController::GetFallbackAppIcon() const {
   TRACE_EVENT0("ui", "TaskManagerView::GetFallbackAppIcon");
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
index a579f56..57edf00 100644
--- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -106,7 +106,8 @@
     WebAppInstalledCallback installed_callback,
     const webapps::AppId& app_id,
     webapps::InstallResultCode code) {
-  dialog_handle->SetInstallSuccess(webapps::IsSuccess(code));
+  dialog_handle->SetInstallComplete(webapps::IsSuccess(code) ? &app_id
+                                                             : nullptr);
 
   // If we receive an error code, there's a chance the dialog was never shown,
   // so we need to clean it up to avoid a memory leak.
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install.mojom b/chrome/browser/ui/webui/ash/app_install/app_install.mojom
index a64d4fe..7196a38 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install.mojom
+++ b/chrome/browser/ui/webui/ash/app_install/app_install.mojom
@@ -37,4 +37,7 @@
   // Runs the callback to install the app and returns whether the app was
   // successfully installed.
   InstallApp() => (bool installed);
+
+  // Opens the app that was just installed, then closes the dialog.
+  LaunchApp();
 };
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
index 96248fc..6cf9e59 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.cc
@@ -37,9 +37,9 @@
   this->ShowSystemDialog(parent);
 }
 
-void AppInstallDialog::SetInstallSuccess(bool success) {
+void AppInstallDialog::SetInstallComplete(const std::string* app_id) {
   if (dialog_ui_) {
-    dialog_ui_->SetInstallSuccess(success);
+    dialog_ui_->SetInstallComplete(app_id);
   }
 }
 
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.h b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.h
index 107f624..d434e50 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_dialog.h
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_dialog.h
@@ -26,8 +26,9 @@
   void Show(gfx::NativeWindow parent,
             mojom::DialogArgsPtr args,
             base::OnceCallback<void(bool accepted)> dialog_accepted_callback);
-  // Callers must set whether the install was successful or not.
-  void SetInstallSuccess(bool success);
+  // Callers must call this once the install has finished, passing in the app_id
+  // if the installation succeeded or a nullptr if it failed.
+  void SetInstallComplete(const std::string* app_id);
 
   void OnDialogShown(content::WebUI* webui) override;
 
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/app_install/app_install_dialog_browsertest.cc
index 420023f..26b437b 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_dialog_browsertest.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_dialog_browsertest.cc
@@ -5,13 +5,17 @@
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/ui/webui/ash/app_install/app_install_dialog.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
+#include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_install_params.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/constants/chromeos_features.h"
@@ -87,6 +91,24 @@
            "querySelector('.action-button').textContent.includes('Open app')")
            .ExtractBool()) {
   }
+
+  // Click the open app button and expect the dialog was closed.
+  content::WebContentsDestroyedWatcher watcher(web_contents);
+  EXPECT_TRUE(
+      content::ExecJs(web_contents,
+                      "document.querySelector('app-install-dialog')."
+                      "shadowRoot.querySelector('.action-button').click()"));
+  watcher.Wait();
+
+  // Expect the app is opened.
+  webapps::AppId app_id = web_app::GenerateAppIdFromManifestId(app_url);
+  Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
+  EXPECT_TRUE(web_app::AppBrowserController::IsForWebApp(app_browser, app_id));
+
+  // Expect the browser tab was not closed.
+  EXPECT_EQ(
+      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
+      app_url);
 }
 
 IN_PROC_BROWSER_TEST_F(AppInstallDialogBrowserTest, FailedInstall) {
@@ -97,13 +119,14 @@
   base::WeakPtr<AppInstallDialog> dialog_handle =
       AppInstallDialog::CreateDialog();
 
-  dialog_handle->Show(
-      browser()->window()->GetNativeWindow(),
-      ash::app_install::mojom::DialogArgs::New(),
-      base::BindOnce(
-          [](base::WeakPtr<AppInstallDialog> dialog_handle,
-             bool dialog_accepted) { dialog_handle->SetInstallSuccess(false); },
-          dialog_handle));
+  dialog_handle->Show(browser()->window()->GetNativeWindow(),
+                      ash::app_install::mojom::DialogArgs::New(),
+                      base::BindOnce(
+                          [](base::WeakPtr<AppInstallDialog> dialog_handle,
+                             bool dialog_accepted) {
+                            dialog_handle->SetInstallComplete(nullptr);
+                          },
+                          dialog_handle));
 
   navigation_observer_dialog.Wait();
   ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded());
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.cc b/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.cc
index b614539..789ec724 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.cc
@@ -4,16 +4,21 @@
 
 #include "chrome/browser/ui/webui/ash/app_install/app_install_page_handler.h"
 
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ui/webui/ash/app_install/app_install.mojom.h"
+#include "components/services/app_service/public/cpp/app_launch_util.h"
 
 namespace ash::app_install {
 
 AppInstallPageHandler::AppInstallPageHandler(
+    Profile* profile,
     mojom::DialogArgsPtr args,
     base::OnceCallback<void(bool accepted)> dialog_accepted_callback,
     mojo::PendingReceiver<mojom::PageHandler> pending_page_handler,
     CloseDialogCallback close_dialog_callback)
-    : dialog_args_{std::move(args)},
+    : profile_{profile},
+      dialog_args_{std::move(args)},
       dialog_accepted_callback_{std::move(dialog_accepted_callback)},
       receiver_{this, std::move(pending_page_handler)},
       close_dialog_callback_{std::move(close_dialog_callback)} {}
@@ -41,10 +46,22 @@
   std::move(dialog_accepted_callback_).Run(true);
 }
 
-void AppInstallPageHandler::OnInstallComplete(bool success) {
-  if (install_app_callback_) {
-    std::move(install_app_callback_).Run(success);
+void AppInstallPageHandler::OnInstallComplete(const std::string* app_id) {
+  if (app_id) {
+    app_id_ = *app_id;
   }
+  if (install_app_callback_) {
+    std::move(install_app_callback_).Run(/*success=*/app_id);
+  }
+}
+
+void AppInstallPageHandler::LaunchApp() {
+  if (app_id_.empty()) {
+    mojo::ReportBadMessage("Unable to launch app without an app_id.");
+    return;
+  }
+  apps::AppServiceProxyFactory::GetForProfile(profile_)->Launch(
+      app_id_, ui::EF_NONE, apps::LaunchSource::kFromInstaller);
 }
 
 }  // namespace ash::app_install
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.h b/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.h
index db9d5718..b9d0749 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.h
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_page_handler.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_ASH_APP_INSTALL_APP_INSTALL_PAGE_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_ASH_APP_INSTALL_APP_INSTALL_PAGE_HANDLER_H_
 
+#include <string>
+
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ash/app_install/app_install.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -21,6 +24,7 @@
  public:
   using CloseDialogCallback = base::OnceCallback<void()>;
   explicit AppInstallPageHandler(
+      Profile* profile,
       mojom::DialogArgsPtr args,
       base::OnceCallback<void(bool accepted)> dialog_accepted_callback,
       mojo::PendingReceiver<mojom::PageHandler> pending_page_handler,
@@ -31,19 +35,22 @@
 
   ~AppInstallPageHandler() override;
 
-  void OnInstallComplete(bool success);
+  void OnInstallComplete(const std::string* app_id);
 
   // mojom::PageHandler:
   void GetDialogArgs(GetDialogArgsCallback callback) override;
   void CloseDialog() override;
   void InstallApp(InstallAppCallback callback) override;
+  void LaunchApp() override;
 
  private:
+  raw_ptr<Profile> profile_;
   mojom::DialogArgsPtr dialog_args_;
   base::OnceCallback<void(bool accepted)> dialog_accepted_callback_;
   mojo::Receiver<mojom::PageHandler> receiver_;
   CloseDialogCallback close_dialog_callback_;
   InstallAppCallback install_app_callback_;
+  std::string app_id_;
 
   base::WeakPtrFactory<AppInstallPageHandler> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc b/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
index def400d..bf6888b 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
@@ -54,11 +54,11 @@
   dialog_accepted_callback_ = std::move(dialog_accepted_callback);
 }
 
-void AppInstallDialogUI::SetInstallSuccess(bool success) {
+void AppInstallDialogUI::SetInstallComplete(const std::string* app_id) {
   if (!page_handler_) {
     return;
   }
-  page_handler_->OnInstallComplete(success);
+  page_handler_->OnInstallComplete(app_id);
 }
 
 void AppInstallDialogUI::BindInterface(
@@ -72,8 +72,8 @@
 void AppInstallDialogUI::CreatePageHandler(
     mojo::PendingReceiver<mojom::PageHandler> receiver) {
   page_handler_ = std::make_unique<AppInstallPageHandler>(
-      std::move(dialog_args_), std::move(dialog_accepted_callback_),
-      std::move(receiver),
+      Profile::FromWebUI(web_ui()), std::move(dialog_args_),
+      std::move(dialog_accepted_callback_), std::move(receiver),
       base::BindOnce(&AppInstallDialogUI::CloseDialog, base::Unretained(this)));
 }
 
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_ui.h b/chrome/browser/ui/webui/ash/app_install/app_install_ui.h
index 9dcc89b..f55ebc53 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_ui.h
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_ui.h
@@ -24,7 +24,7 @@
   void SetDialogArgs(mojom::DialogArgsPtr args);
   void SetDialogCallback(
       base::OnceCallback<void(bool accepted)> dialog_accepted_callback);
-  void SetInstallSuccess(bool success);
+  void SetInstallComplete(const std::string* app_id);
 
   // Instantiates the implementor of the mojom::PageHandlerFactory mojo
   // interface passing the pending receiver that will be internally bound.
diff --git a/chrome/browser/ui/webui/ash/settings/pages/a11y/pdf_ocr_handler_unittest.cc b/chrome/browser/ui/webui/ash/settings/pages/a11y/pdf_ocr_handler_unittest.cc
index 4b147fc..5319e50 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/a11y/pdf_ocr_handler_unittest.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/a11y/pdf_ocr_handler_unittest.cc
@@ -130,7 +130,7 @@
   }
 
   void SimulateSetState(screen_ai::ScreenAIInstallState::State state) {
-    test_screen_ai_install_state_->SetState(state);
+    test_screen_ai_install_state_->SetStateForTesting(state);
   }
 
   content::TestWebUI* test_web_ui() const { return test_web_ui_.get(); }
diff --git a/chrome/browser/ui/webui/settings/accessibility_main_handler_unittest.cc b/chrome/browser/ui/webui/settings/accessibility_main_handler_unittest.cc
index 6dd47c7..791f10d 100644
--- a/chrome/browser/ui/webui/settings/accessibility_main_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/accessibility_main_handler_unittest.cc
@@ -120,7 +120,7 @@
   }
 
   void SimulateSetState(screen_ai::ScreenAIInstallState::State state) {
-    test_screen_ai_install_state_->SetState(state);
+    test_screen_ai_install_state_->SetStateForTesting(state);
   }
 
   content::TestWebUI* test_web_ui() const { return test_web_ui_.get(); }
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
index acd312ad..d19a6b1 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -65,7 +65,6 @@
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
-#include "chrome/browser/web_applications/web_app_id_constants.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
@@ -213,14 +212,6 @@
     }
   }
 
-  // On some devices, Adobe Express is installed through App Preload Service
-  // as an OEM app, but should not appear in the OEM folder.
-  // TODO(b/300857328): Remove this workaround.
-  if (web_app->GetHighestPrioritySource() == WebAppManagement::kOem &&
-      web_app->app_id() == web_app::kAdobeExpressAppId) {
-    return apps::InstallReason::kDefault;
-  }
-
   switch (web_app->GetHighestPrioritySource()) {
     case WebAppManagement::kSystem:
       return apps::InstallReason::kSystem;
@@ -1638,8 +1629,11 @@
       HostContentSettingsMapFactory::GetForProfile(profile_));
 
 #if BUILDFLAG(IS_CHROMEOS)
-  notification_display_service_.Observe(
-      NotificationDisplayServiceFactory::GetForProfile(profile()));
+  // NotificationDisplayService could be null in some tests.
+  if (auto* notification_display_service =
+          NotificationDisplayServiceFactory::GetForProfile(profile())) {
+    notification_display_service_.Observe(notification_display_service);
+  }
 
   badge_manager_ = badging::BadgeManagerFactory::GetForProfile(profile());
   // badge_manager_ is nullptr in guest and incognito profiles.
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
index f4d3e0c..e6ce6256 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
@@ -322,59 +322,6 @@
   EXPECT_EQ(file_cond.condition_values[1]->value, ".txt");
 }
 
-// Verify that Adobe Express has its OEM install source overwritten as
-// InstallReason::kDefault.
-// TODO(b/300857328): Remove this workaround.
-TEST_F(WebAppPublisherHelperTest, PublishOemAdobeExpressAsDefault) {
-  const std::string name = "some app name";
-  const GURL start_url("https://example.com/start_url");
-
-  // Manually edit the database to create an app with the specific App ID but a
-  // non-matching start URL.
-  {
-    ScopedRegistryUpdate update = provider_->sync_bridge_unsafe().BeginUpdate();
-
-    auto new_app = std::make_unique<WebApp>(kAdobeExpressAppId);
-    new_app->SetStartUrl(start_url);
-    new_app->AddSource(WebAppManagement::Type::kOem);
-    new_app->SetName(name);
-
-    update->CreateApp(std::move(new_app));
-  }
-
-  const WebApp* web_app =
-      provider_->registrar_unsafe().GetAppById(kAdobeExpressAppId);
-
-  apps::AppPtr app = publisher_->CreateWebApp(web_app);
-  EXPECT_EQ(app->install_reason, apps::InstallReason::kDefault);
-}
-
-// Verify that the above behavior only applies when the app is OEM-installed.
-// TODO(b/300857328): Remove this workaround.
-TEST_F(WebAppPublisherHelperTest, PublishSyncAdobeExpressAsSync) {
-  const std::string name = "some app name";
-  const GURL start_url("https://example.com/start_url");
-
-  // Manually edit the database to create an app with the specific App ID but a
-  // non-matching start URL.
-  {
-    ScopedRegistryUpdate update = provider_->sync_bridge_unsafe().BeginUpdate();
-
-    auto new_app = std::make_unique<WebApp>(kAdobeExpressAppId);
-    new_app->SetStartUrl(start_url);
-    new_app->AddSource(WebAppManagement::Type::kSync);
-    new_app->SetName(name);
-
-    update->CreateApp(std::move(new_app));
-  }
-
-  const WebApp* web_app =
-      provider_->registrar_unsafe().GetAppById(kAdobeExpressAppId);
-
-  apps::AppPtr app = publisher_->CreateWebApp(web_app);
-  EXPECT_EQ(app->install_reason, apps::InstallReason::kSync);
-}
-
 #if BUILDFLAG(IS_CHROMEOS)
 TEST_F(WebAppPublisherHelperTest, UpdateShortcutDoesNotPublishDelta) {
   EnableCrosWebAppShortcutUiUpdate(true);
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/feed/FeedSurfaceScopeDependencyProvider.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/feed/FeedSurfaceScopeDependencyProvider.java
index 7dd7ca4..995fd21e 100644
--- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/feed/FeedSurfaceScopeDependencyProvider.java
+++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/feed/FeedSurfaceScopeDependencyProvider.java
@@ -125,7 +125,7 @@
      * Adds a header offset observer to the surface this scope is associated with.
      *
      * @param observer The observer to add.
-     * @Return a reference to be used when removing the observer, or null if not successful.
+     * @return a reference to be used when removing the observer, or null if not successful.
      */
     default void addHeaderOffsetObserver(SurfaceHeaderOffsetObserver observer) {}
 
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 90d0a46..00da537 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1702425214-915c1314fa46f8dbbb5bf3cfd8d8a86c1896adc2.profdata
+chrome-android32-main-1702447123-bed2e5fe15bf2185c87941cc65b80896d4126b24.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 35bd600..e8fd13a9 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1702425214-14c0ac1ffc03747544aa7a7cf4c0a61557c0b42f.profdata
+chrome-android64-main-1702447123-a38d1365b5e43a01cd21d9e5b20a6497833bfbd1.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 14cfc7d..360c5505 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1702425214-c0eeefb29930be2c4e15f71c555b06034cc26f56.profdata
+chrome-linux-main-1702447123-266f7fc8e5fce15ba880d22bef2d48878e563c4d.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 72bbf93..0a858318 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1702432768-94aea22f9e9b926edeb7c28cc770df1bfae9ddff.profdata
+chrome-mac-arm-main-1702461414-8ea1afeac8e596a108ef03d039c19dc2c7531899.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d44343ba..6465eedb 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1702425214-1fdb9a0a29f3689c8e41dfe04aedc8409376b4b1.profdata
+chrome-mac-main-1702447123-b3d1bd65b3dc0ca24f49b4e68bb71073949cbf3b.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index bdc14a0..99b5135 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1702425214-5e919e3462b94a38d972768c6c40f439958542b5.profdata
+chrome-win-arm64-main-1702447123-78c1140c790c3a9c0e62c2af90cbd845e5349689.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d6363a1..03428c2 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1702425214-5070cd26284fc4b60e0b182054fcf04b72f2bb33.profdata
+chrome-win32-main-1702447123-a31776760bdc4ea37f254d84b09aee737ef69edc.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9916f7f..a04c736f 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1702425214-bc7d81d4f7f7000ffc8054316eef6b5b4f620ce8.profdata
+chrome-win64-main-1702447123-9223de7885538ed24977d864c1dd4a142590be3f.profdata
diff --git a/chrome/common/chrome_render_frame.mojom b/chrome/common/chrome_render_frame.mojom
index 92c421e..05f928d 100644
--- a/chrome/common/chrome_render_frame.mojom
+++ b/chrome/common/chrome_render_frame.mojom
@@ -68,4 +68,8 @@
   // Tells the render frame to load any blocked plugins matching the given
   // identifier (empty string matches all).
   LoadBlockedPlugins(string identifier);
+
+  // Indicates that the frame should collect draggable regions set using the
+  // app-region CSS property.
+  SetSupportsAppRegion(bool supports_app_region);
 };
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index d514ff1e..ef842d9 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -576,6 +576,10 @@
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 }
 
+void ChromeRenderFrameObserver::SetSupportsAppRegion(bool supports_app_region) {
+  render_frame()->GetWebView()->SetSupportsAppRegion(supports_app_region);
+}
+
 void ChromeRenderFrameObserver::SetClientSidePhishingDetection() {
 #if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
   phishing_classifier_ = safe_browsing::PhishingClassifierDelegate::Create(
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h
index 073d3a5..2ad51aa9 100644
--- a/chrome/renderer/chrome_render_frame_observer.h
+++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -107,6 +107,7 @@
 #endif
   void GetMediaFeedURL(GetMediaFeedURLCallback callback) override;
   void LoadBlockedPlugins(const std::string& identifier) override;
+  void SetSupportsAppRegion(bool supports_app_region) override;
 
   // Initialize a |phishing_classifier_delegate_|.
   void SetClientSidePhishingDetection();
diff --git a/chrome/test/base/chromeos/ash_browser_test_starter.cc b/chrome/test/base/chromeos/ash_browser_test_starter.cc
index f4b3065..cf495d40d 100644
--- a/chrome/test/base/chromeos/ash_browser_test_starter.cc
+++ b/chrome/test/base/chromeos/ash_browser_test_starter.cc
@@ -201,8 +201,7 @@
 void AshBrowserTestStarter::StartLacros(InProcessBrowserTest* test_class_obj) {
   DCHECK(HasLacrosArgument());
 
-  crosapi::BrowserManager::Get()->set_device_ownership_waiter_for_testing(
-      std::make_unique<crosapi::FakeDeviceOwnershipWaiter>());
+  SetUpBrowserManager();
 
   {
     NewLacrosWindowWatcher watcher;
@@ -215,6 +214,13 @@
   CHECK(crosapi::BrowserManager::Get()->IsRunning());
 }
 
+void AshBrowserTestStarter::SetUpBrowserManager() {
+  DCHECK(HasLacrosArgument());
+
+  crosapi::BrowserManager::Get()->set_device_ownership_waiter_for_testing(
+      std::make_unique<crosapi::FakeDeviceOwnershipWaiter>());
+}
+
 void AshBrowserTestStarter::OnWindowDestroying(aura::Window* window) {
   DCHECK_EQ(window, initial_lacros_window_);
   initial_lacros_window_ = nullptr;
diff --git a/chrome/test/base/chromeos/ash_browser_test_starter.h b/chrome/test/base/chromeos/ash_browser_test_starter.h
index 8626a0a..217c774 100644
--- a/chrome/test/base/chromeos/ash_browser_test_starter.h
+++ b/chrome/test/base/chromeos/ash_browser_test_starter.h
@@ -40,6 +40,9 @@
   // this no earlier than SetUpOnMainThread().
   void StartLacros(InProcessBrowserTest* test_class_obj);
 
+  // Sets the browser manager's ownership waiter to a test fake.
+  void SetUpBrowserManager();
+
   net::EmbeddedTestServer* https_server();
   GURL base_url();
 
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
index 2e9f32f..bc82dfd 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
@@ -51,7 +51,8 @@
   ['SearchBoxTest', 'search_box_test.js'],
   ['SearchResultRowTest', 'search_result_row_test.js'],
   ['SearchResultBoldingTest', 'search_result_bolding_test.js'],
-  ['ShortcutCustomizationApp', 'shortcut_customization_test.js'],
+  // TODO(https://crbug.com/1498419): Tests are flaky.
+  // ['ShortcutCustomizationApp', 'shortcut_customization_test.js'],
   ['ShortcutSearchHandlerTest', 'shortcut_search_handler_test.js'],
   ['ShortcutsPageTest', 'shortcuts_page_test.js'],
   ['ShortcutUtils', 'shortcut_utils_test.js'],
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
index 99910e02..85ae18f 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -1416,32 +1416,25 @@
         strictQuery('search-box', getPage().shadowRoot, SearchBoxElement);
     let searchField = strictQuery(
         '#search', searchBox.shadowRoot, CrToolbarSearchFieldElement);
-
-    // Verify that the search field is focused by default when the app opens.
-    await flushTasks();
-    assertTrue(searchField.isSearchFocused());
-
-    // Remove focus from the search field.
-    searchField.blur();
-    searchBox =
-        strictQuery('search-box', getPage().shadowRoot, SearchBoxElement);
-    searchField = strictQuery(
-        '#search', searchBox.shadowRoot, CrToolbarSearchFieldElement);
-
-    // Confirm that the search field is no longer focused.
-    await flushTasks();
     assertFalse(searchField.isSearchFocused());
 
-    // Trigger the 'handleFindShortcut' function.
-    getPage().handleFindShortcut(/*modalContextOpen=*/ false);
+    // press ctrl + f.
+    const keyboardEvent = new KeyboardEvent('keydown', {
+      key: 'f',
+      keyCode: 70,
+      code: 'KeyF',
+      ctrlKey: true,
+      altKey: false,
+      shiftKey: false,
+      metaKey: false,
+    });
+    getPage().dispatchEvent(keyboardEvent);
+    await flushTasks();
 
     searchBox =
         strictQuery('search-box', getPage().shadowRoot, SearchBoxElement);
     searchField = strictQuery(
         '#search', searchBox.shadowRoot, CrToolbarSearchFieldElement);
-
-    // Verify that the search field is focused.
-    await flushTasks();
     assertTrue(searchField.isSearchFocused());
   });
 });
diff --git a/chrome/test/data/webui/cr_components/most_visited_test.ts b/chrome/test/data/webui/cr_components/most_visited_test.ts
index 6976164f..274b59b 100644
--- a/chrome/test/data/webui/cr_components/most_visited_test.ts
+++ b/chrome/test/data/webui/cr_components/most_visited_test.ts
@@ -1067,6 +1067,10 @@
     }));
     await flushTasks();
     const reorderCalled = handler.whenCalled('reorderMostVisitedTile');
+    document.dispatchEvent(new DragEvent('drop', {
+      clientX: secondRect.x + 1,
+      clientY: secondRect.y + 1,
+    }));
     document.dispatchEvent(new DragEvent('dragend', {
       clientX: secondRect.x + 1,
       clientY: secondRect.y + 1,
@@ -1096,6 +1100,10 @@
     }));
     await flushTasks();
     const reorderCalled = handler.whenCalled('reorderMostVisitedTile');
+    document.dispatchEvent(new DragEvent('drop', {
+      clientX: firstRect.x + 1,
+      clientY: firstRect.y + 1,
+    }));
     document.dispatchEvent(new DragEvent('dragend', {
       clientX: firstRect.x + 1,
       clientY: firstRect.y + 1,
@@ -1123,6 +1131,10 @@
       clientX: firstRect.x + firstRect.width / 2,
       clientY: firstRect.y + firstRect.height / 2,
     }));
+    document.dispatchEvent(new DragEvent('drop', {
+      clientX: secondRect.x + 1,
+      clientY: secondRect.y + 1,
+    }));
     document.dispatchEvent(new DragEvent('dragend', {
       clientX: secondRect.x + 1,
       clientY: secondRect.y + 1,
diff --git a/chromeos/ash/components/language_packs/language_pack_manager.cc b/chromeos/ash/components/language_packs/language_pack_manager.cc
index c7b833cb..3dc3971 100644
--- a/chromeos/ash/components/language_packs/language_pack_manager.cc
+++ b/chromeos/ash/components/language_packs/language_pack_manager.cc
@@ -7,9 +7,11 @@
 #include <optional>
 #include <string_view>
 
+#include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "base/containers/contains.h"
 #include "base/containers/flat_map.h"
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
@@ -455,11 +457,22 @@
 }
 
 void LanguagePackManager::CheckAndUpdateDlcsForInputMethods(
-    PrefService* prefs) {
+    PrefService* pref_service) {
   // The list of input methods have changed. We need to get the list of current
   // DLCs installed on device, which is an asynchronous method.
   DlcserviceClient::Get()->GetExistingDlcs(
-      base::BindOnce(&OnGetExistingDlcs, prefs));
+      base::BindOnce(&OnGetExistingDlcs, pref_service));
+}
+
+void LanguagePackManager::ObservePrefs(PrefService* pref_service) {
+  // This is the main gate for the functionality of observing Prefs.
+  // If this flag is false, all of the cascading logic is disabled.
+  if (base::FeatureList::IsEnabled(features::kLanguagePacksInSettings)) {
+    pref_change_registrar_.Init(pref_service);
+    base::RepeatingClosure callback = base::BindRepeating(
+        &LanguagePackManager::CheckAndUpdateDlcsForInputMethods, pref_service);
+    pref_change_registrar_.Add(ash::prefs::kLanguagePreloadEngines, callback);
+  }
 }
 
 void LanguagePackManager::AddObserver(Observer* const observer) {
@@ -503,6 +516,7 @@
 
 LanguagePackManager::~LanguagePackManager() {
   CHECK_EQ(g_instance, this);
+  pref_change_registrar_.RemoveAll();
   g_instance = nullptr;
 }
 
diff --git a/chromeos/ash/components/language_packs/language_pack_manager.h b/chromeos/ash/components/language_packs/language_pack_manager.h
index 6b9ffa2..ba780b1 100644
--- a/chromeos/ash/components/language_packs/language_pack_manager.h
+++ b/chromeos/ash/components/language_packs/language_pack_manager.h
@@ -15,6 +15,8 @@
 #include "base/scoped_observation.h"
 #include "base/strings/strcat.h"
 #include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_service.h"
 #include "ui/base/ime/ash/input_method_util.h"
 
 class PrefService;
@@ -236,6 +238,9 @@
   static void UpdatePacksForOobe(const std::string& locale,
                                  OnUpdatePacksForOobeCallback callback);
 
+  // Registers itself as an Observer of all the relevant languages Prefs.
+  void ObservePrefs(PrefService* pref_service);
+
   // Adds an observer to the observer list.
   void AddObserver(Observer* observer);
 
@@ -272,7 +277,7 @@
   // Retrieves the list of installed DLCs and updates Packs accordingly.
   // This function should be called when LPM initializes and then each time
   // Prefs change.
-  static void CheckAndUpdateDlcsForInputMethods(PrefService* prefs);
+  static void CheckAndUpdateDlcsForInputMethods(PrefService* pref_service);
 
   // DlcserviceClient::Observer overrides.
   void OnDlcStateChanged(const dlcservice::DlcState& dlc_state) override;
@@ -285,6 +290,7 @@
   base::ObserverList<Observer> observers_;
   base::ScopedObservation<DlcserviceClient, DlcserviceClient::Observer> obs_{
       this};
+  PrefChangeRegistrar pref_change_registrar_;
 };
 
 }  // namespace ash::language_packs
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index cd2ee7ec..f024f259 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -447,5 +448,56 @@
             .heuristic_type = ADDRESS_HOME_APT_NUM,
             .expected_result = ADDRESS_HOME_CITY}));
 
+// Tests that consecutive identical events are not added twice to the event log.
+TEST(AutofillFieldLogEventTypeTest, AppendLogEventIfNotRepeated) {
+  // The following three FieldLogEventTypes are arbitrary besides being of
+  // distinct types.
+  AutofillField::FieldLogEventType a = AskForValuesToFillFieldLogEvent{
+      .has_suggestion = OptionalBoolean::kFalse,
+      .suggestion_is_shown = OptionalBoolean::kFalse};
+  AutofillField::FieldLogEventType a2 = AskForValuesToFillFieldLogEvent{
+      .has_suggestion = OptionalBoolean::kTrue,
+      .suggestion_is_shown = OptionalBoolean::kTrue};
+  AutofillField::FieldLogEventType b =
+      TriggerFillFieldLogEvent{.data_type = FillDataType::kUndefined,
+                               .associated_country_code = "DE",
+                               .timestamp = AutofillClock::Now()};
+  AutofillField::FieldLogEventType c = FillFieldLogEvent{
+      .fill_event_id = absl::get<TriggerFillFieldLogEvent>(b).fill_event_id,
+      .had_value_before_filling = OptionalBoolean::kTrue,
+      .autofill_skipped_status =
+          FieldFillingSkipReason::kAutofilledFieldsNotRefill,
+      .was_autofilled = OptionalBoolean::kTrue,
+      .had_value_after_filling = OptionalBoolean::kTrue};
+
+  AutofillField f;
+  EXPECT_TRUE(f.field_log_events().empty());
+
+  f.AppendLogEventIfNotRepeated(a);
+  EXPECT_EQ(f.field_log_events().size(), 1u);
+  f.AppendLogEventIfNotRepeated(a);
+  EXPECT_EQ(f.field_log_events().size(), 1u);
+
+  f.AppendLogEventIfNotRepeated(a2);
+  EXPECT_EQ(f.field_log_events().size(), 2u);
+  f.AppendLogEventIfNotRepeated(a2);
+  EXPECT_EQ(f.field_log_events().size(), 2u);
+
+  f.AppendLogEventIfNotRepeated(b);
+  EXPECT_EQ(f.field_log_events().size(), 3u);
+  f.AppendLogEventIfNotRepeated(b);
+  EXPECT_EQ(f.field_log_events().size(), 3u);
+
+  f.AppendLogEventIfNotRepeated(c);
+  EXPECT_EQ(f.field_log_events().size(), 4u);
+  f.AppendLogEventIfNotRepeated(c);
+  EXPECT_EQ(f.field_log_events().size(), 4u);
+
+  f.AppendLogEventIfNotRepeated(a);
+  EXPECT_EQ(f.field_log_events().size(), 5u);
+  f.AppendLogEventIfNotRepeated(a);
+  EXPECT_EQ(f.field_log_events().size(), 5u);
+}
+
 }  // namespace
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_suggestion_generator.cc b/components/autofill/core/browser/autofill_suggestion_generator.cc
index e392139..75b8b17 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -12,6 +12,7 @@
 #include "base/notreached.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_browser_util.h"
@@ -27,6 +28,7 @@
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/data_model/iban.h"
 #include "components/autofill/core/browser/field_filling_address_util.h"
+#include "components/autofill/core/browser/field_type_utils.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_parsing/address_field.h"
 #include "components/autofill/core/browser/form_structure.h"
@@ -132,12 +134,69 @@
 #endif
 }
 
+// For a profile containing a full address, the main text is the name, and
+// the label is the address. The problem arises when a profile isn't complete
+// (aka it doesn't have a name or an address etc.).
+//
+// `AutofillProfile::CreateDifferentiatingLabels` generates the a text which
+// contains 2 address fields.
+//
+// Example for a full autofill profile:
+// "Full Name, Address"
+//
+// Examples where autofill profiles are incomplete:
+// "City, Country"
+// "Country, Email"
+//
+// Note: the separator isn't actually ", ", it is
+// IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
+std::u16string GetProfileSuggestionMainTextForNonAddressField(
+    const AutofillProfile& profile,
+    const std::string& app_locale) {
+  std::vector<std::u16string> suggestion_text_array;
+  AutofillProfile::CreateDifferentiatingLabels({&profile}, app_locale,
+                                               &suggestion_text_array);
+  CHECK_EQ(suggestion_text_array.size(), 1u);
+
+  const std::u16string separator =
+      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
+  // The first part contains the main text.
+  return suggestion_text_array[0].substr(
+      0, suggestion_text_array[0].find_first_of(separator));
+}
+
+// Check comment of method above:
+// `GetProfileSuggestionMainTextForNonAddressField`.
+std::vector<std::u16string> GetProfileSuggestionLabelForNonAddressField(
+    const std::vector<const AutofillProfile*>& profiles,
+    const std::string& app_locale) {
+  std::vector<std::u16string> labels;
+  AutofillProfile::CreateDifferentiatingLabels(profiles, app_locale, &labels);
+  CHECK_EQ(labels.size(), profiles.size());
+
+  for (std::u16string& label : labels) {
+    const std::u16string separator =
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
+    std::vector<std::u16string> text_pieces = base::SplitStringUsingSubstr(
+        label, separator, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+    // `text_pieces[1]` contains the label.
+    label = text_pieces.size() > 1 ? text_pieces[1] : u"";
+  }
+  return labels;
+}
+
 // In addition to just getting the values out of the profile, this function
 // handles type-specific formatting.
 std::u16string GetProfileSuggestionMainText(
     const AutofillProfile& profile,
     const std::string& app_locale,
     ServerFieldType trigger_field_type) {
+  if (!IsAddressType(trigger_field_type) &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillForUnclassifiedFieldsAvailable)) {
+    return GetProfileSuggestionMainTextForNonAddressField(profile, app_locale);
+  }
   if (trigger_field_type == ADDRESS_HOME_STREET_ADDRESS) {
     std::string street_address_line;
     ::i18n::addressinput::GetStreetAddressLinesAsSingleLine(
@@ -428,13 +487,19 @@
 // Adds footer child suggestions to build autofill popup submenu.
 void AddFooterChildSuggestions(
     const AutofillProfile& profile,
+    ServerFieldType trigger_field_type,
     absl::optional<ServerFieldTypeSet> last_targeted_fields,
     Suggestion& suggestion) {
+  // If the trigger field is not classified as an address field, then the
+  // filling was triggered from the context menu. In this scenario, the user
+  // should not be able to fill everything.
   // If the last filling granularity was not full form, add the
   // `PopupItemId::kFillEverythingFromAddressProfile` suggestion. This allows
   // the user to go back to filling the whole form once in a more fine grained
   // filling experience.
-  if (!last_targeted_fields || *last_targeted_fields != kAllServerFieldTypes) {
+  if (IsAddressType(trigger_field_type) &&
+      (!last_targeted_fields ||
+       *last_targeted_fields != kAllServerFieldTypes)) {
     suggestion.children.push_back(GetFillEverythingFromAddressProfileSuggestion(
         Suggestion::Guid(profile.guid())));
   }
@@ -526,18 +591,30 @@
 // `last_filling_granularity`.
 // `last_targeted_fields` specified the last set of fields target by the user.
 // When not present, we default to full form.
+// This function is called only for first-level popup.
 PopupItemId GetProfileSuggestionPopupItemId(
     absl::optional<ServerFieldTypeSet> optional_last_targeted_fields,
-    FieldTypeGroup triggering_field_type_group) {
+    ServerFieldType trigger_field_type) {
   if (!base::FeatureList::IsEnabled(
           features::kAutofillGranularFillingAvailable)) {
     return PopupItemId::kAddressEntry;
   }
 
+  // If a field is not classified as an address, then autofill was triggered
+  // from the context menu.
+  if (!IsAddressType(trigger_field_type) &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillForUnclassifiedFieldsAvailable)) {
+    return PopupItemId::kAddressEntryNotSelectable;
+  }
+
+  const FieldTypeGroup trigger_field_type_group =
+      GroupTypeOfServerFieldType(trigger_field_type);
+
   // Lambda to return the expected `PopupItemId` when
   // `optional_last_targeted_fields` matches one of the granular filling groups.
   auto get_popup_item_id_for_group_filling = [&] {
-    switch (triggering_field_type_group) {
+    switch (trigger_field_type_group) {
       case FieldTypeGroup::kName:
         return PopupItemId::kFillFullName;
       case FieldTypeGroup::kAddress:
@@ -547,12 +624,16 @@
         return PopupItemId::kFillFullPhoneNumber;
       case FieldTypeGroup::kEmail:
         return PopupItemId::kFillFullEmail;
-      default:
-        // If the 'current_granularity' is group filling, BUT the current
-        // focused field is not one for which group we offer group filling,
-        // we default back to fill full form behaviour/pre-granular filling
-        // popup id.
+      case FieldTypeGroup::kBirthdateField:
         return PopupItemId::kAddressEntry;
+      case FieldTypeGroup::kNoGroup:
+      case FieldTypeGroup::kCreditCard:
+      case FieldTypeGroup::kPasswordField:
+      case FieldTypeGroup::kTransaction:
+      case FieldTypeGroup::kUsernameField:
+      case FieldTypeGroup::kUnfillable:
+      case FieldTypeGroup::kIban:
+        NOTREACHED_NORETURN();
     }
   };
 
@@ -686,11 +767,17 @@
 
   // Generate disambiguating labels based on the list of matches.
   std::vector<std::u16string> differentiating_labels;
-  if (formatter) {
+
+  if (!IsAddressType(trigger_field_type) &&
+      base::FeatureList::IsEnabled(
+          features::kAutofillForUnclassifiedFieldsAvailable)) {
+    differentiating_labels =
+        GetProfileSuggestionLabelForNonAddressField(profiles, app_locale);
+  } else if (formatter) {
     differentiating_labels = formatter->GetLabels();
   } else {
     AutofillProfile::CreateInferredLabels(profiles, field_types,
-                                          trigger_field_type, 1, app_locale,
+                                          {trigger_field_type}, 1, app_locale,
                                           &differentiating_labels);
   }
 
@@ -1110,7 +1197,7 @@
     suggestions.back().acceptance_a11y_announcement =
         l10n_util::GetStringUTF16(IDS_AUTOFILL_A11Y_ANNOUNCE_FILLED_FORM);
     suggestions.back().popup_item_id = GetProfileSuggestionPopupItemId(
-        last_targeted_fields, trigger_field_type_group);
+        last_targeted_fields, trigger_field_type);
     suggestions.back().hidden_prior_to_address_rewriter_usage =
         previously_hidden_profiles_guid.contains(profile->guid());
     if (suggestions.back().popup_item_id ==
@@ -1312,7 +1399,8 @@
                              suggestion);
   AddContactChildSuggestions(trigger_field_type, profile, app_locale,
                              suggestion);
-  AddFooterChildSuggestions(profile, last_targeted_fields, suggestion);
+  AddFooterChildSuggestions(profile, trigger_field_type, last_targeted_fields,
+                            suggestion);
 }
 
 std::vector<Suggestion>
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index 316fdf9..c955b09 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -1393,15 +1393,6 @@
   EXPECT_EQ(suggestions[0].icon, Suggestion::Icon::kLocation);
 }
 
-// Fallback to full form (PopupItemId::kAddressEntry) when the last targeted
-// fields are a group but the triggering field does not match any group.
-TEST_F(AutofillChildrenSuggestionsGenenarationTest,
-       CreateSuggestionsFromProfiles_LastTargetedFieldsAreGroup_Fallback) {
-  std::vector<Suggestion> suggestions = CreateSuggestionWithChildrenFromProfile(
-      profile(), kAllServerFieldTypes, CREDIT_CARD_TYPE);
-  EXPECT_EQ(suggestions[0].popup_item_id, PopupItemId::kAddressEntry);
-}
-
 // Asserts that when the triggering field is a phone field, the phone number
 // suggestion is of type `PopupItemId::kFillFullPhoneNumber`. In other
 // scenarios, phone number is of type `PopupItemId::kAddressFieldByFieldFilling`
@@ -1610,6 +1601,179 @@
   }));
 }
 
+class AutofillNonAddressFieldsSuggestionsGenenarationTest
+    : public AutofillChildrenSuggestionsGenenarationTest {
+ public:
+  void SetUp() override {
+    AutofillChildrenSuggestionsGenenarationTest::SetUp();
+    scoped_feature_list_.InitWithFeatures(
+        /*enabled_features=*/{features::kAutofillGranularFillingAvailable,
+                              features::
+                                  kAutofillForUnclassifiedFieldsAvailable},
+        /*disabled_features=*/{});
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(AutofillNonAddressFieldsSuggestionsGenenarationTest,
+       AllProfilesGenerateSuggestions) {
+  personal_data()->AddProfile(test::GetFullProfile());
+  personal_data()->AddProfile(test::GetFullProfile2());
+
+  FormFieldData triggering_field;
+
+  EXPECT_EQ(suggestion_generator()
+                ->GetSuggestionsForProfiles(
+                    {UNKNOWN_TYPE}, triggering_field, UNKNOWN_TYPE,
+                    /*last_targeted_fields=*/absl::nullopt,
+                    AutofillSuggestionTriggerSource::kManualFallbackAddress)
+                .size(),
+            2u);
+}
+
+// Generally, a profile is displayed with name as main text and address as
+// label. But with incomplete profiles, it might be problematic. This test
+// creates various incomplete profiles and makes sure that a main text and a
+// label are always chosen from the available fields (or only main_text if the
+// profile has only one field).
+TEST_F(AutofillNonAddressFieldsSuggestionsGenenarationTest,
+       SuggestionsAreCorrectAndExpectedLabelsAreCreated) {
+  std::vector<AutofillProfile> profiles(
+      5, AutofillProfile(i18n_model_definition::kLegacyHierarchyCountryCode));
+  profiles[0].SetRawInfo(NAME_FULL, u"test0");
+  profiles[0].SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, u"test0_label");
+  profiles[1].SetRawInfo(NAME_FULL, u"test1");
+  profiles[1].SetRawInfo(ADDRESS_HOME_CITY, u"test1_label");
+  profiles[2].SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, u"test2");
+  profiles[2].SetRawInfo(ADDRESS_HOME_CITY, u"test2_label");
+  profiles[3].SetRawInfo(ADDRESS_HOME_CITY, u"test3");
+  profiles[3].SetRawInfo(EMAIL_ADDRESS, u"test3_label");
+  profiles[4].SetRawInfo(EMAIL_ADDRESS, u"test4");
+
+  std::vector<Suggestion> suggestions =
+      suggestion_generator()->CreateSuggestionsFromProfiles(
+          {&profiles[0], &profiles[1], &profiles[2], &profiles[3],
+           &profiles[4]},
+          {UNKNOWN_TYPE},
+          /*last_targeted_fields=*/absl::nullopt, UNKNOWN_TYPE,
+          /*trigger_field_max_length=*/0);
+
+  ASSERT_EQ(5u, suggestions.size());
+  EXPECT_THAT(
+      suggestions,
+      ElementsAre(AllOf(Field(&Suggestion::main_text,
+                              Suggestion::Text(
+                                  u"test0", Suggestion::Text::IsPrimary(true))),
+                        Field(&Suggestion::labels,
+                              std::vector<std::vector<Suggestion::Text>>{
+                                  {Suggestion::Text(u"test0_label")}}),
+                        Field(&Suggestion::popup_item_id,
+                              PopupItemId::kAddressEntryNotSelectable)),
+                  AllOf(Field(&Suggestion::main_text,
+                              Suggestion::Text(
+                                  u"test1", Suggestion::Text::IsPrimary(true))),
+                        Field(&Suggestion::labels,
+                              std::vector<std::vector<Suggestion::Text>>{
+                                  {Suggestion::Text(u"test1_label")}}),
+                        Field(&Suggestion::popup_item_id,
+                              PopupItemId::kAddressEntryNotSelectable)),
+                  AllOf(Field(&Suggestion::main_text,
+                              Suggestion::Text(
+                                  u"test2", Suggestion::Text::IsPrimary(true))),
+                        Field(&Suggestion::labels,
+                              std::vector<std::vector<Suggestion::Text>>{
+                                  {Suggestion::Text(u"test2_label")}}),
+                        Field(&Suggestion::popup_item_id,
+                              PopupItemId::kAddressEntryNotSelectable)),
+                  AllOf(Field(&Suggestion::main_text,
+                              Suggestion::Text(
+                                  u"test3", Suggestion::Text::IsPrimary(true))),
+                        Field(&Suggestion::labels,
+                              std::vector<std::vector<Suggestion::Text>>{
+                                  {Suggestion::Text(u"test3_label")}}),
+                        Field(&Suggestion::popup_item_id,
+                              PopupItemId::kAddressEntryNotSelectable)),
+                  AllOf(Field(&Suggestion::main_text,
+                              Suggestion::Text(
+                                  u"test4", Suggestion::Text::IsPrimary(true))),
+                        Field(&Suggestion::labels,
+                              std::vector<std::vector<Suggestion::Text>>{{}}),
+                        Field(&Suggestion::popup_item_id,
+                              PopupItemId::kAddressEntryNotSelectable))));
+}
+
+// Tests that a non-address field suggestion has all the profile fields as
+// children, and doesn't have children like "Fill full address" or "Fill full
+// name".
+TEST_F(AutofillNonAddressFieldsSuggestionsGenenarationTest,
+       SuggestionHasCorrectChildren) {
+  std::vector<Suggestion> suggestions = CreateSuggestionWithChildrenFromProfile(
+      profile(), absl::nullopt, UNKNOWN_TYPE);
+
+  // The child suggestions should be:
+  //
+  // 1. first name
+  // 2. middle name
+  // 3. family name
+  // 4. line separator
+  // 5. address line 1
+  // 6. address line 2
+  // 7. Zip
+  // 8. line separator
+  // 9. phone number
+  // 10. email
+  // 11. line separator
+  // 12. edit address
+  // 13. delete address
+  ASSERT_EQ(suggestions.size(), 1u);
+  ASSERT_EQ(13u, suggestions[0].children.size());
+
+  EXPECT_THAT(
+      suggestions[0].children,
+      ElementsAre(
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(NAME_FIRST, app_locale()), NAME_FIRST,
+              Suggestion::Guid(profile().guid())),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(NAME_MIDDLE, app_locale()), NAME_MIDDLE,
+              Suggestion::Guid(profile().guid())),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(NAME_LAST, app_locale()), NAME_LAST,
+              Suggestion::Guid(profile().guid())),
+          EqualsSuggestion(PopupItemId::kSeparator),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(ADDRESS_HOME_LINE1, app_locale()),
+              ADDRESS_HOME_LINE1, Suggestion::Guid(profile().guid())),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(ADDRESS_HOME_LINE2, app_locale()),
+              ADDRESS_HOME_LINE2, Suggestion::Guid(profile().guid())),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(ADDRESS_HOME_ZIP, app_locale()),
+              ADDRESS_HOME_ZIP, Suggestion::Guid(profile().guid())),
+          EqualsSuggestion(PopupItemId::kSeparator),
+          // Triggering field is not a phone number, international phone number
+          // should be shown to the user.
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              GetFormattedInternationalNumber(), PHONE_HOME_WHOLE_NUMBER,
+              Suggestion::Guid(profile().guid())),
+          EqualsFieldByFieldFillingSuggestion(
+              PopupItemId::kAddressFieldByFieldFilling,
+              profile().GetInfo(EMAIL_ADDRESS, app_locale()), EMAIL_ADDRESS,
+              Suggestion::Guid(profile().guid())),
+          EqualsSuggestion(PopupItemId::kSeparator),
+          EqualsSuggestion(PopupItemId::kEditAddressProfile),
+          EqualsSuggestion(PopupItemId::kDeleteAddressProfile)));
+}
+
 // TODO(crbug.com/1477646): Investigate AssignLabelsAndDeduplicate and remove
 // the test if it is not needed.
 TEST_F(AutofillSuggestionGeneratorTest,
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index cd5df36..c8de60191 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -2019,8 +2019,10 @@
   }
 
   client().GetCrowdsourcingManager()->StartUploadRequest(
-      *submitted_form, was_autofilled, non_empty_types,
-      /*login_form_signature=*/std::string(), observed_submission,
+      /*upload_contents=*/submitted_form->EncodeUploadRequest(
+          non_empty_types, was_autofilled,
+          /*login_form_signature=*/{}, observed_submission),
+      submitted_form->submission_source(), submitted_form->active_field_count(),
       client().GetPrefs(), GetWeakPtr());
 }
 
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index 0e7bb972..e2b7a36 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -141,6 +141,10 @@
 using ::testing::SaveArg;
 using ::testing::UnorderedElementsAre;
 using ::testing::VariantWith;
+using upload_contents_matchers::FieldAutofillTypeIs;
+using upload_contents_matchers::FieldsAre;
+using upload_contents_matchers::FormSignatureIs;
+using upload_contents_matchers::ObservedSubmissionIs;
 
 const std::string kArbitraryNickname = "Grocery Card";
 const std::u16string kArbitraryNickname16 = u"Grocery Card";
@@ -10785,7 +10789,8 @@
     BrowserAutofillManagerTest::SetUp();
 
     // All uploads should be expected explicitly.
-    EXPECT_CALL(*crowdsourcing_manager(), StartUploadRequest).Times(0);
+    EXPECT_CALL(*crowdsourcing_manager(), StartUploadRequest(_, _, _, _, _))
+        .Times(0);
 
     form_.name = u"MyForm";
     form_.url = GURL("https://myform.com/form.html");
@@ -10813,20 +10818,17 @@
 // Ensure that a vote is submitted after a regular form submission.
 TEST_F(BrowserAutofillManagerVotingTest, Submission) {
   SimulateTypingFirstNameIntoFirstField();
-
-  std::map<std::u16string, ServerFieldTypeSet> expected_vote_types = {
-      {u"firstname",
-       {ServerFieldType::NAME_FIRST, ServerFieldType::CREDIT_CARD_NAME_FIRST}},
-      {u"lastname", {ServerFieldType::EMPTY_TYPE}},
-  };
-
-  // Ensure that vote is submitted after form submission.
   EXPECT_CALL(
       *crowdsourcing_manager(),
-      StartUploadRequest(AllOf(SignatureIs(CalculateFormSignature(form_)),
-                               UploadedAutofillTypesAre(expected_vote_types)),
-                         _, _, _, /*observed_submission=*/true, _, _))
-      .Times(1);
+      StartUploadRequest(
+          FirstElementIs(AllOf(
+              FormSignatureIs(CalculateFormSignature(form_)),
+              FieldsAre(FieldAutofillTypeIs(
+                            {ServerFieldType::NAME_FIRST,
+                             ServerFieldType::CREDIT_CARD_NAME_FIRST}),
+                        FieldAutofillTypeIs({ServerFieldType::EMPTY_TYPE})),
+              ObservedSubmissionIs(true))),
+          _, _, _, _));
   FormSubmitted(form_);
 }
 
@@ -10847,19 +10849,19 @@
 
   // 4. Simulate removing the focus from the form, which generates a second blur
   // vote which should be sent.
-  std::map<std::u16string, ServerFieldTypeSet> expected_vote_types = {
-      {u"firstname",
-       {ServerFieldType::NAME_FIRST, ServerFieldType::CREDIT_CARD_NAME_FIRST}},
-      {u"lastname",
-       {ServerFieldType::NAME_LAST, ServerFieldType::CREDIT_CARD_NAME_LAST,
-        ServerFieldType::NAME_LAST_SECOND}},
-  };
-  EXPECT_CALL(
-      *crowdsourcing_manager(),
-      StartUploadRequest(AllOf(SignatureIs(first_form_signature),
-                               UploadedAutofillTypesAre(expected_vote_types)),
-                         _, _, _, /*observed_submission=*/false, _, _))
-      .Times(1);
+  EXPECT_CALL(*crowdsourcing_manager(),
+              StartUploadRequest(
+                  FirstElementIs(AllOf(
+                      FormSignatureIs(first_form_signature),
+                      FieldsAre(FieldAutofillTypeIs(
+                                    {ServerFieldType::NAME_FIRST,
+                                     ServerFieldType::CREDIT_CARD_NAME_FIRST}),
+                                FieldAutofillTypeIs(
+                                    {ServerFieldType::NAME_LAST,
+                                     ServerFieldType::CREDIT_CARD_NAME_LAST,
+                                     ServerFieldType::NAME_LAST_SECOND})),
+                      ObservedSubmissionIs(false))),
+                  _, _, _, _));
   browser_autofill_manager_->OnFocusNoLongerOnForm(true);
 
   // 5. Grow the form by one field, which changes the form signature.
@@ -10873,19 +10875,18 @@
   EXPECT_NE(first_form_signature, second_form_signature);
   // Because the next field after the two names is not a credit card field,
   // field disambiguation removes the credit card name votes.
-  expected_vote_types = {
-      {u"firstname", {ServerFieldType::NAME_FIRST}},
-      {u"lastname",
-       {ServerFieldType::NAME_LAST, ServerFieldType::NAME_LAST_SECOND}},
-      {u"zip", {ServerFieldType::EMPTY_TYPE}},
-  };
   EXPECT_CALL(
       *crowdsourcing_manager(),
-      StartUploadRequest(AllOf(SignatureIs(second_form_signature),
-                               UploadedAutofillTypesAre(expected_vote_types)),
-                         _, _, _,
-                         /*observed_submission=*/true, _, _))
-      .Times(1);
+      StartUploadRequest(
+          FirstElementIs(AllOf(
+              FormSignatureIs(second_form_signature),
+              FieldsAre(
+                  FieldAutofillTypeIs({ServerFieldType::NAME_FIRST}),
+                  FieldAutofillTypeIs({ServerFieldType::NAME_LAST,
+                                       ServerFieldType::NAME_LAST_SECOND}),
+                  FieldAutofillTypeIs({ServerFieldType::EMPTY_TYPE})),
+              ObservedSubmissionIs(true))),
+          _, _, _, _));
   FormSubmitted(form_);
 }
 
@@ -10894,17 +10895,17 @@
   SimulateTypingFirstNameIntoFirstField();
 
   // Simulate removing focus from form, which triggers a blur vote.
-  std::map<std::u16string, ServerFieldTypeSet> expected_vote_types = {
-      {u"firstname",
-       {ServerFieldType::NAME_FIRST, ServerFieldType::CREDIT_CARD_NAME_FIRST}},
-      {u"lastname", {ServerFieldType::EMPTY_TYPE}},
-  };
   EXPECT_CALL(
       *crowdsourcing_manager(),
-      StartUploadRequest(AllOf(SignatureIs(CalculateFormSignature(form_)),
-                               UploadedAutofillTypesAre(expected_vote_types)),
-                         _, _, _, /*observed_submission=*/false, _, _))
-      .Times(1);
+      StartUploadRequest(
+          FirstElementIs(AllOf(
+              FormSignatureIs(CalculateFormSignature(form_)),
+              FieldsAre(FieldAutofillTypeIs(
+                            {ServerFieldType::NAME_FIRST,
+                             ServerFieldType::CREDIT_CARD_NAME_FIRST}),
+                        FieldAutofillTypeIs({ServerFieldType::EMPTY_TYPE})),
+              ObservedSubmissionIs(false))),
+          _, _, _, _));
   browser_autofill_manager_->OnFocusNoLongerOnForm(true);
 
   // Simulate a navigation. This is when the vote is sent.
@@ -10916,22 +10917,20 @@
 TEST_F(BrowserAutofillManagerVotingTest, NoBlurVoteOnSubmission) {
   SimulateTypingFirstNameIntoFirstField();
 
-  std::map<std::u16string, ServerFieldTypeSet> expected_vote_types = {
-      {u"firstname",
-       {ServerFieldType::NAME_FIRST, ServerFieldType::CREDIT_CARD_NAME_FIRST}},
-      {u"lastname", {ServerFieldType::EMPTY_TYPE}},
-  };
-
   // Simulate removing focus from form, which enqueues a blur vote. The blur
   // vote will be ignored and only the submission will be sent.
   browser_autofill_manager_->OnFocusNoLongerOnForm(true);
-
   EXPECT_CALL(
       *crowdsourcing_manager(),
-      StartUploadRequest(AllOf(SignatureIs(CalculateFormSignature(form_)),
-                               UploadedAutofillTypesAre(expected_vote_types)),
-                         _, _, _, /*observed_submission=*/true, _, _))
-      .Times(1);
+      StartUploadRequest(
+          FirstElementIs(AllOf(
+              FormSignatureIs(CalculateFormSignature(form_)),
+              FieldsAre(FieldAutofillTypeIs(
+                            {ServerFieldType::NAME_FIRST,
+                             ServerFieldType::CREDIT_CARD_NAME_FIRST}),
+                        FieldAutofillTypeIs({ServerFieldType::EMPTY_TYPE})),
+              ObservedSubmissionIs(true))),
+          _, _, _, _));
   FormSubmitted(form_);
 }
 
diff --git a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_manager.h b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_manager.h
index 3f033501..16af6d7 100644
--- a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_manager.h
+++ b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_manager.h
@@ -18,6 +18,7 @@
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/common/signatures.h"
 #include "components/version_info/channel.h"
 #include "net/base/backoff_entry.h"
diff --git a/components/autofill/core/browser/crowdsourcing/mock_autofill_crowdsourcing_manager.h b/components/autofill/core/browser/crowdsourcing/mock_autofill_crowdsourcing_manager.h
index a7d9d6d..7eb8cde 100644
--- a/components/autofill/core/browser/crowdsourcing/mock_autofill_crowdsourcing_manager.h
+++ b/components/autofill/core/browser/crowdsourcing/mock_autofill_crowdsourcing_manager.h
@@ -34,6 +34,15 @@
 
   MOCK_METHOD(bool,
               StartUploadRequest,
+              (std::vector<AutofillUploadContents>,
+               mojom::SubmissionSource,
+               int,
+               PrefService*,
+               base::WeakPtr<Observer>),
+              (override));
+
+  MOCK_METHOD(bool,
+              StartUploadRequest,
               (const FormStructure&,
                bool,
                const ServerFieldTypeSet&,
diff --git a/components/autofill/core/browser/data_model/autofill_profile.cc b/components/autofill/core/browser/data_model/autofill_profile.cc
index a4866058..b52f448 100644
--- a/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -150,16 +150,16 @@
   return SpecificityForType(type1) < SpecificityForType(type2);
 }
 
-// Fills |distinguishing_fields| with a list of fields to use when creating
+// Fills `distinguishing_fields` with a list of fields to use when creating
 // labels that can help to distinguish between two profiles. Draws fields from
-// |suggested_fields| if it is non-NULL; otherwise returns a default list.
-// If |suggested_fields| is non-NULL, does not include |excluded_field| in the
-// list. Otherwise, |excluded_field| is ignored, and should be set to
-// |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
+// `suggested_fields` if it is non-NULL; otherwise returns a default list.
+// If `suggested_fields` is non-NULL, does not include `excluded_fields` in the
+// list. Otherwise, `excluded_fields` is ignored, and should be set to
+// an empty list by convention. The resulting list of fields is sorted in
 // decreasing order of importance.
 void GetFieldsForDistinguishingProfiles(
     const std::vector<ServerFieldType>* suggested_fields,
-    ServerFieldType excluded_field,
+    ServerFieldTypeSet excluded_fields,
     std::vector<ServerFieldType>* distinguishing_fields) {
   static const ServerFieldType kDefaultDistinguishingFields[] = {
       NAME_FULL,
@@ -181,7 +181,7 @@
     default_fields.assign(
         kDefaultDistinguishingFields,
         kDefaultDistinguishingFields + std::size(kDefaultDistinguishingFields));
-    if (excluded_field == UNKNOWN_TYPE) {
+    if (excluded_fields.empty()) {
       distinguishing_fields->swap(default_fields);
       return;
     }
@@ -189,10 +189,12 @@
   }
 
   // Keep track of which fields we've seen so that we avoid duplicate entries.
-  // Always ignore fields of unknown type and the excluded field.
+  // Always ignore fields of unknown type and those part of `excluded_fields`.
   ServerFieldTypeSet seen_fields;
   seen_fields.insert(UNKNOWN_TYPE);
-  seen_fields.insert(GetStorableTypeCollapsingGroups(excluded_field));
+  for (ServerFieldType excluded_field : excluded_fields) {
+    seen_fields.insert(GetStorableTypeCollapsingGroups(excluded_field));
+  }
 
   distinguishing_fields->clear();
   for (const ServerFieldType& it : *suggested_fields) {
@@ -204,13 +206,18 @@
   std::sort(distinguishing_fields->begin(), distinguishing_fields->end(),
             CompareSpecificity);
 
-  // Special case: If the excluded field is a partial name (e.g. first name) and
-  // the suggested fields include other name fields, include |NAME_FULL| in the
-  // list of distinguishing fields as a last-ditch fallback. This allows us to
-  // distinguish between profiles that are identical except for the name.
-  ServerFieldType effective_excluded_type =
-      GetStorableTypeCollapsingGroups(excluded_field);
-  if (excluded_field != effective_excluded_type) {
+  // Special case: If one of the excluded fields is a partial name (e.g.
+  // `NAME_FIRST`) or phone number (e.g `PHONE_HOME_CITY_CODE`) and the
+  // suggested fields include other name or phone fields fields, include
+  // `NAME_FULL` or `PHONE_HOME_WHOLE_NUMBER` in the list of distinguishing
+  // fields as a last-ditch fallback. This allows us to distinguish between
+  // profiles that are identical except for the name or phone number.
+  for (ServerFieldType excluded_field : excluded_fields) {
+    ServerFieldType effective_excluded_type =
+        GetStorableTypeCollapsingGroups(excluded_field);
+    if (excluded_field == effective_excluded_type) {
+      continue;
+    }
     for (const ServerFieldType& it : *suggested_fields) {
       if (it != excluded_field &&
           GetStorableTypeCollapsingGroups(it) == effective_excluded_type) {
@@ -885,8 +892,8 @@
     const std::string& app_locale,
     std::vector<std::u16string>* labels) {
   const size_t kMinimalFieldsShown = 2;
-  CreateInferredLabels(profiles, absl::nullopt, UNKNOWN_TYPE,
-                       kMinimalFieldsShown, app_locale, labels);
+  CreateInferredLabels(profiles, absl::nullopt, {}, kMinimalFieldsShown,
+                       app_locale, labels);
   DCHECK_EQ(profiles.size(), labels->size());
 }
 
@@ -894,7 +901,7 @@
 void AutofillProfile::CreateInferredLabels(
     const std::vector<const AutofillProfile*>& profiles,
     const absl::optional<ServerFieldTypeSet>& suggested_fields,
-    ServerFieldType excluded_field,
+    ServerFieldTypeSet excluded_fields,
     size_t minimal_fields_shown,
     const std::string& app_locale,
     std::vector<std::u16string>* labels) {
@@ -904,7 +911,7 @@
           ? std::vector(suggested_fields->begin(), suggested_fields->end())
           : std::vector<ServerFieldType>();
   GetFieldsForDistinguishingProfiles(
-      suggested_fields ? &suggested_fields_types : nullptr, excluded_field,
+      suggested_fields ? &suggested_fields_types : nullptr, excluded_fields,
       &fields_to_use);
 
   // Construct the default label for each profile. Also construct a map that
diff --git a/components/autofill/core/browser/data_model/autofill_profile.h b/components/autofill/core/browser/data_model/autofill_profile.h
index 4304b724..c1a404a 100644
--- a/components/autofill/core/browser/data_model/autofill_profile.h
+++ b/components/autofill/core/browser/data_model/autofill_profile.h
@@ -198,17 +198,17 @@
       const std::string& app_locale,
       std::vector<std::u16string>* labels);
 
-  // Creates inferred labels for |profiles|, according to the rules above and
-  // stores them in |created_labels|. If |suggested_fields| is not NULL, the
-  // resulting label fields are drawn from |suggested_fields|, except excluding
-  // |excluded_field|. Otherwise, the label fields are drawn from a default set,
-  // and |excluded_field| is ignored; by convention, it should be of
-  // |UNKNOWN_TYPE| when |suggested_fields| is NULL. Each label includes at
-  // least |minimal_fields_shown| fields, if possible.
+  // Creates inferred labels for `profiles`, according to the rules above and
+  // stores them in `labels`. If `suggested_fields` is not nullopt, the
+  // resulting label fields are drawn from it minus those in
+  // `excluded_fields`. Otherwise, the label fields are drawn from a default
+  // set, and `excluded_fields` are ignored; by convention, it should be
+  // an empty set when `suggested_fields` is nullopt. Each label includes at
+  // least `minimal_fields_shown` fields, if possible.
   static void CreateInferredLabels(
       const std::vector<const AutofillProfile*>& profiles,
       const absl::optional<ServerFieldTypeSet>& suggested_fields,
-      ServerFieldType excluded_field,
+      ServerFieldTypeSet excluded_fields,
       size_t minimal_fields_shown,
       const std::string& app_locale,
       std::vector<std::u16string>* labels);
diff --git a/components/autofill/core/browser/data_model/autofill_profile_unittest.cc b/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
index 8a230b90..d147bac2 100644
--- a/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
@@ -289,9 +289,8 @@
 
   std::vector<std::u16string> labels;
   for (size_t i = 0; i < std::size(kExpectedLabels); ++i) {
-    AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                          absl::nullopt, UNKNOWN_TYPE, i,
-                                          "en-US", &labels);
+    AutofillProfile::CreateInferredLabels(
+        ToRawPointerVector(profiles), absl::nullopt, {}, i, "en-US", &labels);
     ASSERT_FALSE(labels.empty());
     EXPECT_EQ(UTF8ToUTF16(kExpectedLabels[i]), labels.back());
   }
@@ -324,9 +323,8 @@
 
   std::vector<std::u16string> labels;
   for (size_t i = 0; i < std::size(kExpectedLabels); ++i) {
-    AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                          absl::nullopt, UNKNOWN_TYPE, i,
-                                          "en-US", &labels);
+    AutofillProfile::CreateInferredLabels(
+        ToRawPointerVector(profiles), absl::nullopt, {}, i, "en-US", &labels);
     ASSERT_FALSE(labels.empty());
     EXPECT_EQ(UTF8ToUTF16(kExpectedLabels[i]), labels.back());
   }
@@ -369,9 +367,8 @@
 
   std::vector<std::u16string> labels;
   for (size_t i = 0; i < std::size(kExpectedLabels); ++i) {
-    AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                          absl::nullopt, UNKNOWN_TYPE, i,
-                                          "en-US", &labels);
+    AutofillProfile::CreateInferredLabels(
+        ToRawPointerVector(profiles), absl::nullopt, {}, i, "en-US", &labels);
     ASSERT_FALSE(labels.empty());
     EXPECT_EQ(UTF8ToUTF16(kExpectedLabels[i]), labels.back());
   }
@@ -407,9 +404,8 @@
 
   std::vector<std::u16string> labels;
   for (size_t i = 0; i < std::size(kExpectedLabels); ++i) {
-    AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                          absl::nullopt, UNKNOWN_TYPE, i,
-                                          "en-US", &labels);
+    AutofillProfile::CreateInferredLabels(
+        ToRawPointerVector(profiles), absl::nullopt, {}, i, "en-US", &labels);
     ASSERT_FALSE(labels.empty());
     EXPECT_EQ(UTF8ToUTF16(kExpectedLabels[i]), labels.back());
   }
@@ -441,9 +437,8 @@
 
   std::vector<std::u16string> labels;
   for (size_t i = 0; i < std::size(kExpectedLabels); ++i) {
-    AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                          absl::nullopt, UNKNOWN_TYPE, i,
-                                          "en-US", &labels);
+    AutofillProfile::CreateInferredLabels(
+        ToRawPointerVector(profiles), absl::nullopt, {}, i, "en-US", &labels);
     ASSERT_FALSE(labels.empty());
     EXPECT_EQ(UTF8ToUTF16(kExpectedLabels[i]), labels.back());
   }
@@ -464,15 +459,13 @@
   std::vector<std::u16string> labels;
   // Two fields at least - no filter.
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        absl::nullopt, UNKNOWN_TYPE, 2, "en-US",
-                                        &labels);
+                                        absl::nullopt, {}, 2, "en-US", &labels);
   EXPECT_EQ(u"John Doe, 666 Erebus St.", labels[0]);
   EXPECT_EQ(u"Jane Doe, 123 Letha Shore.", labels[1]);
 
   // Three fields at least - no filter.
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        absl::nullopt, UNKNOWN_TYPE, 3, "en-US",
-                                        &labels);
+                                        absl::nullopt, {}, 3, "en-US", &labels);
   EXPECT_EQ(u"John Doe, 666 Erebus St., Elysium", labels[0]);
   EXPECT_EQ(u"Jane Doe, 123 Letha Shore., Dis", labels[1]);
 
@@ -480,23 +473,21 @@
                                          ADDRESS_HOME_ZIP};
 
   // Two fields at least, from suggested fields - no filter.
-  AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, UNKNOWN_TYPE, 2,
-                                        "en-US", &labels);
+  AutofillProfile::CreateInferredLabels(
+      ToRawPointerVector(profiles), suggested_fields, {}, 2, "en-US", &labels);
   EXPECT_EQ(u"Elysium 91111", labels[0]);
   EXPECT_EQ(u"Dis 91222", labels[1]);
 
   // Three fields at least, from suggested fields - no filter.
-  AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, UNKNOWN_TYPE, 3,
-                                        "en-US", &labels);
+  AutofillProfile::CreateInferredLabels(
+      ToRawPointerVector(profiles), suggested_fields, {}, 3, "en-US", &labels);
   EXPECT_EQ(u"Elysium, CA 91111", labels[0]);
   EXPECT_EQ(u"Dis, CA 91222", labels[1]);
 
   // Three fields at least, from suggested fields - but filter reduces available
   // fields to two.
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, ADDRESS_HOME_ZIP, 3,
+                                        suggested_fields, {ADDRESS_HOME_ZIP}, 3,
                                         "en-US", &labels);
   EXPECT_EQ(u"Elysium, CA", labels[0]);
   EXPECT_EQ(u"Dis, CA", labels[1]);
@@ -504,16 +495,15 @@
   // In our implementation we always display NAME_FULL for all NAME* fields...
   suggested_fields = {NAME_MIDDLE};
   // One field at least, from suggested fields - no filter.
-  AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, UNKNOWN_TYPE, 1,
-                                        "en-US", &labels);
+  AutofillProfile::CreateInferredLabels(
+      ToRawPointerVector(profiles), suggested_fields, {}, 1, "en-US", &labels);
   EXPECT_EQ(u"John Doe", labels[0]);
   EXPECT_EQ(u"Jane Doe", labels[1]);
 
   // One field at least, from suggested fields - filter the same as suggested
   // field.
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, NAME_MIDDLE, 1,
+                                        suggested_fields, {NAME_MIDDLE}, 1,
                                         "en-US", &labels);
   EXPECT_EQ(std::u16string(), labels[0]);
   EXPECT_EQ(std::u16string(), labels[1]);
@@ -521,9 +511,8 @@
   // In our implementation we always display NAME_FULL for NAME_MIDDLE_INITIAL
   suggested_fields = {NAME_MIDDLE};
   // One field at least, from suggested fields - no filter.
-  AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, UNKNOWN_TYPE, 1,
-                                        "en-US", &labels);
+  AutofillProfile::CreateInferredLabels(
+      ToRawPointerVector(profiles), suggested_fields, {}, 1, "en-US", &labels);
   EXPECT_EQ(u"John Doe", labels[0]);
   EXPECT_EQ(u"Jane Doe", labels[1]);
 
@@ -531,14 +520,14 @@
   // unknown suggested field.
   suggested_fields = {UNKNOWN_TYPE, NAME_FULL, ADDRESS_HOME_LINE1};
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, NAME_FULL, 1, "en-US",
-                                        &labels);
+                                        suggested_fields, {NAME_FULL}, 1,
+                                        "en-US", &labels);
   EXPECT_EQ(std::u16string(u"666 Erebus St."), labels[0]);
   EXPECT_EQ(std::u16string(u"123 Letha Shore."), labels[1]);
 
   // No suggested fields, but non-unknown excluded field.
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        absl::nullopt, NAME_FULL, 1, "en-US",
+                                        absl::nullopt, {NAME_FULL}, 1, "en-US",
                                         &labels);
   EXPECT_EQ(std::u16string(u"666 Erebus St."), labels[0]);
   EXPECT_EQ(std::u16string(u"123 Letha Shore."), labels[1]);
@@ -564,8 +553,8 @@
                                          EMAIL_ADDRESS};
   std::vector<std::u16string> labels;
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, NAME_LAST, 1, "en-US",
-                                        &labels);
+                                        suggested_fields, {NAME_LAST}, 1,
+                                        "en-US", &labels);
   ASSERT_EQ(2U, labels.size());
   EXPECT_EQ(u"88 Nowhere Ave.", labels[0]);
   EXPECT_EQ(u"88 Nowhere Ave.", labels[1]);
@@ -573,8 +562,8 @@
   // Otherwise, we should.
   suggested_fields.insert(NAME_FIRST);
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, NAME_LAST, 1, "en-US",
-                                        &labels);
+                                        suggested_fields, {NAME_LAST}, 1,
+                                        "en-US", &labels);
   ASSERT_EQ(2U, labels.size());
   EXPECT_EQ(u"88 Nowhere Ave., John Doe", labels[0]);
   EXPECT_EQ(u"88 Nowhere Ave., Johnny K Doe", labels[1]);
@@ -596,9 +585,8 @@
   // should not fall back to the full name as a distinguishing field.
   ServerFieldTypeSet suggested_fields = {ADDRESS_HOME_LINE1, EMAIL_ADDRESS};
   std::vector<std::u16string> labels;
-  AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, UNKNOWN_TYPE, 2,
-                                        "en-US", &labels);
+  AutofillProfile::CreateInferredLabels(
+      ToRawPointerVector(profiles), suggested_fields, {}, 2, "en-US", &labels);
   ASSERT_EQ(2U, labels.size());
   EXPECT_EQ(u"88 Nowhere Ave., doe@example.com", labels[0]);
   EXPECT_EQ(u"88 Nowhere Ave., dojo@example.com", labels[1]);
@@ -623,8 +611,7 @@
 
   std::vector<std::u16string> labels;
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        absl::nullopt, UNKNOWN_TYPE, 3, "en-US",
-                                        &labels);
+                                        absl::nullopt, {}, 3, "en-US", &labels);
   ASSERT_EQ(3U, labels.size());
   EXPECT_EQ(u"John Doe, doe@example.com, Gogole", labels[0]);
   EXPECT_EQ(u"John Doe, doe@example.com, Ggoole", labels[1]);
@@ -634,8 +621,7 @@
   // distinguishing field.
   profiles[1]->SetRawInfo(ADDRESS_HOME_LINE1, u"88 Nowhere Ave.");
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        absl::nullopt, UNKNOWN_TYPE, 1, "en-US",
-                                        &labels);
+                                        absl::nullopt, {}, 1, "en-US", &labels);
   ASSERT_EQ(3U, labels.size());
   EXPECT_EQ(u"John Doe, doe@example.com, Gogole", labels[0]);
   EXPECT_EQ(u"John Doe, 88 Nowhere Ave., doe@example.com, Ggoole", labels[1])
@@ -657,8 +643,8 @@
                                          ADDRESS_HOME_STREET_ADDRESS};
   std::vector<std::u16string> labels;
   AutofillProfile::CreateInferredLabels(ToRawPointerVector(profiles),
-                                        suggested_fields, NAME_FULL, 1, "en-US",
-                                        &labels);
+                                        suggested_fields, {NAME_FULL}, 1,
+                                        "en-US", &labels);
   ASSERT_EQ(1U, labels.size());
   EXPECT_EQ(u"88 Nowhere Ave., Apt. 42", labels[0]);
 }
diff --git a/components/autofill/core/browser/metrics/log_event.cc b/components/autofill/core/browser/metrics/log_event.cc
index 96cef8d..07ba8901 100644
--- a/components/autofill/core/browser/metrics/log_event.cc
+++ b/components/autofill/core/browser/metrics/log_event.cc
@@ -53,12 +53,12 @@
 
 bool AreCollapsible(const TriggerFillFieldLogEvent& event1,
                     const TriggerFillFieldLogEvent& event2) {
-  return event1.fill_event_id != event2.fill_event_id;
+  return event1.fill_event_id == event2.fill_event_id;
 }
 
 bool AreCollapsible(const FillFieldLogEvent& event1,
                     const FillFieldLogEvent& event2) {
-  return event1.fill_event_id != event2.fill_event_id &&
+  return event1.fill_event_id == event2.fill_event_id &&
          event1.had_value_before_filling == event2.had_value_before_filling &&
          event1.autofill_skipped_status == event2.autofill_skipped_status &&
          event1.was_autofilled == event2.was_autofilled &&
diff --git a/components/autofill/core/browser/metrics/log_event.h b/components/autofill/core/browser/metrics/log_event.h
index 82bb426..1f601f8 100644
--- a/components/autofill/core/browser/metrics/log_event.h
+++ b/components/autofill/core/browser/metrics/log_event.h
@@ -95,7 +95,7 @@
 // Log the field that triggers the suggestion that the user selects to fill.
 struct TriggerFillFieldLogEvent {
   FillEventId fill_event_id = GetNextFillEventId();
-  // The type of filled data for the autofil event.
+  // The type of filled data for the Autofill event.
   FillDataType data_type = internal::IsRequired();
   // The country_code associated with the information filled. Only present for
   // autofill addresses (i.e. `AutofillEventType::kAutofillProfile`).
diff --git a/components/autofill/core/browser/profile_token_quality.cc b/components/autofill/core/browser/profile_token_quality.cc
index 837b13a0..b3d70507 100644
--- a/components/autofill/core/browser/profile_token_quality.cc
+++ b/components/autofill/core/browser/profile_token_quality.cc
@@ -147,9 +147,19 @@
       // The field was not autofilled or autofilled with a different profile.
       continue;
     }
+    if (!field.autofilled_type()) {
+      // TODO(b/311604770): Field-by-field filling doesn't support
+      // `autofilled_type()`.
+      continue;
+    }
+    if (!GetSupportedTypes(*profile_).contains(*field.autofilled_type())) {
+      // If the user changed the country of their profile before submission, the
+      // `autofilled_type()` might not be supported anymore.
+      continue;
+    }
 
     const ServerFieldType stored_type =
-        profile_->GetStorableTypeOf(field.Type().GetStorableType());
+        profile_->GetStorableTypeOf(*field.autofilled_type());
     const FormSignatureHash hash =
         GetFormSignatureHash(form_structure.form_signature());
     if (auto observations = observations_.find(stored_type);
@@ -202,7 +212,6 @@
 std::vector<ObservationType>
 ProfileTokenQuality::GetObservationTypesForFieldType(
     ServerFieldType type) const {
-  CHECK(GetSupportedTypes(*profile_).contains(type));
   const auto it = observations_.find(profile_->GetStorableTypeOf(type));
   if (it == observations_.end()) {
     return {};
diff --git a/components/autofill/core/browser/profile_token_quality_unittest.cc b/components/autofill/core/browser/profile_token_quality_unittest.cc
index e371ad2..f7927537 100644
--- a/components/autofill/core/browser/profile_token_quality_unittest.cc
+++ b/components/autofill/core/browser/profile_token_quality_unittest.cc
@@ -221,6 +221,24 @@
               UnorderedElementsAre(ObservationType::kAccepted));
 }
 
+// Tests that when the type of a field changes between filling and submission,
+// observations are collected for the type the field had when it was filled.
+TEST_F(ProfileTokenQualityTest, AddObservationsForFilledForm_DynamicChange) {
+  AutofillProfile profile = test::GetFullProfile();
+  pdm_.AddProfile(profile);
+  ProfileTokenQuality& quality = profile.token_quality();
+
+  FormData form = GetFormWithTypes({NAME_FIRST});
+  FillForm(form, profile);
+
+  FormStructure* form_structure = bam_.FindCachedFormById(form.global_id());
+  form_structure->field(0)->SetTypeTo(AutofillType(NAME_LAST));
+  EXPECT_TRUE(
+      quality.AddObservationsForFilledForm(*form_structure, form, pdm_));
+  EXPECT_THAT(quality.GetObservationTypesForFieldType(NAME_FIRST),
+              UnorderedElementsAre(ObservationType::kAccepted));
+}
+
 // Tests that `SaveObservationsForFilledFormForAllSubmittedProfiles()` collects
 // observations for all profiles that were used to fill the form.
 TEST_F(ProfileTokenQualityTest,
diff --git a/components/autofill/core/browser/test_utils/vote_uploads_test_matchers.h b/components/autofill/core/browser/test_utils/vote_uploads_test_matchers.h
index 3ac8683..8a61dc6 100644
--- a/components/autofill/core/browser/test_utils/vote_uploads_test_matchers.h
+++ b/components/autofill/core/browser/test_utils/vote_uploads_test_matchers.h
@@ -12,6 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/form_structure_test_api.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/common/signatures.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,6 +26,56 @@
 using ::testing::Property;
 using ::testing::ResultOf;
 
+// Returns a container matcher that applies `matcher` to the first element of
+// the container.
+inline auto FirstElementIs(auto matcher) {
+  return ::testing::AllOf(
+      ::testing::SizeIs(::testing::Gt(0u)),
+      ResultOf([](const auto& container) { return container[0]; }, matcher));
+}
+
+// Matchers for `AutofillUploadContents`. These are in their own namespace to
+// make their names briefer.
+namespace upload_contents_matchers {
+
+// Creates a matcher for an `AutofillUploadContents`'s form_signature method
+// against `form_signature`.
+inline ::testing::Matcher<AutofillUploadContents> FormSignatureIs(
+    FormSignature form_signature) {
+  return Property("form_signature", &AutofillUploadContents::form_signature,
+                  form_signature.value());
+}
+
+// Creates a matcher that matches `matchers` against the fields of an
+// `AutofillUploadContents`. It requires that the match (and ordering) is exact.
+template <typename... Matchers>
+inline ::testing::Matcher<AutofillUploadContents> FieldsAre(
+    Matchers... matchers) {
+  return ::testing::Property("field", &AutofillUploadContents::field,
+                             ::testing::ElementsAre(matchers...));
+}
+
+inline ::testing::Matcher<AutofillUploadContents> ObservedSubmissionIs(
+    bool observed_submission) {
+  return ::testing::Property("submission", &AutofillUploadContents::submission,
+                             observed_submission);
+}
+
+// Matchers for `AutofillUploadContents::Field`.
+inline ::testing::Matcher<AutofillUploadContents::Field> FieldAutofillTypeIs(
+    ServerFieldTypeSet type_set) {
+  auto extract_types = [](const AutofillUploadContents::Field& field) {
+    ServerFieldTypeSet s;
+    for (auto type : field.autofill_type()) {
+      s.insert(ToSafeServerFieldType(type, ServerFieldType::NO_SERVER_DATA));
+    }
+    return s;
+  };
+  return ::testing::ResultOf(extract_types, ::testing::Eq(type_set));
+}
+
+}  // namespace upload_contents_matchers
+
 inline auto SignatureIsSameAs(const FormData& form) {
   return Property("form_signature", &FormStructure::form_signature,
                   CalculateFormSignature(form));
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapper.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapper.java
index eda8791e..c2684f85 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapper.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapper.java
@@ -26,7 +26,8 @@
 
     /**
      * Gets the notification metadata.
-     * @See {@link NotificationMetadata}.
+     *
+     * @see {@link NotificationMetadata}.
      */
     public NotificationMetadata getMetadata() {
         return mNotificationMetadata;
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/PendingIntentProvider.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/PendingIntentProvider.java
index bb35def..85537b020 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/PendingIntentProvider.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/PendingIntentProvider.java
@@ -20,7 +20,8 @@
 
     /**
      * Creates {@link PendingIntent}that triggers {@link android.content.BroadcastReceiver}.
-     * @See {@link PendingIntent#getBroadcast(Context, int, Intent, int)}.
+     *
+     * @see {@link PendingIntent#getBroadcast(Context, int, Intent, int)}.
      */
     public static PendingIntentProvider getBroadcast(
             Context context, int requestCode, Intent intent, int flags, boolean mutable) {
@@ -39,7 +40,8 @@
 
     /**
      * Creates {@link PendingIntent} that triggers {@link android.app.Service}.
-     * @See {@link PendingIntent#getService(Context, int, Intent, int)} .
+     *
+     * @see {@link PendingIntent#getService(Context, int, Intent, int)} .
      */
     public static PendingIntentProvider getService(
             Context context, int requestCode, Intent intent, int flags, boolean mutable) {
@@ -56,7 +58,8 @@
 
     /**
      * Creates {@link PendingIntent} that triggers {@link android.app.Activity}.
-     * @See {@link PendingIntent#getActivity(Context, int, Intent, int)}.
+     *
+     * @see {@link PendingIntent#getActivity(Context, int, Intent, int)}.
      */
     public static PendingIntentProvider getActivity(
             Context context, int requestCode, Intent intent, int flags, boolean mutable) {
diff --git a/components/content_capture/android/java/src/org/chromium/components/content_capture/PlatformContentCaptureConsumer.java b/components/content_capture/android/java/src/org/chromium/components/content_capture/PlatformContentCaptureConsumer.java
index 1c898c9b..7e22e02 100644
--- a/components/content_capture/android/java/src/org/chromium/components/content_capture/PlatformContentCaptureConsumer.java
+++ b/components/content_capture/android/java/src/org/chromium/components/content_capture/PlatformContentCaptureConsumer.java
@@ -26,8 +26,8 @@
     /**
      * This method is used when ViewStructure is available.
      *
-     * @Return ContentCaptureConsumer or null if ContentCapture service isn't
-     *         available, disabled or isn't AiAi service.
+     * @return ContentCaptureConsumer or null if ContentCapture service isn't available, disabled or
+     *     isn't AiAi service.
      */
     public static ContentCaptureConsumer create(
             Context context, View view, ViewStructure structure, WebContents webContents) {
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
index 15441565..61c9a14b 100644
--- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
+++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -45,7 +45,8 @@
 
         /**
          * Creates image fetcher parameters. The image will not be resized.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         public static Params create(final GURL url, String clientName) {
             return create(url.getSpec(), clientName);
@@ -53,7 +54,8 @@
 
         /**
          * Creates image fetcher parameters. The image will not be resized.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         @Deprecated
         public static Params create(final String url, String clientName) {
@@ -63,7 +65,8 @@
 
         /**
          * Creates image fetcher parameters with image size specified.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         public static Params create(final GURL url, String clientName, int width, int height) {
             return create(url.getSpec(), clientName, width, height);
@@ -71,7 +74,8 @@
 
         /**
          * Creates image fetcher parameters with image size specified.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         @Deprecated
         public static Params create(final String url, String clientName, int width, int height) {
@@ -82,7 +86,8 @@
 
         /**
          * Creates image fetcher parameters with image size specified.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         public static Params createNoResizing(
                 final GURL url, String clientName, int width, int height) {
@@ -98,7 +103,8 @@
         /**
          * Only used in rare cases. Creates image fetcher parameters that keeps the cache file for a
          * certain period of time.
-         * @See {@link #Params(String, String, int, int, boolean, int)}.
+         *
+         * @see {@link #Params(String, String, int, int, boolean, int)}.
          */
         public static Params createWithExpirationInterval(
                 final GURL url,
diff --git a/components/password_manager/core/browser/affiliation/affiliation_utils.cc b/components/password_manager/core/browser/affiliation/affiliation_utils.cc
index 8152881e..bc541b2 100644
--- a/components/password_manager/core/browser/affiliation/affiliation_utils.cc
+++ b/components/password_manager/core/browser/affiliation/affiliation_utils.cc
@@ -55,7 +55,7 @@
   url::StdStringCanonOutput canonical_output(canonical_uri);
 
   bool canonicalization_succeeded = url::CanonicalizeStandardURL(
-      input_uri.c_str(), input_uri.size(), input_parsed,
+      input_uri.c_str(), input_parsed,
       url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr,
       &canonical_output, &canonical_parsed);
   canonical_output.Complete();
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index cc71322..147d3d4 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -438,7 +438,8 @@
     ON_CALL(*client_.GetPasswordFeatureManager(),
             ShouldShowAccountStorageBubbleUi)
         .WillByDefault(Return(true));
-    ON_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+    ON_CALL(mock_autofill_crowdsourcing_manager_,
+            StartUploadRequest(_, _, _, _, _, _, _))
         .WillByDefault(Return(true));
     ON_CALL(*client_.GetPasswordFeatureManager(), GetDefaultPasswordStore)
         .WillByDefault(Return(PasswordForm::Store::kProfileStore));
@@ -3327,7 +3328,8 @@
                                  ServerFieldTypeSet{NOT_USERNAME}, _, true,
                                  nullptr, /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
diff --git a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
index 64b24f4d..7e6de17 100644
--- a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -281,7 +281,8 @@
 
     ON_CALL(client_, GetAutofillCrowdsourcingManager())
         .WillByDefault(Return(&mock_autofill_crowdsourcing_manager_));
-    ON_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+    ON_CALL(mock_autofill_crowdsourcing_manager_,
+            StartUploadRequest(_, _, _, _, _, _, _))
         .WillByDefault(Return(true));
     ON_CALL(*client_.GetPasswordFeatureManager(), GetDefaultPasswordStore)
         .WillByDefault(Return(PasswordForm::Store::kProfileStore));
@@ -891,7 +892,8 @@
 
   // TODO(https://crbug.com/928690): implement not sending incorrect votes and
   // check that StartUploadRequest is not called.
-  EXPECT_CALL(*mock_autofill_crowdsourcing_manager(), StartUploadRequest)
+  EXPECT_CALL(*mock_autofill_crowdsourcing_manager(),
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(1);
   password_save_manager_impl()->Save(&observed_form_, parsed_submitted_form);
 }
diff --git a/components/password_manager/core/browser/votes_uploader_unittest.cc b/components/password_manager/core/browser/votes_uploader_unittest.cc
index bdc52661..ccf94aa 100644
--- a/components/password_manager/core/browser/votes_uploader_unittest.cc
+++ b/components/password_manager/core/browser/votes_uploader_unittest.cc
@@ -105,7 +105,8 @@
     EXPECT_CALL(client_, GetAutofillCrowdsourcingManager())
         .WillRepeatedly(Return(&mock_autofill_crowdsourcing_manager_));
 
-    ON_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+    ON_CALL(mock_autofill_crowdsourcing_manager_,
+            StartUploadRequest(_, _, _, _, _, _, _))
         .WillByDefault(Return(true));
 
     // Create |fields| in |form_to_upload_| and |submitted_form_|. Only |name|
@@ -259,7 +260,8 @@
   // SendVotesOnSave should call UploadPasswordVote and StartUploadRequest
   // twice. The first call is not the one that should be tested.
   testing::Expectation first_call =
-      EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest);
+      EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+                  StartUploadRequest(_, _, _, _, _, _, _));
 
   EXPECT_CALL(
       mock_autofill_crowdsourcing_manager_,
@@ -636,7 +638,8 @@
 
 TEST_F(VotesUploaderTest, NoSingleUsernameDataNoUpload) {
   VotesUploader votes_uploader(&client_, false);
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
   base::HistogramTester histogram_tester;
   votes_uploader.set_should_send_username_first_flow_votes(true);
@@ -688,7 +691,8 @@
                   false, expected_types, std::string(), true,
                   /* pref_service= */ nullptr, /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -730,7 +734,8 @@
                   false, expected_types, std::string(), true,
                   /* pref_service= */ nullptr, /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -787,7 +792,8 @@
                   /*pref_service=*/nullptr,
                   /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -843,7 +849,8 @@
                   /*pref_service=*/nullptr,
                   /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -898,7 +905,8 @@
                   /*pref_service=*/nullptr,
                   /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
@@ -952,7 +960,8 @@
                   /*pref_service=*/nullptr,
                   /*observer=*/IsNull()));
 #else
-  EXPECT_CALL(mock_autofill_crowdsourcing_manager_, StartUploadRequest)
+  EXPECT_CALL(mock_autofill_crowdsourcing_manager_,
+              StartUploadRequest(_, _, _, _, _, _, _))
       .Times(0);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 059a2e7..c748ca41 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -1190,6 +1190,18 @@
   <message name="IDS_POLICY_DLP_FILES_OPEN_TIMEOUT_MESSAGE" desc="The message for notification shown after a DLP files warning times out.">
     Try opening your files again
   </message>
+ <message name="IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_DATA_CONTROLS_ACCESSIBLE_NAME" desc="The message is read to ChromeVox users when they focus a generic learn more link related to data controls.">
+    Learn more about Data Controls
+  </message>
+ <message name="IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_MALWARE_PROTECTION_ACCESSIBLE_NAME" desc="The message is read to ChromeVox users when they focus a generic learn more link related to enterprise connector's malware protection.">
+    Learn more about Malware protection
+  </message>
+ <message name="IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_SENSITIVE_DATA_PROTECTION_ACCESSIBLE_NAME" desc="The message is read to ChromeVox users when they focus a generic learn more link related to enterprise connector's sensitive data protection.">
+    Learn more about Sensitive Data protection
+  </message>
+  <message name="IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION" desc="The message is read to ChromeVox users when they focus the justification text area.">
+    Please enter a justification message having at most <ph name="MAX_CHAR_COUNT">$2<ex>280</ex></ph> characters. Used <ph name="ACTUAL_CHAR_COUNT">$1<ex>10</ex></ph> out of <ph name="MAX_CHAR_COUNT">$2<ex>280</ex></ph> characters.
+  </message>
   <message name="IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE" desc="The title for notification informing the user that the device will restart soon.">
     Device will restart very soon
   </message>
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..e5195184
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_JUSTIFICATION_TEXTAREA_ACCESSIBLE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+149e88561be52a32afa5e3fb8221a587f2c87c99
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_DATA_CONTROLS_ACCESSIBLE_NAME.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_DATA_CONTROLS_ACCESSIBLE_NAME.png.sha1
new file mode 100644
index 0000000..790d157
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_DATA_CONTROLS_ACCESSIBLE_NAME.png.sha1
@@ -0,0 +1 @@
+5b06ef8eb6d89d7ad55bd2788c063e89e9ad6ece
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_MALWARE_PROTECTION_ACCESSIBLE_NAME.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_MALWARE_PROTECTION_ACCESSIBLE_NAME.png.sha1
new file mode 100644
index 0000000..790d157
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_MALWARE_PROTECTION_ACCESSIBLE_NAME.png.sha1
@@ -0,0 +1 @@
+5b06ef8eb6d89d7ad55bd2788c063e89e9ad6ece
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_SENSITIVE_DATA_PROTECTION_ACCESSIBLE_NAME.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_SENSITIVE_DATA_PROTECTION_ACCESSIBLE_NAME.png.sha1
new file mode 100644
index 0000000..790d157
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_FILES_LEARN_MORE_ABOUT_SENSITIVE_DATA_PROTECTION_ACCESSIBLE_NAME.png.sha1
@@ -0,0 +1 @@
+5b06ef8eb6d89d7ad55bd2788c063e89e9ad6ece
\ No newline at end of file
diff --git a/content/child/browser_exposed_child_interfaces.cc b/content/child/browser_exposed_child_interfaces.cc
index 3720297..19bbb5b 100644
--- a/content/child/browser_exposed_child_interfaces.cc
+++ b/content/child/browser_exposed_child_interfaces.cc
@@ -26,11 +26,15 @@
       base::BindRepeating(&tracing::TracedProcess::OnTracedProcessRequest),
       base::SequencedTaskRunner::GetCurrentDefault());
 
+  // TODO(crbug.com/1505638): Investiagte the reason why the mojo connection
+  // is often created and closed for the same render process on lacros-chrome.
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
   if (!in_browser_process) {
     binders->Add<mojom::SyntheticTrialConfiguration>(
         base::BindRepeating(&ChildProcessSyntheticTrialSyncer::Create),
         base::SequencedTaskRunner::GetCurrentDefault());
   }
+#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
 
   GetContentClient()->ExposeInterfacesToBrowser(io_task_runner, binders);
 }
diff --git a/content/common/service_worker/service_worker_router_evaluator.cc b/content/common/service_worker/service_worker_router_evaluator.cc
index f4721ae..3da8247 100644
--- a/content/common/service_worker/service_worker_router_evaluator.cc
+++ b/content/common/service_worker/service_worker_router_evaluator.cc
@@ -362,10 +362,13 @@
     need_running_status_ = true;
   }
   if (url_pattern) {
+    RE2::Options options;
+    options.set_case_sensitive(!url_pattern->options.ignore_case);
+
 #define SET_PATTERN(type_name, type)                                         \
   do {                                                                       \
     auto regex = ConvertToRegex(*url_pattern, type);                         \
-    type_name##_pattern_ = std::make_unique<RE2>(regex, RE2::Options());     \
+    type_name##_pattern_ = std::make_unique<RE2>(regex, options);            \
     if (!type_name##_pattern_->ok()) {                                       \
       RecordSetupError(ServiceWorkerRouterEvaluatorErrorEnums::kParseError); \
       return false;                                                          \
diff --git a/content/common/service_worker/service_worker_router_evaluator_unittest.cc b/content/common/service_worker/service_worker_router_evaluator_unittest.cc
index 6de3aba0..b14f23eb 100644
--- a/content/common/service_worker/service_worker_router_evaluator_unittest.cc
+++ b/content/common/service_worker/service_worker_router_evaluator_unittest.cc
@@ -767,6 +767,80 @@
   EXPECT_FALSE(eval_result.has_value());
 }
 
+TEST(ServiceWorkerRouterEvaluator, SimpleIgnoreCaseMatch) {
+  blink::ServiceWorkerRouterRules rules;
+  {
+    blink::ServiceWorkerRouterRule rule;
+    {
+      blink::SafeUrlPattern url_pattern = DefaultURLPattern();
+      auto parse_result = liburlpattern::Parse(
+          "/test/*.html",
+          [](base::StringPiece input) { return std::string(input); });
+      ASSERT_TRUE(parse_result.ok());
+      url_pattern.pathname = parse_result.value().PartList();
+      url_pattern.options.ignore_case = true;
+      rule.condition =
+          blink::ServiceWorkerRouterCondition::WithUrlPattern(url_pattern);
+    }
+    {
+      blink::ServiceWorkerRouterSource source;
+      source.type = blink::ServiceWorkerRouterSource::Type::kNetwork;
+      source.network_source.emplace();
+      rule.sources.push_back(source);
+    }
+    rules.rules.push_back(rule);
+  }
+  ASSERT_EQ(1U, rules.rules.size());
+
+  ServiceWorkerRouterEvaluator evaluator(rules);
+  ASSERT_EQ(1U, evaluator.rules().rules.size());
+  EXPECT_TRUE(evaluator.IsValid());
+
+  network::ResourceRequest request;
+  request.method = "GET";
+  request.url = GURL("https://example.com/TeSt/page.HTML");
+  const auto eval_result = evaluator.EvaluateWithoutRunningStatus(request);
+  EXPECT_TRUE(eval_result.has_value());
+  EXPECT_EQ(1U, eval_result->sources.size());
+}
+
+TEST(ServiceWorkerRouterEvaluator, SimpleRespectCaseAndMismatch) {
+  blink::ServiceWorkerRouterRules rules;
+  {
+    blink::ServiceWorkerRouterRule rule;
+    {
+      blink::SafeUrlPattern url_pattern = DefaultURLPattern();
+      auto parse_result = liburlpattern::Parse(
+          "/test/*.html",
+          [](base::StringPiece input) { return std::string(input); });
+      ASSERT_TRUE(parse_result.ok());
+      url_pattern.pathname = parse_result.value().PartList();
+      // Respects case.
+      url_pattern.options.ignore_case = false;
+      rule.condition =
+          blink::ServiceWorkerRouterCondition::WithUrlPattern(url_pattern);
+    }
+    {
+      blink::ServiceWorkerRouterSource source;
+      source.type = blink::ServiceWorkerRouterSource::Type::kNetwork;
+      source.network_source.emplace();
+      rule.sources.push_back(source);
+    }
+    rules.rules.push_back(rule);
+  }
+  ASSERT_EQ(1U, rules.rules.size());
+
+  ServiceWorkerRouterEvaluator evaluator(rules);
+  ASSERT_EQ(1U, evaluator.rules().rules.size());
+  EXPECT_TRUE(evaluator.IsValid());
+
+  network::ResourceRequest request;
+  request.method = "GET";
+  request.url = GURL("https://example.com/TeSt/page.HTML");
+  const auto eval_result = evaluator.EvaluateWithoutRunningStatus(request);
+  EXPECT_FALSE(eval_result.has_value());
+}
+
 TEST(ServiceWorkerRouterEvaluator, EmptyCondition) {
   blink::ServiceWorkerRouterRules rules;
   {
diff --git a/device/vr/android/xr_image_transport_base.cc b/device/vr/android/xr_image_transport_base.cc
index 10bb30b9..55a61eb8 100644
--- a/device/vr/android/xr_image_transport_base.cc
+++ b/device/vr/android/xr_image_transport_base.cc
@@ -194,9 +194,9 @@
 
   static constexpr gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
   static constexpr gfx::BufferUsage usage = gfx::BufferUsage::SCANOUT;
-  uint32_t shared_image_usage = gpu::SHARED_IMAGE_USAGE_SCANOUT |
-                                gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                                gpu::SHARED_IMAGE_USAGE_GLES2;
+  uint32_t shared_image_usage =
+      gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
+      gpu::SHARED_IMAGE_USAGE_GLES2_READ | gpu::SHARED_IMAGE_USAGE_GLES2_WRITE;
 
   // Create a new AHardwareBuffer backed handle.
   buffer->scoped_ahb_handle =
diff --git a/device/vr/openxr/android/openxr_graphics_binding_open_gles.cc b/device/vr/openxr/android/openxr_graphics_binding_open_gles.cc
index 10599cd3..0d123dc3 100644
--- a/device/vr/openxr/android/openxr_graphics_binding_open_gles.cc
+++ b/device/vr/openxr/android/openxr_graphics_binding_open_gles.cc
@@ -220,9 +220,9 @@
 
   static constexpr gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888;
   static constexpr gfx::BufferUsage usage = gfx::BufferUsage::SCANOUT;
-  uint32_t shared_image_usage = gpu::SHARED_IMAGE_USAGE_SCANOUT |
-                                gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                                gpu::SHARED_IMAGE_USAGE_GLES2;
+  uint32_t shared_image_usage =
+      gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
+      gpu::SHARED_IMAGE_USAGE_GLES2_READ | gpu::SHARED_IMAGE_USAGE_GLES2_WRITE;
 
   glGenTextures(1, &swap_chain_info.shared_buffer_texture);
 
diff --git a/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc b/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
index 86b8757..e797b9b 100644
--- a/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
+++ b/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
@@ -183,7 +183,8 @@
         gfx::Size(texture2d_desc.Width, texture2d_desc.Height);
     const uint32_t shared_image_usage = gpu::SHARED_IMAGE_USAGE_SCANOUT |
                                         gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                                        gpu::SHARED_IMAGE_USAGE_GLES2;
+                                        gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                                        gpu::SHARED_IMAGE_USAGE_GLES2_WRITE;
 
     gpu::MailboxHolder& mailbox_holder = swap_chain_info.mailbox_holder;
     auto client_shared_image = sii->CreateSharedImage(
diff --git a/docs/website b/docs/website
index 8fa01e6..7e14119 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit 8fa01e615655f80075f9149063032d3e3d5956df
+Subproject commit 7e14119375ad198e276c3a2eecafb4f9b0970d1f
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index 6b11615..224e2ac 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -587,6 +587,10 @@
 void AppWindow::UpdateDraggableRegions(
     const std::vector<mojom::DraggableRegionPtr>& regions) {
   native_app_window_->UpdateDraggableRegions(regions);
+
+  if (on_update_draggable_regions_callback_for_testing_) {
+    std::move(on_update_draggable_regions_callback_for_testing_).Run();
+  }
 }
 
 void AppWindow::UpdateAppIcon(const gfx::Image& image) {
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index 9acbf152..a9ac5a5 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -394,6 +394,10 @@
     native_app_window_ = std::move(native_app_window);
   }
 
+  void SetOnUpdateDraggableRegionsForTesting(base::OnceClosure callback) {
+    on_update_draggable_regions_callback_for_testing_ = std::move(callback);
+  }
+
   bool DidFinishFirstNavigation() { return did_finish_first_navigation_; }
 
  protected:
@@ -593,6 +597,9 @@
   // processes.
   bool did_finish_first_navigation_ = false;
 
+  // Allows tests to wait for draggable regions to be sent from the renderer.
+  base::OnceClosure on_update_draggable_regions_callback_for_testing_;
+
   base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_{this};
 };
 
diff --git a/extensions/browser/app_window/app_window_browsertest.cc b/extensions/browser/app_window/app_window_browsertest.cc
index 6542e4b..7569520 100644
--- a/extensions/browser/app_window/app_window_browsertest.cc
+++ b/extensions/browser/app_window/app_window_browsertest.cc
@@ -88,6 +88,28 @@
   CloseAppWindow(app_window);
 }
 
+IN_PROC_BROWSER_TEST_F(AppWindowBrowserTest, DraggableFramelessWindow) {
+  AppWindow* app_window = CreateTestAppWindow(R"({ "frame": "none" })");
+
+  base::RunLoop run_loop;
+  app_window->SetOnUpdateDraggableRegionsForTesting(run_loop.QuitClosure());
+
+  static constexpr char kTestScript[] =
+      "window.document.body.style.height = '50px';"
+      "window.document.body.style.width = '100px';"
+      "window.document.body.style.appRegion = 'drag';";
+  content::WebContents* app_contents =
+      app_window->app_window_contents_for_test()->GetWebContents();
+  EXPECT_TRUE(ExecJs(app_contents->GetPrimaryMainFrame(), kTestScript));
+
+  run_loop.Run();
+
+  NativeAppWindow* native_window = GetNativeAppWindowForAppWindow(app_window);
+  SkRegion* draggable_region = native_window->GetDraggableRegion();
+  ASSERT_TRUE(draggable_region);
+  EXPECT_FALSE(draggable_region->isEmpty());
+}
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Disabled due to flake. https://crbug.com/1416579
diff --git a/extensions/common/mojom/app_window.mojom b/extensions/common/mojom/app_window.mojom
index cba4cf6..ec1d1c9 100644
--- a/extensions/common/mojom/app_window.mojom
+++ b/extensions/common/mojom/app_window.mojom
@@ -6,4 +6,8 @@
 
 interface AppWindow {
   SetVisuallyDeemphasized(bool deemphasized);
+
+  // Indicates that the frame should collect draggable regions set using the
+  // app-region CSS property.
+  SetSupportsAppRegion(bool supports_app_region);
 };
diff --git a/extensions/components/native_app_window/native_app_window_views.cc b/extensions/components/native_app_window/native_app_window_views.cc
index e4365ba9..00087f2c 100644
--- a/extensions/components/native_app_window/native_app_window_views.cc
+++ b/extensions/components/native_app_window/native_app_window_views.cc
@@ -11,6 +11,8 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/app_window.h"
+#include "extensions/common/mojom/app_window.mojom.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/controls/webview/webview.h"
@@ -270,6 +272,13 @@
     // initialize it with black background color.
     render_frame_host->GetView()->SetBackgroundColor(SK_ColorBLACK);
   }
+
+  if (frameless_) {
+    mojo::Remote<extensions::mojom::AppWindow> app_window;
+    render_frame_host->GetRemoteInterfaces()->GetInterface(
+        app_window.BindNewPipeAndPassReceiver());
+    app_window->SetSupportsAppRegion(true);
+  }
 }
 
 // views::View implementation.
diff --git a/extensions/renderer/extensions_render_frame_observer.cc b/extensions/renderer/extensions_render_frame_observer.cc
index 5e11d6c..882251b 100644
--- a/extensions/renderer/extensions_render_frame_observer.cc
+++ b/extensions/renderer/extensions_render_frame_observer.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/public/common/logging/logging_utils.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_view.h"
 
 namespace extensions {
 
@@ -97,6 +98,11 @@
   receivers_.Add(this, std::move(receiver));
 }
 
+void ExtensionsRenderFrameObserver::SetSupportsAppRegion(
+    bool supports_app_region) {
+  render_frame()->GetWebView()->SetSupportsAppRegion(supports_app_region);
+}
+
 void ExtensionsRenderFrameObserver::SetVisuallyDeemphasized(bool deemphasized) {
   // TODO(danakj): This mojo API should be a MainFrame-only interface and object
   // rather than an every-frame interface and object.
diff --git a/extensions/renderer/extensions_render_frame_observer.h b/extensions/renderer/extensions_render_frame_observer.h
index a991d579..89da5b7 100644
--- a/extensions/renderer/extensions_render_frame_observer.h
+++ b/extensions/renderer/extensions_render_frame_observer.h
@@ -33,6 +33,7 @@
   // Toggles visual muting of the render view area. This is on when a
   // constrained window is showing.
   void SetVisuallyDeemphasized(bool deemphasized) override;
+  void SetSupportsAppRegion(bool supports_app_region) override;
 
   // RenderFrameObserver implementation.
   void DetailedConsoleMessageAdded(
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index 2ab85c9c..c90eabc 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.42.1"
+  version: "1.43.1"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 0eb43b4..0a96cd90 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -337,16 +337,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 122.0.6181.0',
+    'description': 'Run with ash-chrome version 122.0.6182.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v122.0.6181.0',
-          'revision': 'version:122.0.6181.0',
+          'location': 'lacros_version_skew_tests_v122.0.6182.0',
+          'revision': 'version:122.0.6182.0',
         },
       ],
     },
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index 1364644..3af9ecdf 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@
 {
   "LACROS_VERSION_SKEW_CANARY": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 122.0.6181.0",
+    "description": "Run with ash-chrome version 122.0.6182.0",
     "identifier": "Lacros version skew testing ash canary",
     "swarming": {
       "cipd_packages": [
         {
           "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-          "location": "lacros_version_skew_tests_v122.0.6181.0",
-          "revision": "version:122.0.6181.0"
+          "location": "lacros_version_skew_tests_v122.0.6182.0",
+          "revision": "version:122.0.6182.0"
         }
       ]
     }
diff --git a/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm b/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm
index 79e0ba7..650efd5b 100644
--- a/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm
+++ b/ios/chrome/browser/find_in_page/model/find_in_page_egtest.mm
@@ -265,7 +265,8 @@
 
 // Tests that there is no query persistence when coming back to a normal tab
 // after switching temporarily to another tab.
-- (void)testFindInPageSwitchingTabs {
+// TODO(crbug.com/1500182): Re-enable this test.
+- (void)FLAKY_testFindInPageSwitchingTabs {
   // TODO(crbug.com/1464379): Failing on iOS17 iPhone.
   if (@available(iOS 17.0, *)) {
     if (![ChromeEarlGrey isIPadIdiom]) {
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
index a826c8f..483b4fd 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -328,10 +328,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kLocalOrSyncable];
 
-  // Confirmation choice is ignored when `kReplaceSyncPromosWithSignInPromos` is
-  // enabled.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  [SigninEarlGreyUI signOut];
 
   // Sign in with fake supervised identity.
   [SigninEarlGreyUI signinWithFakeIdentity:fakeSupervisedIdentity];
@@ -367,9 +364,8 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kLocalOrSyncable];
 
-  // Sign out from the supervised account with option to keep local data.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  // Sign out from the supervised account.
+  [SigninEarlGreyUI signOut];
 
   // Verify bookmarks are available.
   [BookmarkEarlGreyUI openBookmarks];
@@ -393,9 +389,8 @@
       setupStandardBookmarksInStorage:bookmarks::StorageType::kAccount];
   [ChromeEarlGreyUI waitForAppToIdle];
 
-  // Sign out from the supervised account with option to clear local data.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  // Sign out from the supervised account.
+  [SigninEarlGreyUI signOut];
 
   // Verify bookmarks are cleared.
   [BookmarkEarlGreyUI openBookmarks];
@@ -423,9 +418,7 @@
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1];
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity];
 
-  // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  [SigninEarlGreyUI signOut];
 }
 
 // Tests that signing out of a managed account from the Settings works
@@ -437,9 +430,7 @@
   ExpectSigninConsentHistogram(signin_metrics::SigninAccountType::kManaged);
   ExpectNoSyncConsentHistogram(signin_metrics::SigninAccountType::kManaged);
 
-  // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 }
 
 // Opens the sign in screen and then cancel it by opening a new tab. Ensures
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h
index 237af5d..c91c2db 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h
@@ -31,6 +31,11 @@
                     enableSync:(BOOL)enableSync;
 
 // Signs the primary account out of Chrome through the accounts list screen.
+// Taps the "Sign Out" button and dismisses the confirmation snackbar. Assumes
+// that sync sync is replaced by sign-in.
++ (void)signOut;
+
+// Signs the primary account out of Chrome through the accounts list screen.
 // Taps the "Sign Out" button, and then validated the confirmation dialog
 // according to `confirmation`.
 + (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
index e873c43..2912e17 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.mm
@@ -172,6 +172,43 @@
                                    syncTimeout:base::Seconds(10)];
 }
 
++ (void)signOut {
+  CHECK([ChromeEarlGrey isReplaceSyncWithSigninEnabled]);
+  [ChromeEarlGreyUI openSettingsMenu];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
+  // With ReplaceSyncWithSignin, we're now in the "manage sync" view, and
+  // the signout button is at the very bottom. Scroll there.
+  id<GREYMatcher> scrollViewMatcher =
+      grey_accessibilityID(kManageSyncTableViewAccessibilityIdentifier);
+  [[EarlGrey selectElementWithMatcher:scrollViewMatcher]
+      performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
+
+  // Tap the "Sign out" button.
+  [[EarlGrey selectElementWithMatcher:
+                 grey_text(l10n_util::GetNSString(
+                     IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SIGN_OUT_ITEM))]
+      performAction:grey_tap()];
+  // Note that there's no confirmation of signout, so the `confirmation`
+  // param is ignored. However, there is a snackbar - close it, so that it
+  // can't obstruct other UI items.
+  NSString* snackbarLabel = l10n_util::GetNSString(
+      IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SIGN_OUT_SNACKBAR_MESSAGE);
+  // The tap checks the existence of the snackbar and also closes it.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
+      performAction:grey_tap()];
+
+  // Wait until the user is signed out. Use a longer timeout for cases where
+  // sign out also triggers a clear browsing data.
+  [ChromeEarlGrey
+      waitForUIElementToAppearWithMatcher:SettingsDoneButton()
+                                  timeout:base::test::ios::
+                                              kWaitForClearBrowsingDataTimeout];
+
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+  [SigninEarlGrey verifySignedOut];
+}
+
 + (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation {
   [ChromeEarlGreyUI openSettingsMenu];
   [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index bfbec5d..cbd2a59 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -1286,9 +1286,7 @@
   [[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
       assertWithMatcher:grey_sufficientlyVisible()];
 
-  // Sign out
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 
   [[EarlGrey selectElementWithMatcher:chrome_test_util::NTPLogo()]
       assertWithMatcher:grey_sufficientlyVisible()];
@@ -1551,8 +1549,7 @@
   // Opens settings menu and ensures that Discover setting is not present.
   [self checkDiscoverSettingsToggleVisible:NO];
 
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 
   // The feed label should be visible on sign-out.
   [self checkFeedLabelForFeedVisible:YES];
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 9299956..e159c0d7 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -288,9 +288,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kLocalOrSyncable];
 
-  // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -315,11 +313,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kAccount];
 
-  // TODO(crbug.com/1509737) The parameter is ignored when
-  // kReplaceSyncPromosWithSignInPromos is enabled. Change the method to one
-  // that is more meaningful with Sign-in only Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -342,11 +336,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kAccount];
 
-  // TODO(crbug.com/1509737) The parameter is ignored when
-  // kReplaceSyncPromosWithSignInPromos is enabled. Change the method to one
-  // that is more meaningful with Sign-in only Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -366,8 +356,7 @@
 
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity1];
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity1];
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOut];
 
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity2];
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity2];
@@ -554,9 +543,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kLocalOrSyncable];
 
-  // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceNotSyncing];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -575,9 +562,7 @@
   [BookmarkEarlGrey
       setupStandardBookmarksInStorage:bookmarks::StorageType::kLocalOrSyncable];
 
-  // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceNotSyncing];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
diff --git a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
index a6fd90d..710104eb 100644
--- a/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/signin_settings_egtest.mm
@@ -157,8 +157,7 @@
   // Close settings.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()]
       performAction:grey_tap()];
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceNotSyncing];
+  [SigninEarlGreyUI signOut];
   [ChromeEarlGreyUI openSettingsMenu];
   // Tap on sign-in cell.
   [[EarlGrey selectElementWithMatcher:SettingsSignInRowMatcher()]
@@ -218,8 +217,7 @@
   // Close settings.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()]
       performAction:grey_tap()];
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceNotSyncing];
+  [SigninEarlGreyUI signOut];
   [ChromeEarlGreyUI openSettingsMenu];
   // Tap on sign-in cell.
   [[EarlGrey selectElementWithMatcher:SettingsSignInRowMatcher()]
@@ -583,8 +581,7 @@
   // Sign-out then forget fakeIdentity1.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsDoneButton()]
       performAction:grey_tap()];
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  [SigninEarlGreyUI signOut];
   [SigninEarlGrey forgetFakeIdentity:fakeIdentity1];
 
   // Tap on sign-in cell in settings for fakeIdentity2.
diff --git a/ios_internal b/ios_internal
index c8b8487..b8fd6d1 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit c8b84877296746df0c2ad8088c1e53d19b10c8bc
+Subproject commit b8fd6d1953501218760e0f7e2f0485c44d4925c1
diff --git a/media/base/video_frame_layout.cc b/media/base/video_frame_layout.cc
index 53f1a26c..7e5dfe6 100644
--- a/media/base/video_frame_layout.cc
+++ b/media/base/video_frame_layout.cc
@@ -156,7 +156,10 @@
       planes_(std::move(planes)),
       is_multi_planar_(is_multi_planar),
       buffer_addr_align_(buffer_addr_align),
-      modifier_(modifier) {}
+      modifier_(modifier) {
+  // Trigger NOTREACHED() if `format` is not valid.
+  NumPlanes(format);
+}
 
 VideoFrameLayout::~VideoFrameLayout() = default;
 VideoFrameLayout::VideoFrameLayout(const VideoFrameLayout&) = default;
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc
index ee08045..044c9749 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.cc
+++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -485,4 +485,33 @@
   return callbacks;
 }
 
+void CameraAppDeviceImpl::SetCropRegion(const gfx::Rect& crop_region,
+                                        SetCropRegionCallback callback) {
+  CHECK(mojo_task_runner_->BelongsToCurrentThread());
+
+  base::AutoLock lock(crop_region_lock_);
+  crop_region_ = {
+      crop_region.x(),
+      crop_region.y(),
+      crop_region.width(),
+      crop_region.height(),
+  };
+
+  std::move(callback).Run();
+}
+
+void CameraAppDeviceImpl::ResetCropRegion(ResetCropRegionCallback callback) {
+  CHECK(mojo_task_runner_->BelongsToCurrentThread());
+
+  base::AutoLock lock(crop_region_lock_);
+  crop_region_.reset();
+
+  std::move(callback).Run();
+}
+
+std::optional<std::vector<int32_t>> CameraAppDeviceImpl::GetCropRegion() {
+  base::AutoLock lock(crop_region_lock_);
+  return crop_region_;
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_app_device_impl.h b/media/capture/video/chromeos/camera_app_device_impl.h
index c2d1263..bf98134bd 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.h
+++ b/media/capture/video/chromeos/camera_app_device_impl.h
@@ -143,6 +143,10 @@
       mojo::PendingRemote<cros::mojom::CameraInfoObserver> observer,
       RegisterCameraInfoObserverCallback callback) override;
   absl::optional<PortraitModeCallbacks> ConsumePortraitModeCallbacks();
+  void SetCropRegion(const gfx::Rect& crop_region,
+                     SetCropRegionCallback callback) override;
+  void ResetCropRegion(ResetCropRegionCallback callback) override;
+  std::optional<std::vector<int32_t>> GetCropRegion();
 
  private:
   void OnMojoConnectionError();
@@ -226,6 +230,10 @@
   base::Lock multi_stream_lock_;
   bool multi_stream_enabled_ GUARDED_BY(multi_stream_lock_) = false;
 
+  base::Lock crop_region_lock_;
+  std::optional<std::vector<int32_t>> crop_region_
+      GUARDED_BY(crop_region_lock_);
+
   // The weak pointers should be dereferenced and invalidated on camera device
   // ipc thread.
   base::WeakPtrFactory<CameraAppDeviceImpl> weak_ptr_factory_{this};
diff --git a/media/capture/video/chromeos/mojom/camera_app.mojom b/media/capture/video/chromeos/mojom/camera_app.mojom
index 897aaf9..eb7c296 100644
--- a/media/capture/video/chromeos/mojom/camera_app.mojom
+++ b/media/capture/video/chromeos/mojom/camera_app.mojom
@@ -144,6 +144,15 @@
   // Registers the observer to monitor the camera info update.
   RegisterCameraInfoObserver(
     pending_remote<CameraInfoObserver> observer) => ();
+
+  // Sets the crop region to CameraAppDevice. The value will be consumed by
+  // RequestManager to set it to the capture request repeatedly on every frame,
+  // until the new crop region value is set, or reset to the full crop region.
+  SetCropRegion(gfx.mojom.Rect crop_region) => ();
+
+  // Resets the crop region set by |SetCropRegion|. It is no-ops if there is no
+  // crop region value set.
+  ResetCropRegion() => ();
 };
 
 // Interface for camera device to send camera metadata to Chrome Camera App.
diff --git a/media/capture/video/chromeos/request_manager.cc b/media/capture/video/chromeos/request_manager.cc
index d5d901e7..d22a03d4 100644
--- a/media/capture/video/chromeos/request_manager.cc
+++ b/media/capture/video/chromeos/request_manager.cc
@@ -410,6 +410,20 @@
     return;
   }
 
+  // Sets crop region if there is a value set from Camera app.
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_id_);
+  if (camera_app_device) {
+    auto crop_region = camera_app_device->GetCropRegion();
+    if (crop_region.has_value()) {
+      SetCaptureMetadata(
+          cros::mojom::CameraMetadataTag::ANDROID_SCALER_CROP_REGION,
+          cros::mojom::EntryType::TYPE_INT32, crop_region->size(),
+          SerializeMetadataValueFromSpan<int32_t>(*crop_region));
+    }
+  }
+
   auto capture_request = request_builder_->BuildRequest(std::move(stream_types),
                                                         std::move(settings));
   CHECK_GT(capture_request->output_buffers.size(), 0u);
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn
index c7245041..ed963cb 100644
--- a/media/filters/BUILD.gn
+++ b/media/filters/BUILD.gn
@@ -248,6 +248,8 @@
       "hls_codec_detector.h",
       "hls_data_source_provider.cc",
       "hls_data_source_provider.h",
+      "hls_data_source_provider_impl.cc",
+      "hls_data_source_provider_impl.h",
       "hls_demuxer_status.h",
       "hls_manifest_demuxer_engine.cc",
       "hls_manifest_demuxer_engine.h",
@@ -412,6 +414,7 @@
   if (enable_hls_demuxer) {
     sources += [
       "hls_codec_detector_unittest.cc",
+      "hls_data_source_provider_impl_unittest.cc",
       "hls_data_source_provider_unittest.cc",
       "hls_manifest_demuxer_engine_unittest.cc",
       "hls_rendition_impl_unittest.cc",
diff --git a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc b/media/filters/hls_data_source_provider_impl.cc
similarity index 65%
rename from third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc
rename to media/filters/hls_data_source_provider_impl.cc
index 7ce6b1c0..7976be7 100644
--- a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.cc
+++ b/media/filters/hls_data_source_provider_impl.cc
@@ -2,17 +2,16 @@
 // 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/platform/media/hls_data_source_provider_impl.h"
+#include "media/filters/hls_data_source_provider_impl.h"
 
 #include "base/logging.h"
 #include "base/ranges/algorithm.h"
 #include "base/task/bind_post_task.h"
 #include "base/types/pass_key.h"
 #include "media/formats/hls/types.h"
-#include "third_party/blink/renderer/platform/media/buffered_data_source_host_impl.h"
-#include "third_party/blink/renderer/platform/media/multi_buffer_data_source.h"
+#include "media/base/cross_origin_data_source.h"
 
-namespace blink {
+namespace media {
 
 namespace {
 
@@ -21,20 +20,20 @@
 constexpr size_t kDefaultReadSize = 1024 * 16;
 
 void OnMultiBufferReadComplete(
-    std::unique_ptr<media::HlsDataSourceStream> stream,
+    std::unique_ptr<HlsDataSourceStream> stream,
     HlsDataSourceProviderImpl::ReadCb callback,
     int requested_read_size,
     int read_size) {
   switch (read_size) {
-    case media::DataSource::kReadError: {
+    case DataSource::kReadError: {
       stream->UnlockStreamPostWrite(0, true);
       return std::move(callback).Run(
-          media::HlsDataSourceProvider::ReadStatus::Codes::kError);
+          HlsDataSourceProvider::ReadStatus::Codes::kError);
     }
-    case media::DataSource::kAborted: {
+    case DataSource::kAborted: {
       stream->UnlockStreamPostWrite(0, true);
       return std::move(callback).Run(
-          media::HlsDataSourceProvider::ReadStatus::Codes::kAborted);
+          HlsDataSourceProvider::ReadStatus::Codes::kAborted);
     }
     default: {
       CHECK_GE(read_size, 0);
@@ -47,50 +46,8 @@
 
 }  // namespace
 
-MultiBufferDataSourceFactory::~MultiBufferDataSourceFactory() = default;
 HlsDataSourceProviderImpl::DataSourceFactory::~DataSourceFactory() = default;
 
-MultiBufferDataSourceFactory::MultiBufferDataSourceFactory(
-    media::MediaLog* media_log,
-    UrlDataCb get_url_data,
-    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-    const base::TickClock* tick_clock)
-    : media_log_(media_log->Clone()),
-      get_url_data_(get_url_data),
-      main_task_runner_(std::move(main_task_runner)) {
-  buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
-      base::DoNothing(), tick_clock);
-}
-
-void MultiBufferDataSourceFactory::CreateDataSource(GURL uri, DataSourceCb cb) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  auto download_cb =
-#if DCHECK_IS_ON()
-      base::BindRepeating(
-          [](const std::string url, bool is_downloading) {
-            DVLOG(1) << __func__ << "(" << url << ", " << is_downloading << ")";
-          },
-          uri.spec());
-#else
-      base::DoNothing();
-#endif
-
-  get_url_data_.Run(std::move(uri),
-                    base::BindOnce(&MultiBufferDataSourceFactory::OnUrlData,
-                                   weak_factory_.GetWeakPtr(), std::move(cb),
-                                   std::move(download_cb)));
-}
-
-void MultiBufferDataSourceFactory::OnUrlData(
-    DataSourceCb cb,
-    base::RepeatingCallback<void(bool)> download_cb,
-    scoped_refptr<UrlData> data) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  std::move(cb).Run(std::make_unique<MultiBufferDataSource>(
-      main_task_runner_, std::move(data), media_log_.get(),
-      buffered_data_source_host_.get(), std::move(download_cb)));
-}
-
 HlsDataSourceProviderImpl::HlsDataSourceProviderImpl(
     std::unique_ptr<DataSourceFactory> factory)
     : data_source_factory_(std::move(factory)) {}
@@ -108,9 +65,9 @@
 }
 
 void HlsDataSourceProviderImpl::OnDataSourceReady(
-    absl::optional<media::hls::types::ByteRange> range,
+    absl::optional<hls::types::ByteRange> range,
     ReadCb callback,
-    std::unique_ptr<media::DataSource> data_source) {
+    std::unique_ptr<DataSource> data_source) {
   auto stream_id = stream_id_generator_.GenerateNextId();
   auto it = data_source_map_.try_emplace(stream_id, std::move(data_source));
   // The factory may return a CrossOriginDataSource, which must be initialized.
@@ -130,7 +87,7 @@
 
 void HlsDataSourceProviderImpl::ReadFromUrl(
     GURL uri,
-    absl::optional<media::hls::types::ByteRange> range,
+    absl::optional<hls::types::ByteRange> range,
     ReadCb callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   data_source_factory_->CreateDataSource(
@@ -141,7 +98,7 @@
 }
 
 void HlsDataSourceProviderImpl::ReadFromExistingStream(
-    std::unique_ptr<media::HlsDataSourceStream> stream,
+    std::unique_ptr<HlsDataSourceStream> stream,
     ReadCb callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(stream);
@@ -149,7 +106,7 @@
   auto it = data_source_map_.find(stream->stream_id());
   if (it == data_source_map_.end()) {
     std::move(callback).Run(
-        media::HlsDataSourceProvider::ReadStatus::Codes::kError);
+        HlsDataSourceProvider::ReadStatus::Codes::kError);
     return;
   }
 
@@ -185,8 +142,8 @@
 }
 
 void HlsDataSourceProviderImpl::DataSourceInitialized(
-    media::HlsDataSourceStream::StreamId stream_id,
-    absl::optional<media::hls::types::ByteRange> range,
+    HlsDataSourceStream::StreamId stream_id,
+    absl::optional<hls::types::ByteRange> range,
     ReadCb callback,
     bool success) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -196,11 +153,11 @@
       data_source_map_.erase(it);
     }
     std::move(callback).Run(
-        media::HlsDataSourceProvider::ReadStatus::Codes::kAborted);
+        HlsDataSourceProvider::ReadStatus::Codes::kAborted);
     return;
   }
 
-  auto stream = std::make_unique<media::HlsDataSourceStream>(
+  auto stream = std::make_unique<HlsDataSourceStream>(
       stream_id,
       base::BindPostTaskToCurrentDefault(
           base::BindOnce(&HlsDataSourceProviderImpl::OnStreamReleased,
@@ -210,7 +167,7 @@
 }
 
 void HlsDataSourceProviderImpl::OnStreamReleased(
-    media::HlsDataSourceStream::StreamId stream_id) {
+    HlsDataSourceStream::StreamId stream_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = data_source_map_.find(stream_id);
   if (it != data_source_map_.end()) {
diff --git a/media/filters/hls_data_source_provider_impl.h b/media/filters/hls_data_source_provider_impl.h
new file mode 100644
index 0000000..3f79a16
--- /dev/null
+++ b/media/filters/hls_data_source_provider_impl.h
@@ -0,0 +1,68 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FILTERS_HLS_DATA_SOURCE_PROVIDER_IMPL_H_
+#define MEDIA_FILTERS_HLS_DATA_SOURCE_PROVIDER_IMPL_H_
+
+#include <memory>
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/tick_clock.h"
+#include "base/types/pass_key.h"
+#include "media/base/data_source.h"
+#include "media/base/media_export.h"
+#include "media/base/media_log.h"
+#include "media/filters/hls_data_source_provider.h"
+
+namespace media {
+
+class MEDIA_EXPORT HlsDataSourceProviderImpl : public HlsDataSourceProvider {
+ public:
+  // An instance of DataSourceFactory allows separation of DataSource creation
+  // and DataSourceStream buffer management for easier testing.
+  class DataSourceFactory {
+   public:
+    using DataSourceCb = base::OnceCallback<void(std::unique_ptr<DataSource>)>;
+    virtual ~DataSourceFactory() = 0;
+    virtual void CreateDataSource(GURL uri, DataSourceCb cb) = 0;
+  };
+
+  ~HlsDataSourceProviderImpl() override;
+  explicit HlsDataSourceProviderImpl(
+      std::unique_ptr<DataSourceFactory> factory);
+
+  // HlsDataSourceProvider implementation
+  void ReadFromUrl(GURL uri,
+                   absl::optional<hls::types::ByteRange> range,
+                   ReadCb callback) override;
+  void ReadFromExistingStream(std::unique_ptr<HlsDataSourceStream> stream,
+                              ReadCb callback) override;
+  void AbortPendingReads(base::OnceClosure cb) override;
+
+ private:
+  void OnDataSourceReady(absl::optional<hls::types::ByteRange> range,
+                         ReadCb callback,
+                         std::unique_ptr<DataSource> data_source);
+  void OnStreamReleased(HlsDataSourceStream::StreamId stream_id);
+  void DataSourceInitialized(HlsDataSourceStream::StreamId stream_id,
+                             absl::optional<hls::types::ByteRange> range,
+                             ReadCb callback,
+                             bool success);
+
+  std::unique_ptr<DataSourceFactory> data_source_factory_;
+
+  HlsDataSourceStream::StreamId::Generator stream_id_generator_;
+
+  base::flat_map<HlsDataSourceStream::StreamId, std::unique_ptr<DataSource>>
+      data_source_map_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<HlsDataSourceProviderImpl> weak_factory_{this};
+};
+
+}  // namespace media
+
+#endif  // #ifndef MEDIA_FILTERS_HLS_DATA_SOURCE_PROVIDER_IMPL_H_
diff --git a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl_unittest.cc b/media/filters/hls_data_source_provider_impl_unittest.cc
similarity index 89%
rename from third_party/blink/renderer/platform/media/hls_data_source_provider_impl_unittest.cc
rename to media/filters/hls_data_source_provider_impl_unittest.cc
index 7878ad7..935b8292 100644
--- a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl_unittest.cc
+++ b/media/filters/hls_data_source_provider_impl_unittest.cc
@@ -14,11 +14,10 @@
 #include "media/base/mock_media_log.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/media/buffered_data_source_host_impl.h"
-#include "third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h"
-#include "third_party/blink/renderer/platform/media/multi_buffer_data_source.h"
+#include "media/filters/hls_data_source_provider_impl.h"
+#include "media/base/cross_origin_data_source.h"
 
-namespace blink {
+namespace media {
 
 using base::test::RunOnceCallback;
 using testing::_;
@@ -37,7 +36,7 @@
 
 namespace {
 
-class MockDataSource : public media::CrossOriginDataSource {
+class MockDataSource : public CrossOriginDataSource {
  public:
   // Mocked methods from CrossOriginDataSource
   MOCK_METHOD(bool, IsCorsCrossOrigin, (), (const, override));
@@ -65,7 +64,7 @@
   MOCK_METHOD(int64_t, GetMemoryUsage, (), (override));
   MOCK_METHOD(void,
               SetPreload,
-              (media::DataSource::Preload preload),
+              (DataSource::Preload preload),
               (override));
   MOCK_METHOD(GURL, GetUrlAfterRedirects, (), (const, override));
   MOCK_METHOD(void,
@@ -141,7 +140,7 @@
   factory_->AddReadExpectation(0, 16384, 16384);
   impl_->ReadFromUrl(
       GURL("example.com"), absl::nullopt,
-      base::BindOnce([](media::HlsDataSourceProvider::ReadResult result) {
+      base::BindOnce([](HlsDataSourceProvider::ReadResult result) {
         ASSERT_TRUE(result.has_value());
         auto stream = std::move(result).value();
         ASSERT_EQ(stream->read_position(), 16384lu);
@@ -155,7 +154,7 @@
   factory_->AddReadExpectation(0, 16384, 400);
   impl_->ReadFromUrl(
       GURL("example.com"), absl::nullopt,
-      base::BindOnce([](media::HlsDataSourceProvider::ReadResult result) {
+      base::BindOnce([](HlsDataSourceProvider::ReadResult result) {
         ASSERT_TRUE(result.has_value());
         auto stream = std::move(result).value();
         ASSERT_EQ(stream->read_position(), 400lu);
@@ -169,8 +168,8 @@
   // at an offset of 99. The read should be from 99, size of 4242.
   factory_->AddReadExpectation(99, 4242, 4242);
   impl_->ReadFromUrl(
-      GURL("example.com"), media::hls::types::ByteRange::Validate(4242, 99),
-      base::BindOnce([](media::HlsDataSourceProvider::ReadResult result) {
+      GURL("example.com"), hls::types::ByteRange::Validate(4242, 99),
+      base::BindOnce([](HlsDataSourceProvider::ReadResult result) {
         ASSERT_TRUE(result.has_value());
         auto stream = std::move(result).value();
         ASSERT_EQ(stream->read_position(), 4341lu);
@@ -189,7 +188,7 @@
       GURL("example.com"), absl::nullopt,
       base::BindOnce(
           [](HlsDataSourceProviderImpl* impl_ptr,
-             media::HlsDataSourceProvider::ReadResult result) {
+             HlsDataSourceProvider::ReadResult result) {
             ASSERT_TRUE(result.has_value());
             auto stream = std::move(result).value();
             ASSERT_EQ(stream->read_position(), 16384lu);
@@ -200,7 +199,7 @@
                 std::move(stream),
                 base::BindOnce(
                     [](HlsDataSourceProviderImpl* impl_ptr,
-                       media::HlsDataSourceProvider::ReadResult result) {
+                       HlsDataSourceProvider::ReadResult result) {
                       ASSERT_TRUE(result.has_value());
                       auto stream = std::move(result).value();
                       ASSERT_EQ(stream->read_position(), 32768lu);
@@ -210,7 +209,7 @@
                       impl_ptr->ReadFromExistingStream(
                           std::move(stream),
                           base::BindOnce(
-                              [](media::HlsDataSourceProvider::ReadResult
+                              [](HlsDataSourceProvider::ReadResult
                                      result) {
                                 ASSERT_TRUE(result.has_value());
                                 auto stream = std::move(result).value();
@@ -233,10 +232,10 @@
   EXPECT_CALL(*mock_data_source, Abort()).Times(0);
   EXPECT_CALL(*mock_data_source, Stop()).Times(0);
 
-  media::DataSource::ReadCB read_cb;
+  DataSource::ReadCB read_cb;
   EXPECT_CALL(*mock_data_source, Read(0, _, _, _))
       .WillOnce(
-          [&read_cb](int64_t, int, uint8_t*, media::DataSource::ReadCB cb) {
+          [&read_cb](int64_t, int, uint8_t*, DataSource::ReadCB cb) {
             read_cb = std::move(cb);
           });
 
@@ -245,7 +244,7 @@
   impl_->ReadFromUrl(GURL("example.com"), absl::nullopt,
                      base::BindOnce(
                          [](bool* read_canary,
-                            media::HlsDataSourceProvider::ReadResult result) {
+                            HlsDataSourceProvider::ReadResult result) {
                            *read_canary = true;
                          },
                          &has_been_read));
@@ -278,7 +277,7 @@
   impl_->ReadFromUrl(GURL("example.com"), absl::nullopt,
                      base::BindOnce(
                          [](bool* read_canary,
-                            media::HlsDataSourceProvider::ReadResult result) {
+                            HlsDataSourceProvider::ReadResult result) {
                            *read_canary = true;
                          },
                          &has_been_read));
diff --git a/net/dns/public/dns_over_https_server_config.cc b/net/dns/public/dns_over_https_server_config.cc
index 3dcfa133..5767f1b 100644
--- a/net/dns/public/dns_over_https_server_config.cc
+++ b/net/dns/public/dns_over_https_server_config.cc
@@ -30,10 +30,9 @@
   std::string canonical;
   url::StdStringCanonOutput output(&canonical);
   url::Parsed canonical_parsed;
-  bool is_valid =
-      url::CanonicalizeStandardURL(url.data(), url.size(), parsed,
-                                   url::SchemeType::SCHEME_WITH_HOST_AND_PORT,
-                                   nullptr, &output, &canonical_parsed);
+  bool is_valid = url::CanonicalizeStandardURL(
+      url.data(), parsed, url::SchemeType::SCHEME_WITH_HOST_AND_PORT, nullptr,
+      &output, &canonical_parsed);
   if (!is_valid)
     return absl::nullopt;
   const url::Component& scheme_range = canonical_parsed.scheme;
diff --git a/net/quic/quic_http3_logger.cc b/net/quic/quic_http3_logger.cc
index fce189ad..de1bd0c1 100644
--- a/net/quic/quic_http3_logger.cc
+++ b/net/quic/quic_http3_logger.cc
@@ -147,7 +147,6 @@
                               frame.values.size() + 1, /* min = */ 1,
                               /* max = */ 10, /* buckets = */ 10);
   int reserved_identifier_count = 0;
-  bool settings_extended_connect_enabled = false;
   for (const auto& value : frame.values) {
     if (value.first == quic::SETTINGS_QPACK_MAX_TABLE_CAPACITY) {
       UMA_HISTOGRAM_COUNTS_1M(
@@ -158,8 +157,6 @@
     } else if (value.first == quic::SETTINGS_QPACK_BLOCKED_STREAMS) {
       UMA_HISTOGRAM_COUNTS_1000(
           "Net.QuicSession.ReceivedSettings.BlockedStreams", value.second);
-    } else if (value.first == quic::SETTINGS_ENABLE_CONNECT_PROTOCOL) {
-      settings_extended_connect_enabled = value.second == 1;
     } else if (value.first >= 0x21 && value.first % 0x1f == 2) {
       // Reserved setting identifiers are defined at
       // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-defined-settings-parameters.
@@ -174,9 +171,6 @@
       "Net.QuicSession.ReceivedSettings.ReservedCountPlusOne",
       reserved_identifier_count + 1, /* min = */ 1,
       /* max = */ 5, /* buckets = */ 5);
-  UMA_HISTOGRAM_BOOLEAN(
-      "Net.QuicSession.ReceivedSettings.EnableExtendedConnect",
-      settings_extended_connect_enabled);
 
   if (!net_log_.IsCapturing())
     return;
diff --git a/net/tools/dump_cache/dump_cache.cc b/net/tools/dump_cache/dump_cache.cc
index 16ae2dc..dd21784 100644
--- a/net/tools/dump_cache/dump_cache.cc
+++ b/net/tools/dump_cache/dump_cache.cc
@@ -10,6 +10,7 @@
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
+#include "base/i18n/icu_util.h"
 #include "base/strings/string_util.h"
 #include "net/disk_cache/blockfile/disk_format.h"
 #include "net/tools/dump_cache/dump_files.h"
@@ -71,6 +72,9 @@
   // Setup an AtExitManager so Singleton objects will be destroyed.
   base::AtExitManager at_exit_manager;
 
+  // base::UnlocalizedTimeFormatWithPattern() depends on ICU.
+  base::i18n::InitializeICU();
+
   base::CommandLine::Init(argc, argv);
 
   const base::CommandLine& command_line =
@@ -83,9 +87,9 @@
   if (input_path.empty())
     return Help();
 
-  int version = GetMajorVersion(input_path);
-  if (version != 2)
+  if (!CheckFileVersion(input_path)) {
     return FILE_ACCESS_ERROR;
+  }
 
   if (command_line.HasSwitch(kDumpContents))
     return DumpContents(input_path);
diff --git a/net/tools/dump_cache/dump_files.cc b/net/tools/dump_cache/dump_files.cc
index bd8449e..da5951a 100644
--- a/net/tools/dump_cache/dump_files.cc
+++ b/net/tools/dump_cache/dump_files.cc
@@ -53,12 +53,27 @@
   return true;
 }
 
-int GetMajorVersionFromFile(const base::FilePath& name) {
+int GetMajorVersionFromIndexFile(const base::FilePath& name) {
   disk_cache::IndexHeader header;
   if (!ReadHeader(name, reinterpret_cast<char*>(&header), sizeof(header)))
     return 0;
+  if (header.magic != disk_cache::kIndexMagic) {
+    return 0;
+  }
+  return header.version;
+}
 
-  return header.version >> 16;
+int GetMajorVersionFromBlockFile(const base::FilePath& name) {
+  disk_cache::BlockFileHeader header;
+  if (!ReadHeader(name, reinterpret_cast<char*>(&header), sizeof(header))) {
+    return 0;
+  }
+
+  if (header.magic != disk_cache::kBlockMagic) {
+    return 0;
+  }
+
+  return header.version;
 }
 
 // Dumps the contents of the Stats record.
@@ -394,30 +409,24 @@
 
 // -----------------------------------------------------------------------
 
-int GetMajorVersion(const base::FilePath& input_path) {
+bool CheckFileVersion(const base::FilePath& input_path) {
   base::FilePath index_name(input_path.Append(kIndexName));
 
-  int version = GetMajorVersionFromFile(index_name);
-  if (!version)
-    return 0;
+  int index_version = GetMajorVersionFromIndexFile(index_name);
+  if (!index_version || index_version != disk_cache::kVersion3_0) {
+    return false;
+  }
 
-  base::FilePath data_name(input_path.Append(FILE_PATH_LITERAL("data_0")));
-  if (version != GetMajorVersionFromFile(data_name))
-    return 0;
-
-  data_name = input_path.Append(FILE_PATH_LITERAL("data_1"));
-  if (version != GetMajorVersionFromFile(data_name))
-    return 0;
-
-  data_name = input_path.Append(FILE_PATH_LITERAL("data_2"));
-  if (version != GetMajorVersionFromFile(data_name))
-    return 0;
-
-  data_name = input_path.Append(FILE_PATH_LITERAL("data_3"));
-  if (version != GetMajorVersionFromFile(data_name))
-    return 0;
-
-  return version;
+  constexpr int kCurrentBlockVersion = disk_cache::kBlockVersion2;
+  for (int i = 0; i < disk_cache::kFirstAdditionalBlockFile; i++) {
+    std::string data_name = "data_" + base::NumberToString(i);
+    auto data_path = input_path.AppendASCII(data_name);
+    int block_version = GetMajorVersionFromBlockFile(data_path);
+    if (!block_version || block_version != kCurrentBlockVersion) {
+      return false;
+    }
+  }
+  return true;
 }
 
 // Dumps the headers of all files.
diff --git a/net/tools/dump_cache/dump_files.h b/net/tools/dump_cache/dump_files.h
index 8a6c83c..6d9fded 100644
--- a/net/tools/dump_cache/dump_files.h
+++ b/net/tools/dump_cache/dump_files.h
@@ -11,8 +11,8 @@
 
 #include "base/files/file_path.h"
 
-// Returns the major version of the specified cache.
-int GetMajorVersion(const base::FilePath& input_path);
+// Check file version of the specified cache.
+bool CheckFileVersion(const base::FilePath& input_path);
 
 // Dumps all entries from the cache.
 int DumpContents(const base::FilePath& input_path);
diff --git a/services/webnn/public/mojom/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
index 271142a3..08aa92ef 100644
--- a/services/webnn/public/mojom/webnn_graph.mojom
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -288,6 +288,29 @@
   SymmetricPadding symmetric;
 };
 
+// This operator performs the following normalization, defined as:
+// Output = scale * (input - mean) / sqrt(variance + epsilon) + bias, where
+// mean and variance are computed per instance per channel. The specified
+// layout determines how to choose the channel.
+struct InstanceNormalization {
+  // The input operand (referenced by input_operand_id) must be distinct from
+  // the output operand (referenced by output_operand_id).
+  uint64 input_operand_id;
+  uint64 output_operand_id;
+
+  // The optional 1-D tensor of the scale values whose size is equal to the
+  // size of the feature dimension of the input.
+  uint64? scale_operand_id;
+  // The optional 1-D tensor of the bias values whose size is equal to the
+  // size of the feature dimension of the input.
+  uint64? bias_operand_id;
+  // A float scalar which specifies a small value to prevent computational
+  // error due to divide-by-zero.
+  float epsilon = 1e-5;
+  // The layout format of the input.
+  InputOperandLayout layout;
+};
+
 // Represents matmul operation which compute the matrix product of two input tensors.
 struct Matmul {
   // The id of `a` operand is used to get the `Operand` description from
@@ -724,6 +747,7 @@
   Gather gather;
   Gemm gemm;
   LayerNormalization layer_normalization;
+  InstanceNormalization instance_normalization;
   LeakyRelu leaky_relu;
   Matmul matmul;
   Pad pad;
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc
index a7d8fe9..e95c86a 100644
--- a/services/webnn/webnn_graph_impl.cc
+++ b/services/webnn/webnn_graph_impl.cc
@@ -328,6 +328,28 @@
   return component_attributes;
 }
 
+webnn::InstanceNormalizationAttributes ConvertToInstanceNormalizationAttributes(
+    const IdToOperandMap& id_to_operand_map,
+    const mojom::InstanceNormalizationPtr& instance_normalization) {
+  webnn::InstanceNormalizationAttributes component_attributes;
+  const auto& scale_operand_id = instance_normalization->scale_operand_id;
+  if (scale_operand_id) {
+    const mojom::OperandPtr& scale_operand =
+        id_to_operand_map.at(scale_operand_id.value());
+    component_attributes.scale = ConvertToComponentOperand(scale_operand.get());
+  }
+  const auto& bias_operand_id = instance_normalization->bias_operand_id;
+  if (bias_operand_id) {
+    const mojom::OperandPtr& bias_operand =
+        id_to_operand_map.at(bias_operand_id.value());
+    component_attributes.bias = ConvertToComponentOperand(bias_operand.get());
+  }
+  component_attributes.layout =
+      MojoInputOperandLayoutToComponent(instance_normalization->layout);
+
+  return component_attributes;
+}
+
 webnn::SliceAttributes ConvertToSliceAttributes(
     const webnn::mojom::SlicePtr& slice) {
   webnn::SliceAttributes component_attributes;
@@ -800,6 +822,46 @@
   return true;
 }
 
+bool ValidateInstanceNormalization(
+    const IdToOperandMap& id_to_operand_map,
+    const mojom::InstanceNormalizationPtr& instance_normalization) {
+  const auto* input = GetMojoOperand(id_to_operand_map,
+                                     instance_normalization->input_operand_id);
+  const auto* output = GetMojoOperand(
+      id_to_operand_map, instance_normalization->output_operand_id);
+  if (!input || !output || output == input) {
+    // The instanceNormalization operator is invalid.
+    return false;
+  }
+  const auto& scale_operand_id = instance_normalization->scale_operand_id;
+  if (scale_operand_id &&
+      (!id_to_operand_map.contains(scale_operand_id.value()) ||
+       scale_operand_id.value() == instance_normalization->output_operand_id)) {
+    // The scale operand is invalid.
+    return false;
+  }
+  const auto& bias_operand_id = instance_normalization->bias_operand_id;
+  if (bias_operand_id &&
+      (!id_to_operand_map.contains(bias_operand_id.value()) ||
+       bias_operand_id.value() == instance_normalization->output_operand_id)) {
+    // The bias operand is invalid.
+    return false;
+  }
+
+  const auto validated_output = ValidateInstanceNormalizationAndInferOutput(
+      ConvertToComponentOperand(input),
+      ConvertToInstanceNormalizationAttributes(id_to_operand_map,
+                                               instance_normalization));
+  if (!validated_output.has_value()) {
+    return false;
+  }
+  if (validated_output != ConvertToComponentOperand(output)) {
+    return false;
+  }
+
+  return true;
+}
+
 bool ValidateMatmul(const IdToOperandMap& id_to_operand_map,
                     const mojom::MatmulPtr& matmul) {
   auto* a = GetMojoOperand(id_to_operand_map, matmul->a_operand_id);
@@ -1170,6 +1232,9 @@
     case mojom::Operation::Tag::kLayerNormalization:
       return ValidateLayerNormalization(id_to_operand_map,
                                         operation->get_layer_normalization());
+    case mojom::Operation::Tag::kInstanceNormalization:
+      return ValidateInstanceNormalization(
+          id_to_operand_map, operation->get_instance_normalization());
     case mojom::Operation::Tag::kLeakyRelu:
       return ValidateLeakyRelu(id_to_operand_map, operation->get_leaky_relu());
     case mojom::Operation::Tag::kMatmul:
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
index 58a30f2..94663a1 100644
--- a/services/webnn/webnn_graph_impl_unittest.cc
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -2650,6 +2650,208 @@
   }
 }
 
+struct InstanceNormalizationTester {
+  OperandInfo input;
+  absl::optional<OperandInfo> scale;
+  absl::optional<OperandInfo> bias;
+  struct InstanceNormalizationAttributes {
+    absl::optional<uint64_t> scale_operand_id;
+    absl::optional<uint64_t> bias_operand_id;
+    mojom::InputOperandLayout layout =
+        mojom::InputOperandLayout::kChannelsFirst;
+    float epsilon = 1e-5;
+  };
+  InstanceNormalizationAttributes attributes;
+  OperandInfo output;
+  bool expected;
+
+  void Test() {
+    // Build the graph with mojo type.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id =
+        builder.BuildInput("input", input.dimensions, input.type);
+    uint64_t output_operand_id =
+        builder.BuildOutput("output", output.dimensions, output.type);
+
+    if (scale) {
+      attributes.scale_operand_id =
+          builder.BuildInput("scale", scale->dimensions, scale->type);
+    }
+    if (bias) {
+      attributes.bias_operand_id =
+          builder.BuildInput("bias", bias->dimensions, bias->type);
+    }
+    builder.BuildInstanceNormalization(input_operand_id, output_operand_id,
+                                       std::move(attributes));
+    EXPECT_EQ(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()), expected);
+  }
+};
+
+TEST_F(WebNNGraphImplTest, InstanceNormalizationTest) {
+  {
+    // Test building instanceNormalization with default option.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = true}
+        .Test();
+  }
+  {
+    // Test building instanceNormalization with layout = kChannelsLast.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .scale = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                             .dimensions = {3}},
+        .bias = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {3}},
+        .attributes = {.layout = mojom::InputOperandLayout::kChannelsLast},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = true}
+        .Test();
+  }
+  {
+    // Test building instanceNormalization with default layout = kChannelsFirst.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .scale = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                             .dimensions = {2}},
+        .bias = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {2}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = true}
+        .Test();
+  }
+  {
+    // Test instanceNormalization when input data type and scale data type
+    // mismatched.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .scale = OperandInfo{.type = mojom::Operand::DataType::kInt32,
+                             .dimensions = {2}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test building instanceNormalization when the size of scale is not equal
+    // to the size of the feature dimension of the input.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .scale = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                             .dimensions = {3}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test instanceNormalization when input data type and bias data type
+    // mismatched.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .bias = OperandInfo{.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {2}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test building instanceNormalization when the size of bias is not equal
+    // to the size of the feature dimension of the input.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .bias = OperandInfo{.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {2}},
+        .attributes = {.layout = mojom::InputOperandLayout::kChannelsLast},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for output type is not the same as input type.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .output = {.type = mojom::Operand::DataType::kInt32,
+                   .dimensions = {1, 2, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for output shape is not the same as input shape.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3, 3}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 1, 3, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for input is not a 4-D tensor.
+    InstanceNormalizationTester{
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 2, 3}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 2, 3}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for input operand == output operand.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 2, 3, 4}, mojom::Operand::DataType::kFloat32);
+    builder.BuildInstanceNormalization(
+        input_operand_id, input_operand_id,
+        InstanceNormalizationTester::InstanceNormalizationAttributes{});
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+  {
+    // Test the invalid graph when the output is the same as the scale.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 2, 3, 4}, mojom::Operand::DataType::kFloat32);
+    uint64_t scale_operand_id =
+        builder.BuildInput("scale", {2}, mojom::Operand::DataType::kFloat32);
+
+    InstanceNormalizationTester::InstanceNormalizationAttributes attributes;
+    attributes.scale_operand_id = scale_operand_id;
+
+    builder.BuildInstanceNormalization(input_operand_id, scale_operand_id,
+                                       std::move(attributes));
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+  {
+    // Test the invalid graph when the output is the same as the bias.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 2, 3, 4}, mojom::Operand::DataType::kFloat32);
+    uint64_t bias_operand_id =
+        builder.BuildInput("bias", {2}, mojom::Operand::DataType::kFloat32);
+
+    InstanceNormalizationTester::InstanceNormalizationAttributes attributes;
+    attributes.bias_operand_id = bias_operand_id;
+
+    builder.BuildInstanceNormalization(input_operand_id, bias_operand_id,
+                                       std::move(attributes));
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+}
+
 struct LayerNormalizationTester {
   OperandInfo input;
   absl::optional<OperandInfo> scale;
diff --git a/services/webnn/webnn_test_utils.h b/services/webnn/webnn_test_utils.h
index c909b29..bbba056 100644
--- a/services/webnn/webnn_test_utils.h
+++ b/services/webnn/webnn_test_utils.h
@@ -260,6 +260,33 @@
         std::move(layer_normalization)));
   }
 
+  // A `InstanceNormalizationAttributes` type should have the following members:
+  // struct InstanceNormalizationAttributes {
+  //  absl::optional<uint64_t> scale_operand_id;
+  //  absl::optional<uint64_t> bias_operand_id;
+  //  float epsilon = 1e-5;
+  //  mojom::InputOperandLayout input_layout;
+  // };
+  template <typename InstanceNormalizationAttributes>
+  void BuildInstanceNormalization(
+      uint64_t input_operand_id,
+      uint64_t output_operand_id,
+      const InstanceNormalizationAttributes& attributes) {
+    mojom::InstanceNormalizationPtr instance_normalization =
+        mojom::InstanceNormalization::New();
+    instance_normalization->input_operand_id = input_operand_id;
+    instance_normalization->output_operand_id = output_operand_id;
+
+    instance_normalization->scale_operand_id = attributes.scale_operand_id;
+    instance_normalization->bias_operand_id = attributes.bias_operand_id;
+    instance_normalization->layout = attributes.layout;
+    instance_normalization->epsilon = attributes.epsilon;
+
+    graph_info_->operations.push_back(
+        mojom::Operation::NewInstanceNormalization(
+            std::move(instance_normalization)));
+  }
+
   void BuildLeakyRelu(uint64_t input_operand_id,
                       uint64_t output_operand_id,
                       float alpha);
diff --git a/services/webnn/webnn_utils.cc b/services/webnn/webnn_utils.cc
index 940be86..880ec4ba 100644
--- a/services/webnn/webnn_utils.cc
+++ b/services/webnn/webnn_utils.cc
@@ -30,6 +30,8 @@
       return "gather";
     case mojom::Operation::Tag::kGemm:
       return "gemm";
+    case mojom::Operation::Tag::kInstanceNormalization:
+      return "instanceNormalization";
     case mojom::Operation::Tag::kLayerNormalization:
       return "layerNormalization";
     case mojom::Operation::Tag::kLeakyRelu:
diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h
index fff7a46..b7adeeaa 100644
--- a/skia/ext/skia_utils_mac.h
+++ b/skia/ext/skia_utils_mac.h
@@ -82,27 +82,49 @@
 #ifdef __OBJC__
 
 // Draws an NSImage with a given size into a SkBitmap.
-SK_API SkBitmap NSImageToSkBitmapWithColorSpace(NSImage* image,
+SK_API SkBitmap NSImageToSkBitmap(NSImage* image, bool is_opaque);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline SkBitmap NSImageToSkBitmapWithColorSpace(NSImage* image,
                                                 bool is_opaque,
-                                                CGColorSpaceRef color_space);
+                                                CGColorSpaceRef color_space) {
+  return NSImageToSkBitmap(image, is_opaque);
+}
 
 // Draws an NSImageRep with a given size into a SkBitmap.
-SK_API SkBitmap NSImageRepToSkBitmapWithColorSpace(NSImageRep* image,
+SK_API SkBitmap NSImageRepToSkBitmap(NSImageRep* image,
+                                     NSSize size,
+                                     bool is_opaque);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline SkBitmap NSImageRepToSkBitmapWithColorSpace(NSImageRep* image,
                                                    NSSize size,
                                                    bool is_opaque,
-                                                   CGColorSpaceRef colorspace);
+                                                   CGColorSpaceRef colorspace) {
+  return NSImageRepToSkBitmap(image, size, is_opaque);
+}
 
 // Given an SkBitmap, return an autoreleased NSBitmapImageRep.
-SK_API NSBitmapImageRep* SkBitmapToNSBitmapImageRepWithColorSpace(
+SK_API NSBitmapImageRep* SkBitmapToNSBitmapImageRep(const SkBitmap& skiaBitmap);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline NSBitmapImageRep* SkBitmapToNSBitmapImageRepWithColorSpace(
     const SkBitmap& skiaBitmap,
-    CGColorSpaceRef colorSpace);
+    CGColorSpaceRef colorSpace) {
+  return SkBitmapToNSBitmapImageRep(skiaBitmap);
+}
 
 #endif  // __OBJC__
 
 // Given an SkBitmap and a color space, return an autoreleased NSImage.
 // TODO(https://crbug.com/1433041): Restrict this to Objective-C callers.
-SK_API NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& icon,
-                                                CGColorSpaceRef colorSpace);
+SK_API NSImage* SkBitmapToNSImage(const SkBitmap& icon);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& icon,
+                                                CGColorSpaceRef colorSpace) {
+  return SkBitmapToNSImage(icon);
+}
 
 }  // namespace skia
 
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index 6629a96..ab4c21a 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -9,28 +9,64 @@
 
 #include <memory>
 
+#include "base/apple/foundation_util.h"
 #include "base/apple/scoped_cftyperef.h"
 #include "base/check.h"
 #include "base/mac/mac_util.h"
 #include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
 
 namespace {
 
 // Draws an NSImage or an NSImageRep with a given size into a SkBitmap.
-SkBitmap NSImageOrNSImageRepToSkBitmapWithColorSpace(
-    NSImage* image,
-    NSImageRep* image_rep,
-    NSSize size,
-    bool is_opaque,
-    CGColorSpaceRef color_space) {
+SkBitmap NSImageOrNSImageRepToSkBitmap(NSImage* image,
+                                       NSImageRep* image_rep,
+                                       NSSize size,
+                                       bool is_opaque) {
   // Only image or image_rep should be provided, not both.
   DCHECK((image != nullptr) ^ (image_rep != nullptr));
 
-  SkBitmap bitmap;
-  if (!bitmap.tryAllocN32Pixels(size.width, size.height, is_opaque))
-    return bitmap;  // Return |bitmap| which should respond true to isNull().
+  // Determine the color space for the SkBitmap. Any color space is acceptable,
+  // but if we can match the color space of `image` or `image_rep` then the
+  // result will be higher fidelity.
+  sk_sp<SkColorSpace> sk_color_space;
+  {
+    NSBitmapImageRep* bitmap_image_rep = nil;
+    if (image_rep) {
+      // If `image_rep` is an NSBitmapImageRep, then use its color space.
+      bitmap_image_rep = base::apple::ObjCCast<NSBitmapImageRep>(image_rep);
+    } else {
+      // If `image` has an NSBitmapImageRep, then use the color space of the
+      // first encountered NSBitmapImageRep.
+      for (NSImageRep* rep in [image representations]) {
+        bitmap_image_rep = base::apple::ObjCCast<NSBitmapImageRep>(rep);
+        if (bitmap_image_rep) {
+          break;
+        }
+      }
+    }
+    sk_color_space = SkMakeColorSpaceFromCGColorSpace(
+        [[bitmap_image_rep colorSpace] CGColorSpace]);
 
+    // If we did not extract a color space that matches the input, default to
+    // using sRGB.
+    if (!sk_color_space) {
+      sk_color_space = SkColorSpace::MakeSRGB();
+    }
+  }
+
+  // Set the CGColorSpace of the CGContext to match the SkColorSpace.
+  base::apple::ScopedCFTypeRef<CGColorSpaceRef> cg_color_space(
+      SkCreateCGColorSpace(sk_color_space.get()));
+
+  SkImageInfo info = SkImageInfo::MakeN32(
+      size.width, size.height,
+      is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType, sk_color_space);
+  SkBitmap bitmap;
+  if (!bitmap.tryAllocPixels(info)) {
+    return bitmap;  // Return |bitmap| which should respond true to isNull().
+  }
 
   void* data = bitmap.getPixels();
 
@@ -41,7 +77,7 @@
              && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
 #if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
   base::apple::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
-      data, size.width, size.height, 8, size.width * 4, color_space,
+      data, size.width, size.height, 8, size.width * 4, cg_color_space.get(),
       uint32_t{kCGImageAlphaPremultipliedFirst} | kCGBitmapByteOrder32Host));
 #else
 #error We require that Skia's and CoreGraphics's recommended \
@@ -210,26 +246,22 @@
   return SkBitmap();
 }
 
-SkBitmap NSImageToSkBitmapWithColorSpace(
-    NSImage* image, bool is_opaque, CGColorSpaceRef color_space) {
-  return NSImageOrNSImageRepToSkBitmapWithColorSpace(
-      image, /*image_rep=*/nil, image.size, is_opaque, color_space);
+SkBitmap NSImageToSkBitmap(NSImage* image, bool is_opaque) {
+  return NSImageOrNSImageRepToSkBitmap(image, /*image_rep=*/nil, image.size,
+                                       is_opaque);
 }
 
-SkBitmap NSImageRepToSkBitmapWithColorSpace(NSImageRep* image_rep,
-                                            NSSize size,
-                                            bool is_opaque,
-                                            CGColorSpaceRef color_space) {
-  return NSImageOrNSImageRepToSkBitmapWithColorSpace(
-      /*image=*/nil, image_rep, size, is_opaque, color_space);
+SkBitmap NSImageRepToSkBitmap(NSImageRep* image_rep,
+                              NSSize size,
+                              bool is_opaque) {
+  return NSImageOrNSImageRepToSkBitmap(
+      /*image=*/nil, image_rep, size, is_opaque);
 }
 
-NSBitmapImageRep* SkBitmapToNSBitmapImageRepWithColorSpace(
-    const SkBitmap& skiaBitmap,
-    CGColorSpaceRef colorSpace) {
+NSBitmapImageRep* SkBitmapToNSBitmapImageRep(const SkBitmap& skiaBitmap) {
   // First convert SkBitmap to CGImageRef.
   base::apple::ScopedCFTypeRef<CGImageRef> cgimage(
-      SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace));
+      SkCreateCGImageRef(skiaBitmap));
   if (!cgimage)
     return nil;
 
@@ -237,14 +269,12 @@
   return [[NSBitmapImageRep alloc] initWithCGImage:cgimage.get()];
 }
 
-NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& skiaBitmap,
-                                         CGColorSpaceRef colorSpace) {
+NSImage* SkBitmapToNSImage(const SkBitmap& skiaBitmap) {
   if (skiaBitmap.isNull())
     return nil;
 
   NSImage* image = [[NSImage alloc] init];
-  NSBitmapImageRep* imageRep =
-      SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, colorSpace);
+  NSBitmapImageRep* imageRep = SkBitmapToNSBitmapImageRep(skiaBitmap);
   if (!imageRep)
     return nil;
   [image addRepresentation:imageRep];
diff --git a/skia/ext/skia_utils_mac_unittest.mm b/skia/ext/skia_utils_mac_unittest.mm
index 1470ba6..a9a26c46 100644
--- a/skia/ext/skia_utils_mac_unittest.mm
+++ b/skia/ext/skia_utils_mac_unittest.mm
@@ -41,8 +41,8 @@
   // Checks that the given bitmap is red.
   void TestSkBitmap(const SkBitmap& bitmap);
 
-  // Tests `SkBitmapToNSImageWithColorSpace` for a specific combination of color
-  // and color type. Creates a bitmap with `CreateSkBitmap`, converts it into an
+  // Tests `SkBitmapToNSImage` for a specific combination of color and color
+  // type. Creates a bitmap with `CreateSkBitmap`, converts it into an
   // `NSImage`, then tests it with `TestImageRep`.
   void ShapeHelper(int width,
                    int height,
@@ -155,8 +155,7 @@
   SkBitmap bitmap(CreateSkBitmap(width, height, test_color, color_type));
 
   // Confirm size
-  NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
-      bitmap, base::mac::GetSRGBColorSpace());
+  NSImage* image = skia::SkBitmapToNSImage(bitmap);
   EXPECT_DOUBLE_EQ(image.size.width, (CGFloat)width);
   EXPECT_DOUBLE_EQ(image.size.height, (CGFloat)height);
 
@@ -186,8 +185,7 @@
 
   SkBitmap bitmap(
       CreateSkBitmap(width, height, TestColor::kBlue, ColorType::k24Bit));
-  NSBitmapImageRep* imageRep = skia::SkBitmapToNSBitmapImageRepWithColorSpace(
-      bitmap, base::mac::GetSRGBColorSpace());
+  NSBitmapImageRep* imageRep = skia::SkBitmapToNSBitmapImageRep(bitmap);
 
   EXPECT_DOUBLE_EQ(width, imageRep.size.width);
   EXPECT_DOUBLE_EQ(height, imageRep.size.height);
@@ -202,8 +200,7 @@
   EXPECT_EQ(1u, image.representations.count);
   NSBitmapImageRep* imageRep = base::apple::ObjCCastStrict<NSBitmapImageRep>(
       image.representations.lastObject);
-  SkBitmap bitmap(skia::NSImageRepToSkBitmapWithColorSpace(
-      imageRep, image.size, false, base::mac::GetSRGBColorSpace()));
+  SkBitmap bitmap(skia::NSImageRepToSkBitmap(imageRep, image.size, false));
   TestSkBitmap(bitmap);
 }
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 206eb45..44fc73e 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -6193,9 +6193,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6205,8 +6205,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -6343,9 +6343,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6355,8 +6355,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 1592f11..b135935 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -20593,9 +20593,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20605,8 +20605,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -20743,9 +20743,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20755,8 +20755,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 441debb..28fed8b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -43432,9 +43432,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43443,8 +43443,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -43582,9 +43582,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43593,8 +43593,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -44906,9 +44906,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44917,8 +44917,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -45056,9 +45056,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45067,8 +45067,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -45766,9 +45766,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45777,8 +45777,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 86d4d7e..3e39298 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -16313,12 +16313,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16328,8 +16328,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
@@ -16483,12 +16483,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 122.0.6181.0",
+        "description": "Run with ash-chrome version 122.0.6182.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16498,8 +16498,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v122.0.6181.0",
-              "revision": "version:122.0.6181.0"
+              "location": "lacros_version_skew_tests_v122.0.6182.0",
+              "revision": "version:122.0.6182.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 0eb43b4..0a96cd90 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -337,16 +337,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 122.0.6181.0',
+    'description': 'Run with ash-chrome version 122.0.6182.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6181.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v122.0.6182.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v122.0.6181.0',
-          'revision': 'version:122.0.6181.0',
+          'location': 'lacros_version_skew_tests_v122.0.6182.0',
+          'revision': 'version:122.0.6182.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8d45ba5d..355c4ac 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -20677,6 +20677,25 @@
             ]
         }
     ],
+    "WaffleAndroidStudy": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "favicon_size_in_dip": "32"
+                    },
+                    "enable_features": [
+                        "LargeFaviconFromGoogle",
+                        "SearchEngineChoice"
+                    ]
+                }
+            ]
+        }
+    ],
     "WaffleStudy": [
         {
             "platforms": [
diff --git a/third_party/android_toolchain/3pp/install.sh b/third_party/android_toolchain/3pp/install.sh
index 224463ec..5438512ec 100755
--- a/third_party/android_toolchain/3pp/install.sh
+++ b/third_party/android_toolchain/3pp/install.sh
@@ -48,5 +48,5 @@
 
 # Remove excluded files from the staging directory.
 for pattern in "${GLOB_EXCLUDES[@]}"; do
-  rm -rf $pattern
+  rm -rf "${PREFIX}/${pattern}"
 done
diff --git a/third_party/android_toolchain_canary/3pp/install.sh b/third_party/android_toolchain_canary/3pp/install.sh
index d6f7c1c..50ece3c 100755
--- a/third_party/android_toolchain_canary/3pp/install.sh
+++ b/third_party/android_toolchain_canary/3pp/install.sh
@@ -50,5 +50,5 @@
 
 # Remove excluded files from the staging directory.
 for pattern in "${GLOB_EXCLUDES[@]}"; do
-  rm -rf $pattern
+  rm -rf "${PREFIX}/${pattern}"
 done
diff --git a/third_party/angle b/third_party/angle
index 35e49df..bdd3a77 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 35e49df77d01932715b8cd8dd3e1613cbd476561
+Subproject commit bdd3a778370b833bb91659971efa001c584900a8
diff --git a/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom b/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
index de7d10f..87e985c3 100644
--- a/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
+++ b/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
@@ -5,6 +5,7 @@
 module blink.mojom;
 
 import "mojo/public/mojom/base/byte_string.mojom";
+import "mojo/public/mojom/base/time.mojom";
 import "url/mojom/url.mojom";
 
 // Interface for LCP Critical Path Predictor from the renderer process.
@@ -27,6 +28,14 @@
   // - and the `font_url` scheme is HTTP or HTTPS,
   // Otherwise, the renderer will be killed.
   NotifyFetchedFont(url.mojom.Url font_url);
+
+  // This method is for letting the LCPP know the subresource URL.  This
+  // method should be called under the following conditions:
+  // - the `kHttpDiskCachePrewarming` feature is enabled,
+  // - and the `subresource_url` scheme is HTTP or HTTPS,
+  // Otherwise, the renderer will be killed.
+  // 'subresource_load_start' is the duration from navigation start to resource loading start time.
+  NotifyFetchedSubresource(url.mojom.Url subresource_url, mojo_base.mojom.TimeDelta subresource_load_start);
 };
 
 // LCP Critical Path Predictor hints provided at navigation time.
diff --git a/third_party/blink/public/mojom/printing/web_printing.mojom b/third_party/blink/public/mojom/printing/web_printing.mojom
index e683c27c..5b501d5 100644
--- a/third_party/blink/public/mojom/printing/web_printing.mojom
+++ b/third_party/blink/public/mojom/printing/web_printing.mojom
@@ -17,6 +17,11 @@
   kTwoSidedShortEdge
 };
 
+enum WebPrintColorMode {
+  kColor,
+  kMonochrome
+};
+
 // Basic description of a single printer.
 struct WebPrinterInfo {
   string printer_name;
@@ -36,6 +41,9 @@
   WebPrintingMultipleDocumentHandling multiple_document_handling_default;
   array<WebPrintingMultipleDocumentHandling> multiple_document_handling_supported;
 
+  WebPrintColorMode print_color_mode_default;
+  array<WebPrintColorMode> print_color_mode_supported;
+
   WebPrintingSides? sides_default;
   array<WebPrintingSides> sides_supported;
 };
@@ -45,6 +53,7 @@
 
   uint32 copies;
   WebPrintingMultipleDocumentHandling? multiple_document_handling;
+  WebPrintColorMode? print_color_mode;
   WebPrintingSides? sides;
 };
 
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 6219ead..2ba868f0 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -478,6 +478,11 @@
   // Returns whether this WebView represents a fenced frame root or not.
   virtual bool IsFencedFrameRoot() const = 0;
 
+  // Draggable Regions ---------------------------------------------------
+  // Indicates that this WebView should collect draggable regions set using the
+  // app-region CSS property.
+  virtual void SetSupportsAppRegion(bool supports_app_region) = 0;
+
   // Misc -------------------------------------------------------------
 
   // Returns the number of live WebView instances in this process.
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 84a86ff..18590589 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -3118,6 +3118,8 @@
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_printing_resolution_units.h",
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_printing_sides.cc",
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_printing_sides.h",
+    "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_print_color_mode.cc",
+    "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_print_color_mode.h",
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_print_job_state.cc",
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_print_job_state.h",
     "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_web_print_quality.cc",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index a6ed7ad1..1578648 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1495,6 +1495,9 @@
   sources += rebase_path(blink_core_tests_intersection_observer,
                          "",
                          "intersection_observer")
+  sources += rebase_path(blink_core_tests_lcp_critical_path_predictor,
+                         "",
+                         "lcp_critical_path_predictor")
   sources += rebase_path(blink_core_tests_mathml, "", "mathml")
   sources += rebase_path(blink_core_tests_messaging, "", "messaging")
   sources += rebase_path(blink_core_tests_mobile_metrics, "", "mobile_metrics")
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 738c251..77d5462 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -7034,6 +7034,7 @@
 }
 
 TEST_F(StyleEngineTest, EnsureAppRegionTriggersRelayout) {
+  GetDocument().GetFrame()->SetSupportsAppRegion(true);
   GetDocument().body()->setInnerHTML(R"HTML(
     <head>
     <style>
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index adb1c7c..81a6dbe 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3988,6 +3988,10 @@
   return GetPage()->IsMainFrameFencedFrameRoot();
 }
 
+void WebViewImpl::SetSupportsAppRegion(bool supports_app_region) {
+  MainFrameImpl()->GetFrame()->SetSupportsAppRegion(supports_app_region);
+}
+
 void WebViewImpl::MojoDisconnected() {
 #if !(BUILDFLAG(IS_ANDROID) || \
       (BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_ARM64)))
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 5a99921..3aeffb1 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -241,6 +241,7 @@
   int32_t HistoryListLength() const { return history_list_length_; }
   const SessionStorageNamespaceId& GetSessionStorageNamespaceId() override;
   bool IsFencedFrameRoot() const override;
+  void SetSupportsAppRegion(bool supports_app_region) override;
 
   // Functions to add and remove observers for this object.
   void AddObserver(WebViewObserver* observer);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 4bbd11e8..a2d66e8 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -3827,4 +3827,19 @@
   return loader_.GetDocumentLoader()->GetContentSettings();
 }
 
+bool LocalFrame::SupportsAppRegion() {
+  return supports_app_region_;
+}
+
+void LocalFrame::SetSupportsAppRegion(bool supports_app_region) {
+  supports_app_region_ = supports_app_region;
+  if (supports_app_region) {
+    view_->UpdateDocumentAnnotatedRegions();
+  } else {
+    CHECK(GetDocument());
+    GetDocument()->SetAnnotatedRegions(Vector<AnnotatedRegionValue>());
+    Client()->AnnotatedRegionsChanged();
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 534393e..6e19d55 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -925,6 +925,10 @@
   // Can only be called while the frame is not detached.
   const mojom::RendererContentSettingsPtr& GetContentSettings();
 
+  // Returns true if the frame supports app-region: drag/no-drag.
+  bool SupportsAppRegion();
+  void SetSupportsAppRegion(bool supports_app_region);
+
  private:
   friend class FrameNavigationDisabler;
   // LocalFrameMojoHandler is a part of LocalFrame.
@@ -1186,6 +1190,8 @@
 
   Member<v8_compile_hints::V8LocalCompileHintsProducer>
       v8_local_compile_hints_producer_;
+
+  bool supports_app_region_ = false;
 };
 
 inline FrameLoader& LocalFrame::Loader() const {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 91dba0ae..3016bc66 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1747,8 +1747,10 @@
 
 void LocalFrameView::UpdateDocumentAnnotatedRegions() const {
   Document* document = frame_->GetDocument();
-  if (!document->HasAnnotatedRegions())
+  if (!document->HasAnnotatedRegions() || !frame_->SupportsAppRegion()) {
     return;
+  }
+
   Vector<AnnotatedRegionValue> new_regions;
   CollectAnnotatedRegions(*(document->GetLayoutBox()), new_regions);
   if (new_regions == document->AnnotatedRegions())
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index 9bd131b..d851151 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -100,6 +100,8 @@
   kResetForTesting,
 };
 
+const char kHistogramScanAndPreloadTime[] = "Blink.ScanAndPreloadTime2";
+
 bool ThreadedPreloadScannerEnabled(
     FeatureResetMode reset_mode = FeatureResetMode::kUseCached) {
   // Cache the feature value since checking for each parser regresses some micro
@@ -1346,12 +1348,27 @@
 
 void HTMLDocumentParser::ScanAndPreload(HTMLPreloadScanner* scanner) {
   TRACE_EVENT0("blink", "HTMLDocumentParser::ScanAndPreload");
-  DCHECK(preloader_);
-  base::ElapsedTimer timer;
-  ProcessPreloadData(scanner->Scan(GetDocument()->ValidBaseElementURL()));
+  CHECK(preloader_);
+  base::ElapsedTimer timer_before_scan;
+  std::unique_ptr<PendingPreloadData> preload_data =
+      scanner->Scan(GetDocument()->ValidBaseElementURL());
+  base::UmaHistogramMicrosecondsTimes(
+      base::StrCat(
+          {kHistogramScanAndPreloadTime, ".Scan", GetPreloadHistogramSuffix()}),
+      timer_before_scan.Elapsed());
+  base::ElapsedTimer timer_after_scan;
+  ProcessPreloadData(std::move(preload_data));
+  base::UmaHistogramMicrosecondsTimes(
+      base::StrCat({kHistogramScanAndPreloadTime, GetPreloadHistogramSuffix()}),
+      timer_before_scan.Elapsed());
+  // Keep old histogram until next expiry date.
   base::UmaHistogramTimes(
       base::StrCat({"Blink.ScanAndPreloadTime", GetPreloadHistogramSuffix()}),
-      timer.Elapsed());
+      timer_before_scan.Elapsed());
+  base::UmaHistogramMicrosecondsTimes(
+      base::StrCat({kHistogramScanAndPreloadTime, ".Preload",
+                    GetPreloadHistogramSuffix()}),
+      timer_after_scan.Elapsed());
 }
 
 void HTMLDocumentParser::ProcessPreloadData(
diff --git a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
index 76c494d..a72a1e2 100644
--- a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
+++ b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
@@ -228,8 +228,7 @@
       base::TimeTicks::Now() -
       document->Loader()->GetTiming().NavigationStart();
   CHECK_GE(resource_load_start, base::Seconds(0));
-  // TODO(chikamune): Send url and resource_load_start to browser.
-  NOTIMPLEMENTED();
+  GetHost().NotifyFetchedSubresource(url, resource_load_start);
 }
 
 mojom::blink::LCPCriticalPathPredictorHost&
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 7337cee..30818d9 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/loader/preload_helper.h"
 
+#include "base/metrics/histogram_functions.h"
+#include "base/timer/elapsed_timer.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -909,6 +911,8 @@
 Resource* PreloadHelper::StartPreload(ResourceType type,
                                       FetchParameters& params,
                                       Document& document) {
+  base::ElapsedTimer timer;
+
   ResourceFetcher* resource_fetcher = document.Fetcher();
   Resource* resource = nullptr;
   switch (type) {
@@ -967,6 +971,9 @@
       NOTREACHED();
   }
 
+  base::UmaHistogramMicrosecondsTimes("Blink.PreloadRequestStartDuration",
+                                      timer.Elapsed());
+
   return resource;
 }
 
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index afc0d9e1..787f139 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -4,23 +4,7 @@
 
 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
 
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/frame/settings.h"
-#include "third_party/blink/renderer/core/layout/fragmentation_utils.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/layout/physical_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/table/layout_table_cell.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
-#include "third_party/blink/renderer/core/style/border_edge.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
-#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
 
 namespace blink {
 
@@ -221,243 +205,31 @@
 
 void BackgroundImageGeometry::UseFixedAttachment(
     const PhysicalOffset& attachment_point) {
-  DCHECK(has_background_fixed_to_viewport_);
   PhysicalOffset fixed_adjustment =
       attachment_point - unsnapped_dest_rect_.offset;
   fixed_adjustment.ClampNegativeToZero();
   phase_ += fixed_adjustment;
 }
 
-bool BackgroundImageGeometry::ShouldUseFixedAttachment(
-    const FillLayer& fill_layer) const {
-  // Only backgrounds fixed to viewport should be treated as fixed attachment.
-  // See comments in the private constructor.
-  return has_background_fixed_to_viewport_ &&
-         // Solid color background should use default attachment.
-         fill_layer.GetImage() &&
-         fill_layer.Attachment() == EFillAttachment::kFixed;
-}
-
-bool BackgroundImageGeometry::CanCompositeBackgroundAttachmentFixed() const {
-  return !painting_view_ && has_background_fixed_to_viewport_ &&
-         positioning_box_->CanCompositeBackgroundAttachmentFixed();
-}
-
-PhysicalRect BackgroundImageGeometry::FixedAttachmentPositioningArea(
-    const PaintInfo& paint_info) const {
-  const ScrollableArea* layout_viewport =
-      box_->GetFrameView()->LayoutViewport();
-  DCHECK(layout_viewport);
-  PhysicalSize size(layout_viewport->VisibleContentRect().size());
-  if (CanCompositeBackgroundAttachmentFixed()) {
-    // The caller should have adjusted paint chunk properties to be in the
-    // viewport space.
-    return PhysicalRect(PhysicalOffset(), size);
-  }
-  gfx::PointF viewport_origin_in_local_space =
-      GeometryMapper::SourceToDestinationProjection(
-          box_->View()->FirstFragment().LocalBorderBoxProperties().Transform(),
-          paint_info.context.GetPaintController()
-              .CurrentPaintChunkProperties()
-              .Transform())
-          .MapPoint(gfx::PointF());
-  return PhysicalRect(
-      PhysicalOffset::FromPointFRound(viewport_origin_in_local_space),
-      PhysicalSize(layout_viewport->VisibleContentRect().size()));
-}
-
-namespace {
-
-// Computes the stitched table-grid rect relative to the current fragment.
-PhysicalRect ComputeStitchedTableGridRect(const PhysicalBoxFragment& fragment) {
-  const auto writing_direction = fragment.Style().GetWritingDirection();
-  LogicalRect table_grid_rect;
-  LogicalRect fragment_local_grid_rect;
-  LayoutUnit stitched_block_size;
-
-  for (const PhysicalBoxFragment& walker :
-       To<LayoutBox>(fragment.GetLayoutObject())->PhysicalFragments()) {
-    LogicalRect local_grid_rect = walker.TableGridRect();
-    local_grid_rect.offset.block_offset += stitched_block_size;
-    if (table_grid_rect.IsEmpty())
-      table_grid_rect = local_grid_rect;
-    else
-      table_grid_rect.Unite(local_grid_rect);
-
-    if (&walker == &fragment)
-      fragment_local_grid_rect = local_grid_rect;
-
-    stitched_block_size +=
-        LogicalFragment(writing_direction, walker).BlockSize();
-  }
-
-  // Make the rect relative to the fragment we are currently painting.
-  table_grid_rect.offset.block_offset -=
-      fragment_local_grid_rect.offset.block_offset;
-
-  WritingModeConverter converter(
-      writing_direction, ToPhysicalSize(fragment_local_grid_rect.size,
-                                        writing_direction.GetWritingMode()));
-  return converter.ToPhysical(table_grid_rect);
-}
-
-}  // Anonymous namespace
-
 BackgroundImageGeometry::BackgroundImageGeometry(
     const LayoutView& view,
     const PhysicalOffset& element_positioning_area_offset)
-    : box_(&view), positioning_box_(&view.RootBox()) {
-  has_background_fixed_to_viewport_ = view.IsBackgroundAttachmentFixedObject();
-  painting_view_ = true;
-  // The background of the box generated by the root element covers the
-  // entire canvas and will be painted by the view object, but the we should
-  // still use the root element box for positioning.
-  positioning_size_override_ = view.RootBox().Size();
-  // The background image should paint from the root element's coordinate space.
-  element_positioning_area_offset_ = element_positioning_area_offset;
-}
+    : paint_context_(view, element_positioning_area_offset) {}
 
 BackgroundImageGeometry::BackgroundImageGeometry(
     const LayoutBoxModelObject& obj)
-    : BackgroundImageGeometry(&obj, &obj) {}
+    : paint_context_(obj) {}
 
 // TablesNG background painting.
 BackgroundImageGeometry::BackgroundImageGeometry(const LayoutTableCell& cell,
                                                  PhysicalOffset cell_offset,
                                                  const LayoutBox& table_part,
                                                  PhysicalSize table_part_size)
-    : BackgroundImageGeometry(&cell, &table_part) {
-  painting_table_cell_ = true;
-  cell_using_container_background_ = true;
-  element_positioning_area_offset_ = cell_offset;
-  positioning_size_override_ = table_part_size;
-}
+    : paint_context_(cell, cell_offset, table_part, table_part_size) {}
 
 BackgroundImageGeometry::BackgroundImageGeometry(
     const PhysicalBoxFragment& fragment)
-    : BackgroundImageGeometry(
-          To<LayoutBoxModelObject>(fragment.GetLayoutObject()),
-          To<LayoutBoxModelObject>(fragment.GetLayoutObject())) {
-  DCHECK(box_->IsBox());
-
-  if (fragment.IsTable()) {
-    auto stitched_background_rect = ComputeStitchedTableGridRect(fragment);
-    positioning_size_override_ = stitched_background_rect.size;
-    element_positioning_area_offset_ = -stitched_background_rect.offset;
-    box_has_multiple_fragments_ = !fragment.IsOnlyForNode();
-  } else if (!fragment.IsOnlyForNode()) {
-    // The element is block-fragmented. We need to calculate the correct
-    // background offset within an imaginary box where all the fragments have
-    // been stitched together.
-    element_positioning_area_offset_ =
-        OffsetInStitchedFragments(fragment, &positioning_size_override_);
-    box_has_multiple_fragments_ = true;
-  }
-}
-
-BackgroundImageGeometry::BackgroundImageGeometry(
-    const LayoutBoxModelObject* box,
-    const LayoutBoxModelObject* positioning_box)
-    : box_(box),
-      positioning_box_(positioning_box),
-      has_background_fixed_to_viewport_(
-          HasBackgroundFixedToViewport(*positioning_box)) {
-  // Specialized constructor should be used for LayoutView.
-  DCHECK(!IsA<LayoutView>(box));
-  DCHECK(box);
-  DCHECK(positioning_box);
-}
-
-PhysicalBoxStrut BackgroundImageGeometry::VisualOverflowOutsets() const {
-  PhysicalRect border_box;
-  if (positioning_box_->IsBox()) {
-    border_box = To<LayoutBox>(positioning_box_)->PhysicalBorderBoxRect();
-  } else {
-    border_box = To<LayoutInline>(positioning_box_)->PhysicalLinesBoundingBox();
-  }
-  PhysicalRect visual_overflow =
-      positioning_box_->Layer()
-          ->LocalBoundingBoxIncludingSelfPaintingDescendants();
-  return PhysicalBoxStrut(visual_overflow.Y() - border_box.Y(),
-                          border_box.Right() - visual_overflow.Right(),
-                          border_box.Bottom() - visual_overflow.Bottom(),
-                          visual_overflow.X() - border_box.X());
-}
-
-PhysicalBoxStrut BackgroundImageGeometry::InnerBorderOutsets(
-    const PhysicalRect& dest_rect,
-    const PhysicalRect& positioning_area) const {
-  gfx::RectF inner_border_rect =
-      RoundedBorderGeometry::PixelSnappedRoundedInnerBorder(
-          positioning_box_->StyleRef(), positioning_area)
-          .Rect();
-  PhysicalBoxStrut outset;
-  // TODO(rendering-core) The LayoutUnit(float) constructor always rounds
-  // down. We should FromFloatFloor or FromFloatCeil to move toward the border.
-  outset.left = LayoutUnit(inner_border_rect.x()) - dest_rect.X();
-  outset.top = LayoutUnit(inner_border_rect.y()) - dest_rect.Y();
-  outset.right = dest_rect.Right() - LayoutUnit(inner_border_rect.right());
-  outset.bottom = dest_rect.Bottom() - LayoutUnit(inner_border_rect.bottom());
-  return outset;
-}
-
-SnappedAndUnsnappedOutsets BackgroundImageGeometry::ObscuredBorderOutsets(
-    const PhysicalRect& dest_rect,
-    const PhysicalRect& positioning_area) const {
-  const ComputedStyle& style = positioning_box_->StyleRef();
-  gfx::RectF inner_border_rect =
-      RoundedBorderGeometry::PixelSnappedRoundedInnerBorder(style,
-                                                            positioning_area)
-          .Rect();
-
-  BorderEdge edges[4];
-  style.GetBorderEdgeInfo(edges);
-  const PhysicalBoxStrut box_outsets = positioning_box_->BorderOutsets();
-  SnappedAndUnsnappedOutsets adjust;
-  if (edges[static_cast<unsigned>(BoxSide::kTop)].ObscuresBackground()) {
-    adjust.snapped.top = LayoutUnit(inner_border_rect.y()) - dest_rect.Y();
-    adjust.unsnapped.top = box_outsets.top;
-  }
-  if (edges[static_cast<unsigned>(BoxSide::kRight)].ObscuresBackground()) {
-    adjust.snapped.right =
-        dest_rect.Right() - LayoutUnit(inner_border_rect.right());
-    adjust.unsnapped.right = box_outsets.right;
-  }
-  if (edges[static_cast<unsigned>(BoxSide::kBottom)].ObscuresBackground()) {
-    adjust.snapped.bottom =
-        dest_rect.Bottom() - LayoutUnit(inner_border_rect.bottom());
-    adjust.unsnapped.bottom = box_outsets.bottom;
-  }
-  if (edges[static_cast<unsigned>(BoxSide::kLeft)].ObscuresBackground()) {
-    adjust.snapped.left = LayoutUnit(inner_border_rect.x()) - dest_rect.X();
-    adjust.unsnapped.left = box_outsets.left;
-  }
-  return adjust;
-}
-
-bool BackgroundImageGeometry::HasBackgroundFixedToViewport(
-    const LayoutBoxModelObject& object) {
-  if (!object.IsBackgroundAttachmentFixedObject()) {
-    return false;
-  }
-  // https://www.w3.org/TR/css-transforms-1/#transform-rendering
-  // Fixed backgrounds on the root element are affected by any transform
-  // specified for that element. For all other elements that are effected
-  // by a transform, a value of fixed for the background-attachment property
-  // is treated as if it had a value of scroll.
-  for (const PaintLayer* layer = object.EnclosingLayer();
-       layer && !layer->IsRootLayer(); layer = layer->Parent()) {
-    // Check LayoutObject::HasTransformRelatedProperty() first to exclude
-    // non-applicable transforms and will-change: transform.
-    LayoutObject& ancestor = layer->GetLayoutObject();
-    if (ancestor.HasTransformRelatedProperty() &&
-        (layer->Transform() ||
-         ancestor.StyleRef().HasWillChangeHintForAnyTransformProperty())) {
-      return false;
-    }
-  }
-  return true;
-}
+    : paint_context_(fragment) {}
 
 SnappedAndUnsnappedOutsets BackgroundImageGeometry::ComputeDestRectAdjustments(
     const FillLayer& fill_layer,
@@ -466,7 +238,7 @@
   SnappedAndUnsnappedOutsets dest_adjust;
   switch (fill_layer.Clip()) {
     case EFillBox::kNoClip:
-      dest_adjust.unsnapped = VisualOverflowOutsets();
+      dest_adjust.unsnapped = paint_context_.VisualOverflowOutsets();
       dest_adjust.snapped = dest_adjust.unsnapped;
       break;
     case EFillBox::kFillBox:
@@ -476,24 +248,24 @@
     case EFillBox::kContent:
       // If the PaddingOutsets are zero then this is equivalent to
       // kPadding and we should apply the snapping logic.
-      dest_adjust.unsnapped = positioning_box_->PaddingOutsets();
+      dest_adjust.unsnapped = paint_context_.PaddingOutsets();
       if (!dest_adjust.unsnapped.IsZero()) {
-        dest_adjust.unsnapped += positioning_box_->BorderOutsets();
+        dest_adjust.unsnapped += paint_context_.BorderOutsets();
         // We're not trying to match a border position, so don't snap.
         dest_adjust.snapped = dest_adjust.unsnapped;
         break;
       }
       [[fallthrough]];
     case EFillBox::kPadding:
-      dest_adjust.unsnapped = positioning_box_->BorderOutsets();
+      dest_adjust.unsnapped = paint_context_.BorderOutsets();
       if (disallow_border_derived_adjustment) {
         // Nothing to drive snapping behavior, so don't snap.
         dest_adjust.snapped = dest_adjust.unsnapped;
       } else {
         // Force the snapped dest rect to match the inner border to
         // avoid gaps between the background and border.
-        dest_adjust.snapped = InnerBorderOutsets(unsnapped_dest_rect_,
-                                                 unsnapped_positioning_area);
+        dest_adjust.snapped = paint_context_.InnerBorderOutsets(
+            unsnapped_dest_rect_, unsnapped_positioning_area);
       }
       break;
     case EFillBox::kStrokeBox:
@@ -519,8 +291,8 @@
       // the size and position of the borders, sometimes adjusting the inner
       // border by more than a pixel when done (particularly under magnifying
       // zoom).
-      dest_adjust = ObscuredBorderOutsets(unsnapped_dest_rect_,
-                                          unsnapped_positioning_area);
+      dest_adjust = paint_context_.ObscuredBorderOutsets(
+          unsnapped_dest_rect_, unsnapped_positioning_area);
       break;
     }
     case EFillBox::kText:
@@ -543,16 +315,16 @@
     case EFillBox::kContent:
       // If the PaddingOutsets are zero then this is equivalent to
       // kPadding and we should apply the snapping logic.
-      box_outset.unsnapped = positioning_box_->PaddingOutsets();
+      box_outset.unsnapped = paint_context_.PaddingOutsets();
       if (!box_outset.unsnapped.IsZero()) {
-        box_outset.unsnapped += positioning_box_->BorderOutsets();
+        box_outset.unsnapped += paint_context_.BorderOutsets();
         // We're not trying to match a border position, so don't snap.
         box_outset.snapped = box_outset.unsnapped;
         break;
       }
       [[fallthrough]];
     case EFillBox::kPadding:
-      box_outset.unsnapped = positioning_box_->BorderOutsets();
+      box_outset.unsnapped = paint_context_.BorderOutsets();
       if (disallow_border_derived_adjustment) {
         box_outset.snapped = box_outset.unsnapped;
       } else {
@@ -562,8 +334,8 @@
         // the size and position of the borders, sometimes adjusting the inner
         // border by more than a pixel when done (particularly under magnifying
         // zoom).
-        box_outset.snapped = InnerBorderOutsets(unsnapped_positioning_area,
-                                                unsnapped_positioning_area);
+        box_outset.snapped = paint_context_.InnerBorderOutsets(
+            unsnapped_positioning_area, unsnapped_positioning_area);
       }
       break;
     case EFillBox::kStrokeBox:
@@ -582,20 +354,6 @@
   return box_outset;
 }
 
-PhysicalRect BackgroundImageGeometry::ComputePositioningArea(
-    const PaintInfo& paint_info,
-    const FillLayer& fill_layer,
-    const PhysicalRect& paint_rect) const {
-  if (ShouldUseFixedAttachment(fill_layer)) {
-    return FixedAttachmentPositioningArea(paint_info);
-  }
-  if (painting_view_ || cell_using_container_background_ ||
-      box_has_multiple_fragments_) {
-    return {PhysicalOffset(), positioning_size_override_};
-  }
-  return paint_rect;
-}
-
 void BackgroundImageGeometry::AdjustPositioningArea(
     const PaintInfo& paint_info,
     const FillLayer& fill_layer,
@@ -604,7 +362,7 @@
     PhysicalRect& snapped_positioning_area,
     PhysicalOffset& unsnapped_box_offset,
     PhysicalOffset& snapped_box_offset) {
-  if (ShouldUseFixedAttachment(fill_layer)) {
+  if (paint_context_.ShouldUseFixedAttachment(fill_layer)) {
     unsnapped_dest_rect_ = snapped_dest_rect_ = snapped_positioning_area =
         unsnapped_positioning_area;
   } else {
@@ -635,10 +393,7 @@
     bool disallow_border_derived_adjustment =
         !ShouldPaintSelfBlockBackground(paint_info.phase) ||
         fill_layer.Composite() != CompositeOperator::kCompositeSourceOver ||
-        painting_view_ || painting_table_cell_ || box_has_multiple_fragments_ ||
-        positioning_box_->StyleRef().BorderImage().GetImage() ||
-        positioning_box_->StyleRef().BorderCollapse() ==
-            EBorderCollapse::kCollapse;
+        paint_context_.DisallowBorderDerivedAdjustment();
 
     // Compute all the outsets we need to apply to the rectangles. These
     // outsets also include the snapping behavior.
@@ -679,14 +434,14 @@
     const PhysicalSize& snapped_positioning_area_size) {
   StyleImage* image = fill_layer.GetImage();
   EFillSizeType type = fill_layer.SizeType();
+  const ComputedStyle& style = paint_context_.Style();
 
   // Tile size is snapped for images without intrinsic dimensions (typically
   // generated content) and unsnapped for content that has intrinsic
   // dimensions. Once we choose here we stop tracking whether the tile size is
   // snapped or unsnapped.
-  IntrinsicSizingInfo sizing_info =
-      image->GetNaturalSizingInfo(positioning_box_->StyleRef().EffectiveZoom(),
-                                  box_->StyleRef().ImageOrientation());
+  IntrinsicSizingInfo sizing_info = image->GetNaturalSizingInfo(
+      style.EffectiveZoom(), style.ImageOrientation());
   PhysicalSize image_aspect_ratio =
       PhysicalSize::FromSizeFFloor(sizing_info.aspect_ratio);
   PhysicalSize positioning_area_size = !image->HasIntrinsicSize()
@@ -742,10 +497,10 @@
           tile_size_.height = positioning_area_size.height;
         }
       } else if (layer_width.IsAuto() && layer_height.IsAuto()) {
-        PhysicalSize concrete_image_size = PhysicalSize::FromSizeFFloor(
-            image->ImageSize(positioning_box_->StyleRef().EffectiveZoom(),
-                             gfx::SizeF(positioning_area_size),
-                             box_->StyleRef().ImageOrientation()));
+        PhysicalSize concrete_image_size =
+            PhysicalSize::FromSizeFFloor(image->ImageSize(
+                style.EffectiveZoom(), gfx::SizeF(positioning_area_size),
+                style.ImageOrientation()));
         tile_size_ = concrete_image_size;
       }
 
@@ -915,14 +670,11 @@
 void BackgroundImageGeometry::Calculate(const PaintInfo& paint_info,
                                         const FillLayer& fill_layer,
                                         const PhysicalRect& paint_rect) {
-  DCHECK_GE(box_->GetDocument().Lifecycle().GetState(),
-            DocumentLifecycle::kPrePaintClean);
-
   // Unsnapped positioning area is used to derive quantities
   // that reference source image maps and define non-integer values, such
   // as phase and position.
   PhysicalRect unsnapped_positioning_area =
-      ComputePositioningArea(paint_info, fill_layer, paint_rect);
+      paint_context_.ComputePositioningArea(paint_info, fill_layer, paint_rect);
 
   // Snapped positioning area is used for sizing images based on the
   // background area (like cover and contain), and for setting the repeat
@@ -943,13 +695,15 @@
                         snapped_positioning_area.size);
 
   // Applies *-repeat and *-position.
-  const PhysicalOffset offset_in_background = OffsetInBackground(fill_layer);
+  const PhysicalOffset offset_in_background =
+      paint_context_.OffsetInBackground(fill_layer);
   CalculateRepeatAndPosition(
       fill_layer, offset_in_background, unsnapped_positioning_area.size,
       snapped_positioning_area.size, unsnapped_box_offset, snapped_box_offset);
 
-  if (ShouldUseFixedAttachment(fill_layer))
+  if (paint_context_.ShouldUseFixedAttachment(fill_layer)) {
     UseFixedAttachment(paint_rect.offset);
+  }
 
   // The actual painting area can be bigger than the provided background
   // geometry (`paint_rect`) for `mask-clip: no-clip`, so avoid clipping.
@@ -962,24 +716,6 @@
   snapped_dest_rect_ = PhysicalRect(ToPixelSnappedRect(snapped_dest_rect_));
 }
 
-const ImageResourceObserver& BackgroundImageGeometry::ImageClient() const {
-  return *(painting_view_ ? box_ : positioning_box_);
-}
-
-const ComputedStyle& BackgroundImageGeometry::ImageStyle(
-    const ComputedStyle& fragment_style) const {
-  if (painting_view_ || cell_using_container_background_)
-    return positioning_box_->StyleRef();
-  return fragment_style;
-}
-
-PhysicalOffset BackgroundImageGeometry::OffsetInBackground(
-    const FillLayer& fill_layer) const {
-  if (ShouldUseFixedAttachment(fill_layer))
-    return PhysicalOffset();
-  return element_positioning_area_offset_;
-}
-
 PhysicalOffset BackgroundImageGeometry::ComputePhase() const {
   // Given the size that the whole image should draw at, and the input phase
   // requested by the content, and the space between repeated tiles, compute a
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.h b/third_party/blink/renderer/core/paint/background_image_geometry.h
index cd36d3d..f764ff4 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.h
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.h
@@ -6,15 +6,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BACKGROUND_IMAGE_GEOMETRY_H_
 
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
-#include "third_party/blink/renderer/core/paint/paint_phase.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
+#include "third_party/blink/renderer/core/paint/box_background_paint_context.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
 
-class ComputedStyle;
 class FillLayer;
-class ImageResourceObserver;
 class LayoutBox;
 class LayoutBoxModelObject;
 class LayoutTableCell;
@@ -22,11 +19,6 @@
 class PhysicalBoxFragment;
 struct PaintInfo;
 
-struct SnappedAndUnsnappedOutsets {
-  PhysicalBoxStrut snapped;
-  PhysicalBoxStrut unsnapped;
-};
-
 class BackgroundImageGeometry {
   STACK_ALLOCATED();
 
@@ -47,12 +39,6 @@
 
   explicit BackgroundImageGeometry(const PhysicalBoxFragment&);
 
-  // Compute the initial position area based on the geometry for the object
-  // this BackgroundImageGeometry was created for.
-  PhysicalRect ComputePositioningArea(const PaintInfo& paint_info,
-                                      const FillLayer& fill_layer,
-                                      const PhysicalRect& paint_rect) const;
-
   // Calculates data members. This must be called before any of the following
   // getters is called. The document lifecycle phase must be at least
   // PrePaintClean.
@@ -60,6 +46,8 @@
                  const FillLayer&,
                  const PhysicalRect& paint_rect);
 
+  const BoxBackgroundPaintContext& GetContext() const { return paint_context_; }
+
   // Destination rects define the area into which the image will paint.
   // For cases where no explicit background size is requested, the destination
   // also defines the subset of the image to be drawn. Both border-snapped
@@ -93,25 +81,7 @@
   // the image if used as a pattern with background-repeat: space.
   const PhysicalSize& SpaceSize() const { return repeat_spacing_; }
 
-  // Whether the background needs to be positioned relative to a container
-  // element. Only used for tables.
-  bool CellUsingContainerBackground() const {
-    return cell_using_container_background_;
-  }
-
-  const ImageResourceObserver& ImageClient() const;
-  const ComputedStyle& ImageStyle(const ComputedStyle& fragment_style) const;
-
-  bool CanCompositeBackgroundAttachmentFixed() const;
-
-  static bool HasBackgroundFixedToViewport(const LayoutBoxModelObject&);
-
  private:
-  BackgroundImageGeometry(const LayoutBoxModelObject* box,
-                          const LayoutBoxModelObject* positioning_box);
-
-  bool ShouldUseFixedAttachment(const FillLayer&) const;
-
   void SetSpaceSize(const PhysicalSize& repeat_spacing) {
     repeat_spacing_ = repeat_spacing;
   }
@@ -129,7 +99,6 @@
   void SetSpaceX(LayoutUnit space, LayoutUnit extra_offset);
   void SetSpaceY(LayoutUnit space, LayoutUnit extra_offset);
 
-  PhysicalRect FixedAttachmentPositioningArea(const PaintInfo&) const;
   void UseFixedAttachment(const PhysicalOffset& attachment_point);
 
   // Compute adjustments for the destination rects. Adjustments
@@ -167,53 +136,13 @@
       const PhysicalOffset& unsnapped_box_offset,
       const PhysicalOffset& snapped_box_offset);
 
-  PhysicalBoxStrut VisualOverflowOutsets() const;
-  PhysicalBoxStrut InnerBorderOutsets(
-      const PhysicalRect& dest_rect,
-      const PhysicalRect& positioning_area) const;
-  SnappedAndUnsnappedOutsets ObscuredBorderOutsets(
-      const PhysicalRect& dest_rect,
-      const PhysicalRect& positioning_area) const;
-
-  // The offset of the background image within the background positioning area.
-  PhysicalOffset OffsetInBackground(const FillLayer&) const;
-
-  // In most cases this is the same as positioning_box_. They are different
-  // when we are painting:
-  // 1. the view background (box_ is the LayoutView, and positioning_box_ is
-  //    the LayoutView's RootBox()), or
-  // 2. a table cell using its row/column's background (box_ is the table cell,
-  //    and positioning_box_ is the row/column).
-  // When they are different:
-  // - ImageClient() uses box_ if painting view, otherwise positioning_box_;
-  // - ImageStyle() uses positioning_box_;
-  // - FillLayers come from box_ if painting view, otherwise positioning_box_.
-  const LayoutBoxModelObject* const box_;
-
-  // The positioning box is the source of geometric information for positioning
-  // and sizing the background. It also provides the information listed in the
-  // comment for box_.
-  const LayoutBoxModelObject* const positioning_box_;
-
-  // When painting table cells or the view, the positioning area
-  // differs from the requested paint rect.
-  PhysicalSize positioning_size_override_;
-
-  // The background image offset from within the background positioning area for
-  // non-fixed background attachment. Used for table cells and the view, and
-  // also when an element is block-fragmented.
-  PhysicalOffset element_positioning_area_offset_;
+  const BoxBackgroundPaintContext paint_context_;
 
   PhysicalRect unsnapped_dest_rect_;
   PhysicalRect snapped_dest_rect_;
   PhysicalOffset phase_;
   PhysicalSize tile_size_;
   PhysicalSize repeat_spacing_;
-  bool has_background_fixed_to_viewport_ = false;
-  bool painting_view_ = false;
-  bool painting_table_cell_ = false;
-  bool cell_using_container_background_ = false;
-  bool box_has_multiple_fragments_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_background_paint_context.cc b/third_party/blink/renderer/core/paint/box_background_paint_context.cc
new file mode 100644
index 0000000..36760eb
--- /dev/null
+++ b/third_party/blink/renderer/core/paint/box_background_paint_context.cc
@@ -0,0 +1,312 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/box_background_paint_context.h"
+
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/layout/fragmentation_utils.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/table/layout_table_cell.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
+#include "third_party/blink/renderer/core/style/border_edge.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+
+namespace blink {
+
+namespace {
+
+// Computes the stitched table-grid rect relative to the current fragment.
+PhysicalRect ComputeStitchedTableGridRect(const PhysicalBoxFragment& fragment) {
+  const auto writing_direction = fragment.Style().GetWritingDirection();
+  LogicalRect table_grid_rect;
+  LogicalRect fragment_local_grid_rect;
+  LayoutUnit stitched_block_size;
+
+  for (const PhysicalBoxFragment& walker :
+       To<LayoutBox>(fragment.GetLayoutObject())->PhysicalFragments()) {
+    LogicalRect local_grid_rect = walker.TableGridRect();
+    local_grid_rect.offset.block_offset += stitched_block_size;
+    if (table_grid_rect.IsEmpty()) {
+      table_grid_rect = local_grid_rect;
+    } else {
+      table_grid_rect.Unite(local_grid_rect);
+    }
+
+    if (&walker == &fragment) {
+      fragment_local_grid_rect = local_grid_rect;
+    }
+
+    stitched_block_size +=
+        LogicalFragment(writing_direction, walker).BlockSize();
+  }
+
+  // Make the rect relative to the fragment we are currently painting.
+  table_grid_rect.offset.block_offset -=
+      fragment_local_grid_rect.offset.block_offset;
+
+  WritingModeConverter converter(
+      writing_direction, ToPhysicalSize(fragment_local_grid_rect.size,
+                                        writing_direction.GetWritingMode()));
+  return converter.ToPhysical(table_grid_rect);
+}
+
+}  // Anonymous namespace
+
+BoxBackgroundPaintContext::BoxBackgroundPaintContext(
+    const LayoutView& view,
+    const PhysicalOffset& element_positioning_area_offset)
+    : box_(&view), positioning_box_(&view.RootBox()) {
+  has_background_fixed_to_viewport_ = view.IsBackgroundAttachmentFixedObject();
+  painting_view_ = true;
+  // The background of the box generated by the root element covers the
+  // entire canvas and will be painted by the view object, but the we should
+  // still use the root element box for positioning.
+  positioning_size_override_ = view.RootBox().Size();
+  // The background image should paint from the root element's coordinate space.
+  element_positioning_area_offset_ = element_positioning_area_offset;
+}
+
+BoxBackgroundPaintContext::BoxBackgroundPaintContext(
+    const LayoutBoxModelObject& obj)
+    : BoxBackgroundPaintContext(&obj, &obj) {}
+
+// TablesNG background painting.
+BoxBackgroundPaintContext::BoxBackgroundPaintContext(
+    const LayoutTableCell& cell,
+    PhysicalOffset cell_offset,
+    const LayoutBox& table_part,
+    PhysicalSize table_part_size)
+    : BoxBackgroundPaintContext(&cell, &table_part) {
+  painting_table_cell_ = true;
+  cell_using_container_background_ = true;
+  element_positioning_area_offset_ = cell_offset;
+  positioning_size_override_ = table_part_size;
+}
+
+BoxBackgroundPaintContext::BoxBackgroundPaintContext(
+    const PhysicalBoxFragment& fragment)
+    : BoxBackgroundPaintContext(
+          To<LayoutBoxModelObject>(fragment.GetLayoutObject()),
+          To<LayoutBoxModelObject>(fragment.GetLayoutObject())) {
+  DCHECK(box_->IsBox());
+
+  if (fragment.IsTable()) {
+    auto stitched_background_rect = ComputeStitchedTableGridRect(fragment);
+    positioning_size_override_ = stitched_background_rect.size;
+    element_positioning_area_offset_ = -stitched_background_rect.offset;
+    box_has_multiple_fragments_ = !fragment.IsOnlyForNode();
+  } else if (!fragment.IsOnlyForNode()) {
+    // The element is block-fragmented. We need to calculate the correct
+    // background offset within an imaginary box where all the fragments have
+    // been stitched together.
+    element_positioning_area_offset_ =
+        OffsetInStitchedFragments(fragment, &positioning_size_override_);
+    box_has_multiple_fragments_ = true;
+  }
+}
+
+BoxBackgroundPaintContext::BoxBackgroundPaintContext(
+    const LayoutBoxModelObject* box,
+    const LayoutBoxModelObject* positioning_box)
+    : box_(box),
+      positioning_box_(positioning_box),
+      has_background_fixed_to_viewport_(
+          HasBackgroundFixedToViewport(*positioning_box)) {
+  // Specialized constructor should be used for LayoutView.
+  DCHECK(!IsA<LayoutView>(box));
+  DCHECK(box);
+  DCHECK(positioning_box);
+}
+
+PhysicalBoxStrut BoxBackgroundPaintContext::BorderOutsets() const {
+  return positioning_box_->BorderOutsets();
+}
+
+PhysicalBoxStrut BoxBackgroundPaintContext::PaddingOutsets() const {
+  return positioning_box_->PaddingOutsets();
+}
+
+PhysicalBoxStrut BoxBackgroundPaintContext::VisualOverflowOutsets() const {
+  PhysicalRect border_box;
+  if (positioning_box_->IsBox()) {
+    border_box = To<LayoutBox>(positioning_box_)->PhysicalBorderBoxRect();
+  } else {
+    border_box = To<LayoutInline>(positioning_box_)->PhysicalLinesBoundingBox();
+  }
+  PhysicalRect visual_overflow =
+      positioning_box_->Layer()
+          ->LocalBoundingBoxIncludingSelfPaintingDescendants();
+  return PhysicalBoxStrut(visual_overflow.Y() - border_box.Y(),
+                          border_box.Right() - visual_overflow.Right(),
+                          border_box.Bottom() - visual_overflow.Bottom(),
+                          visual_overflow.X() - border_box.X());
+}
+
+PhysicalBoxStrut BoxBackgroundPaintContext::InnerBorderOutsets(
+    const PhysicalRect& dest_rect,
+    const PhysicalRect& positioning_area) const {
+  gfx::RectF inner_border_rect =
+      RoundedBorderGeometry::PixelSnappedRoundedInnerBorder(
+          positioning_box_->StyleRef(), positioning_area)
+          .Rect();
+  PhysicalBoxStrut outset;
+  // TODO(rendering-core) The LayoutUnit(float) constructor always rounds
+  // down. We should FromFloatFloor or FromFloatCeil to move toward the border.
+  outset.left = LayoutUnit(inner_border_rect.x()) - dest_rect.X();
+  outset.top = LayoutUnit(inner_border_rect.y()) - dest_rect.Y();
+  outset.right = dest_rect.Right() - LayoutUnit(inner_border_rect.right());
+  outset.bottom = dest_rect.Bottom() - LayoutUnit(inner_border_rect.bottom());
+  return outset;
+}
+
+SnappedAndUnsnappedOutsets BoxBackgroundPaintContext::ObscuredBorderOutsets(
+    const PhysicalRect& dest_rect,
+    const PhysicalRect& positioning_area) const {
+  const ComputedStyle& style = positioning_box_->StyleRef();
+  gfx::RectF inner_border_rect =
+      RoundedBorderGeometry::PixelSnappedRoundedInnerBorder(style,
+                                                            positioning_area)
+          .Rect();
+
+  BorderEdge edges[4];
+  style.GetBorderEdgeInfo(edges);
+  const PhysicalBoxStrut box_outsets = BorderOutsets();
+  SnappedAndUnsnappedOutsets adjust;
+  if (edges[static_cast<unsigned>(BoxSide::kTop)].ObscuresBackground()) {
+    adjust.snapped.top = LayoutUnit(inner_border_rect.y()) - dest_rect.Y();
+    adjust.unsnapped.top = box_outsets.top;
+  }
+  if (edges[static_cast<unsigned>(BoxSide::kRight)].ObscuresBackground()) {
+    adjust.snapped.right =
+        dest_rect.Right() - LayoutUnit(inner_border_rect.right());
+    adjust.unsnapped.right = box_outsets.right;
+  }
+  if (edges[static_cast<unsigned>(BoxSide::kBottom)].ObscuresBackground()) {
+    adjust.snapped.bottom =
+        dest_rect.Bottom() - LayoutUnit(inner_border_rect.bottom());
+    adjust.unsnapped.bottom = box_outsets.bottom;
+  }
+  if (edges[static_cast<unsigned>(BoxSide::kLeft)].ObscuresBackground()) {
+    adjust.snapped.left = LayoutUnit(inner_border_rect.x()) - dest_rect.X();
+    adjust.unsnapped.left = box_outsets.left;
+  }
+  return adjust;
+}
+
+PhysicalRect BoxBackgroundPaintContext::ComputePositioningArea(
+    const PaintInfo& paint_info,
+    const FillLayer& fill_layer,
+    const PhysicalRect& paint_rect) const {
+  if (ShouldUseFixedAttachment(fill_layer)) {
+    return FixedAttachmentPositioningArea(paint_info);
+  }
+  if (painting_view_ || cell_using_container_background_ ||
+      box_has_multiple_fragments_) {
+    return {PhysicalOffset(), positioning_size_override_};
+  }
+  return paint_rect;
+}
+
+bool BoxBackgroundPaintContext::DisallowBorderDerivedAdjustment() const {
+  return painting_view_ || painting_table_cell_ ||
+         box_has_multiple_fragments_ ||
+         positioning_box_->StyleRef().BorderImage().GetImage() ||
+         positioning_box_->StyleRef().BorderCollapse() ==
+             EBorderCollapse::kCollapse;
+}
+
+bool BoxBackgroundPaintContext::CanCompositeBackgroundAttachmentFixed() const {
+  return !painting_view_ && has_background_fixed_to_viewport_ &&
+         positioning_box_->CanCompositeBackgroundAttachmentFixed();
+}
+
+bool BoxBackgroundPaintContext::ShouldUseFixedAttachment(
+    const FillLayer& fill_layer) const {
+  // Only backgrounds fixed to viewport should be treated as fixed attachment.
+  // See comments in the private constructor.
+  return has_background_fixed_to_viewport_ &&
+         // Solid color background should use default attachment.
+         fill_layer.GetImage() &&
+         fill_layer.Attachment() == EFillAttachment::kFixed;
+}
+
+bool BoxBackgroundPaintContext::HasBackgroundFixedToViewport(
+    const LayoutBoxModelObject& object) {
+  if (!object.IsBackgroundAttachmentFixedObject()) {
+    return false;
+  }
+  // https://www.w3.org/TR/css-transforms-1/#transform-rendering
+  // Fixed backgrounds on the root element are affected by any transform
+  // specified for that element. For all other elements that are effected
+  // by a transform, a value of fixed for the background-attachment property
+  // is treated as if it had a value of scroll.
+  for (const PaintLayer* layer = object.EnclosingLayer();
+       layer && !layer->IsRootLayer(); layer = layer->Parent()) {
+    // Check LayoutObject::HasTransformRelatedProperty() first to exclude
+    // non-applicable transforms and will-change: transform.
+    LayoutObject& ancestor = layer->GetLayoutObject();
+    if (ancestor.HasTransformRelatedProperty() &&
+        (layer->Transform() ||
+         ancestor.StyleRef().HasWillChangeHintForAnyTransformProperty())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+PhysicalRect BoxBackgroundPaintContext::FixedAttachmentPositioningArea(
+    const PaintInfo& paint_info) const {
+  const ScrollableArea* layout_viewport =
+      box_->GetFrameView()->LayoutViewport();
+  DCHECK(layout_viewport);
+  PhysicalSize size(layout_viewport->VisibleContentRect().size());
+  if (CanCompositeBackgroundAttachmentFixed()) {
+    // The caller should have adjusted paint chunk properties to be in the
+    // viewport space.
+    return PhysicalRect(PhysicalOffset(), size);
+  }
+  gfx::PointF viewport_origin_in_local_space =
+      GeometryMapper::SourceToDestinationProjection(
+          box_->View()->FirstFragment().LocalBorderBoxProperties().Transform(),
+          paint_info.context.GetPaintController()
+              .CurrentPaintChunkProperties()
+              .Transform())
+          .MapPoint(gfx::PointF());
+  return PhysicalRect(
+      PhysicalOffset::FromPointFRound(viewport_origin_in_local_space),
+      PhysicalSize(layout_viewport->VisibleContentRect().size()));
+}
+
+const ComputedStyle& BoxBackgroundPaintContext::Style() const {
+  return box_->StyleRef();
+}
+
+const ImageResourceObserver& BoxBackgroundPaintContext::ImageClient() const {
+  return *(painting_view_ ? box_ : positioning_box_);
+}
+
+const ComputedStyle& BoxBackgroundPaintContext::ImageStyle(
+    const ComputedStyle& fragment_style) const {
+  if (painting_view_ || cell_using_container_background_) {
+    return positioning_box_->StyleRef();
+  }
+  return fragment_style;
+}
+
+PhysicalOffset BoxBackgroundPaintContext::OffsetInBackground(
+    const FillLayer& fill_layer) const {
+  if (ShouldUseFixedAttachment(fill_layer)) {
+    return PhysicalOffset();
+  }
+  return element_positioning_area_offset_;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_background_paint_context.h b/third_party/blink/renderer/core/paint/box_background_paint_context.h
new file mode 100644
index 0000000..531639c
--- /dev/null
+++ b/third_party/blink/renderer/core/paint/box_background_paint_context.h
@@ -0,0 +1,129 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_BACKGROUND_PAINT_CONTEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_BACKGROUND_PAINT_CONTEXT_H_
+
+#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
+#include "third_party/blink/renderer/core/paint/paint_phase.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+class ComputedStyle;
+class FillLayer;
+class ImageResourceObserver;
+class LayoutBox;
+class LayoutBoxModelObject;
+class LayoutTableCell;
+class LayoutView;
+class PhysicalBoxFragment;
+struct PaintInfo;
+
+struct SnappedAndUnsnappedOutsets {
+  PhysicalBoxStrut snapped;
+  PhysicalBoxStrut unsnapped;
+};
+
+// This class contains/describes the state needed to resolve a layer of a
+// 'background-image' or 'mask-image'.
+class BoxBackgroundPaintContext {
+  STACK_ALLOCATED();
+
+ public:
+  // Constructor for LayoutView where the coordinate space is different.
+  BoxBackgroundPaintContext(
+      const LayoutView&,
+      const PhysicalOffset& element_positioning_area_offset);
+
+  // Generic constructor for all other elements.
+  explicit BoxBackgroundPaintContext(const LayoutBoxModelObject&);
+
+  // Constructor for TablesNG table parts.
+  BoxBackgroundPaintContext(const LayoutTableCell& cell,
+                            PhysicalOffset cell_offset,
+                            const LayoutBox& table_part,
+                            PhysicalSize table_part_size);
+
+  explicit BoxBackgroundPaintContext(const PhysicalBoxFragment&);
+
+  // Compute the initial position area based on the geometry for the object
+  // this BackgroundPaintContext was created for.
+  PhysicalRect ComputePositioningArea(const PaintInfo& paint_info,
+                                      const FillLayer& fill_layer,
+                                      const PhysicalRect& paint_rect) const;
+
+  PhysicalBoxStrut BorderOutsets() const;
+  PhysicalBoxStrut PaddingOutsets() const;
+  PhysicalBoxStrut VisualOverflowOutsets() const;
+
+  PhysicalBoxStrut InnerBorderOutsets(
+      const PhysicalRect& dest_rect,
+      const PhysicalRect& positioning_area) const;
+  SnappedAndUnsnappedOutsets ObscuredBorderOutsets(
+      const PhysicalRect& dest_rect,
+      const PhysicalRect& positioning_area) const;
+
+  // The offset of the background image within the background positioning area.
+  PhysicalOffset OffsetInBackground(const FillLayer&) const;
+
+  bool DisallowBorderDerivedAdjustment() const;
+  bool CanCompositeBackgroundAttachmentFixed() const;
+  bool ShouldUseFixedAttachment(const FillLayer&) const;
+
+  // Whether the background needs to be positioned relative to a container
+  // element. Only used for tables.
+  bool CellUsingContainerBackground() const {
+    return cell_using_container_background_;
+  }
+
+  const ComputedStyle& Style() const;
+
+  const ImageResourceObserver& ImageClient() const;
+  const ComputedStyle& ImageStyle(const ComputedStyle& fragment_style) const;
+
+  static bool HasBackgroundFixedToViewport(const LayoutBoxModelObject&);
+
+ private:
+  BoxBackgroundPaintContext(const LayoutBoxModelObject* box,
+                            const LayoutBoxModelObject* positioning_box);
+
+  PhysicalRect FixedAttachmentPositioningArea(const PaintInfo&) const;
+
+  // In most cases this is the same as positioning_box_. They are different
+  // when we are painting:
+  // 1. the view background (box_ is the LayoutView, and positioning_box_ is
+  //    the LayoutView's RootBox()), or
+  // 2. a table cell using its row/column's background (box_ is the table
+  //    cell, and positioning_box_ is the row/column).
+  // When they are different:
+  // - ImageClient() uses box_ if painting view, otherwise positioning_box_;
+  // - ImageStyle() uses positioning_box_;
+  // - FillLayers come from box_ if painting view, otherwise positioning_box_.
+  const LayoutBoxModelObject* const box_;
+
+  // The positioning box is the source of geometric information for positioning
+  // and sizing the background. It also provides the information listed in the
+  // comment for box_.
+  const LayoutBoxModelObject* const positioning_box_;
+
+  // When painting table cells or the view, the positioning area
+  // differs from the requested paint rect.
+  PhysicalSize positioning_size_override_;
+
+  // The background image offset from within the background positioning area
+  // for non-fixed background attachment. Used for table cells and the view,
+  // and also when an element is block-fragmented.
+  PhysicalOffset element_positioning_area_offset_;
+
+  bool has_background_fixed_to_viewport_ = false;
+  bool painting_view_ = false;
+  bool painting_table_cell_ = false;
+  bool cell_using_container_background_ = false;
+  bool box_has_multiple_fragments_ = false;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_BACKGROUND_PAINT_CONTEXT_H_
diff --git a/third_party/blink/renderer/core/paint/box_fragment_painter.cc b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
index 86ff75e5..597bf74 100644
--- a/third_party/blink/renderer/core/paint/box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
@@ -1096,7 +1096,7 @@
   }
 
   if (box.CanCompositeBackgroundAttachmentFixed() &&
-      BackgroundImageGeometry::HasBackgroundFixedToViewport(box)) {
+      BoxBackgroundPaintContext::HasBackgroundFixedToViewport(box)) {
     PaintCompositeBackgroundAttachmentFixed(paint_info, background_client,
                                             box_decoration_data);
     if (box_decoration_data.ShouldPaintBorder()) {
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index 4f34fe3..56b6bff 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -813,7 +813,7 @@
   DCHECK(info.should_paint_color || info.should_paint_image);
 
   // Painting a background image from an ancestor onto a cell is a complex case.
-  if (geometry.CellUsingContainerBackground()) {
+  if (geometry.GetContext().CellUsingContainerBackground()) {
     return false;
   }
   // Complex cases not handled on the fast path.
@@ -1183,7 +1183,7 @@
       composite_op = SkBlendMode::kSrcOver;
     }
 
-    const ComputedStyle& image_style = geometry.ImageStyle(style_);
+    const ComputedStyle& image_style = geometry.GetContext().ImageStyle(style_);
 
     // If the "image" referenced by the FillLayer is an SVG <mask> reference
     // (and this is a layer for a mask), then repeat, position, clip, origin and
@@ -1191,8 +1191,9 @@
     if (bg_layer.GetType() == EFillLayerType::kMask) {
       if (const auto* mask_source =
               ToMaskSourceIfSVGMask(*fill_layer_info.image)) {
-        const PhysicalRect positioning_area = geometry.ComputePositioningArea(
-            paint_info, bg_layer, scrolled_paint_rect);
+        const PhysicalRect positioning_area =
+            geometry.GetContext().ComputePositioningArea(paint_info, bg_layer,
+                                                         scrolled_paint_rect);
         const gfx::RectF reference_box(gfx::SizeF(positioning_area.size));
         const float zoom = image_style.EffectiveZoom();
 
@@ -1201,15 +1202,18 @@
         context.Translate(positioning_area.X().ToFloat(),
                           positioning_area.Y().ToFloat());
         SVGMaskPainter::PaintSVGMaskLayer(
-            context, *mask_source, geometry.ImageClient(), reference_box, zoom,
-            composite_op, bg_layer.MaskMode() == EFillMaskMode::kMatchSource);
+            context, *mask_source, geometry.GetContext().ImageClient(),
+            reference_box, zoom, composite_op,
+            bg_layer.MaskMode() == EFillMaskMode::kMatchSource);
         return;
       }
     }
+    DCHECK_GE(document_.Lifecycle().GetState(),
+              DocumentLifecycle::kPrePaintClean);
     geometry.Calculate(paint_info, bg_layer, scrolled_paint_rect);
 
-    image = fill_layer_info.image->GetImage(geometry.ImageClient(), document_,
-                                            image_style,
+    image = fill_layer_info.image->GetImage(geometry.GetContext().ImageClient(),
+                                            document_, image_style,
                                             gfx::SizeF(geometry.TileSize()));
 
     image_rendering_settings_context.emplace(context,
@@ -1235,12 +1239,12 @@
 
   absl::optional<RoundedInnerRectClipper> clip_to_border;
   if (fill_layer_info.is_rounded_fill) {
-    DCHECK(!geometry.CanCompositeBackgroundAttachmentFixed());
+    DCHECK(!geometry.GetContext().CanCompositeBackgroundAttachmentFixed());
     clip_to_border.emplace(context, rect, border_rect);
   }
 
   if (bg_layer.Clip() == EFillBox::kText) {
-    DCHECK(!geometry.CanCompositeBackgroundAttachmentFixed());
+    DCHECK(!geometry.GetContext().CanCompositeBackgroundAttachmentFixed());
     PaintFillLayerTextFillBox(paint_info, fill_layer_info, image.get(),
                               composite_op, geometry, rect, scrolled_paint_rect,
                               object_has_multiple_boxes);
@@ -1249,7 +1253,7 @@
 
   // We use BackgroundClip paint property when CanFastScrollFixedAttachment().
   absl::optional<GraphicsContextStateSaver> background_clip_state_saver;
-  if (!geometry.CanCompositeBackgroundAttachmentFixed()) {
+  if (!geometry.GetContext().CanCompositeBackgroundAttachmentFixed()) {
     switch (bg_layer.Clip()) {
       case EFillBox::kFillBox:
       // Spec: For elements with associated CSS layout box, the used values for
diff --git a/third_party/blink/renderer/core/paint/build.gni b/third_party/blink/renderer/core/paint/build.gni
index f8ee176f..edf69650 100644
--- a/third_party/blink/renderer/core/paint/build.gni
+++ b/third_party/blink/renderer/core/paint/build.gni
@@ -11,6 +11,8 @@
   "block_flow_paint_invalidator.h",
   "block_paint_invalidator.cc",
   "block_paint_invalidator.h",
+  "box_background_paint_context.cc",
+  "box_background_paint_context.h",
   "box_border_painter.cc",
   "box_border_painter.h",
   "box_decoration_data.cc",
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index ef1a788..5e523e8 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -3002,6 +3002,10 @@
   return AnnotatedRegions(document, false, exception_state);
 }
 
+void Internals::SetSupportsAppRegion(bool supports_app_region) {
+  GetFrame()->SetSupportsAppRegion(supports_app_region);
+}
+
 DOMRectList* Internals::AnnotatedRegions(Document* document,
                                          bool draggable,
                                          ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index efd180ab..1822439 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -435,6 +435,7 @@
 
   DOMRectList* draggableRegions(Document*, ExceptionState&);
   DOMRectList* nonDraggableRegions(Document*, ExceptionState&);
+  void SetSupportsAppRegion(bool supports_app_region);
 
   DOMArrayBuffer* serializeObject(v8::Isolate* isolate,
                                   const ScriptValue&,
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 9feda14..69c1193 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -261,6 +261,11 @@
     [RaisesException] DOMRectList draggableRegions(Document document);
     [RaisesException] DOMRectList nonDraggableRegions(Document document);
 
+    // Overrides default behavior to support the app-region CSS property.
+    // Setting to true enables collection of draggable/non-draggable
+    // app regions.
+    void SetSupportsAppRegion(boolean supports_app_regions);
+
     // Returns a string with information about the mouse cursor used at the specified client location.
     DOMString getCurrentCursorInfo();
 
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 5130d312..dd178ac 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -1008,6 +1008,7 @@
     "//third_party/blink/renderer/core:testing",
     "//third_party/blink/renderer/core:unit_test_support",
     "//third_party/blink/renderer/modules/breakout_box:unit_tests",
+    "//third_party/blink/renderer/modules/file_system_access:unit_tests",
     "//third_party/blink/renderer/modules/gamepad:unit_tests",
     "//third_party/blink/renderer/modules/hid:unit_tests",
     "//third_party/blink/renderer/modules/idle:unit_tests",
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc
index 78d2a46..d5d3823b 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_mojo.cc
@@ -2280,6 +2280,188 @@
   }
 }
 
+struct InstanceNormalizationTester {
+  OperandInfoBlink input;
+  struct InstanceNormalizationOptions {
+    absl::optional<OperandInfoBlink> scale;
+    absl::optional<OperandInfoBlink> bias;
+    absl::optional<float> epsilon;
+    absl::optional<blink::V8MLInputOperandLayout::Enum> layout;
+  };
+  struct InstanceNormalizationAttributes {
+    absl::optional<OperandInfoMojo> scale;
+    absl::optional<OperandInfoMojo> bias;
+    float epsilon = 1e-5;
+    blink_mojom::InputOperandLayout layout =
+        blink_mojom::InputOperandLayout::kChannelsFirst;
+  };
+  InstanceNormalizationOptions options;
+  OperandInfoMojo expected_operand;
+  InstanceNormalizationAttributes expected_attributes;
+
+  void Test(MLGraphTestMojo& helper,
+            V8TestingScope& scope,
+            MLGraphBuilder* builder) {
+    // Build the graph.
+    auto* input_operand =
+        BuildInput(builder, "input", input.dimensions, input.data_type,
+                   scope.GetExceptionState());
+    MLInstanceNormalizationOptions* instance_normalization_options =
+        MLInstanceNormalizationOptions::Create();
+    if (options.scale) {
+      instance_normalization_options->setScale(
+          BuildInput(builder, "scale", options.scale->dimensions,
+                     options.scale->data_type, scope.GetExceptionState()));
+    }
+    if (options.bias) {
+      instance_normalization_options->setBias(
+          BuildInput(builder, "bias", options.bias->dimensions,
+                     options.bias->data_type, scope.GetExceptionState()));
+    }
+    if (options.epsilon) {
+      instance_normalization_options->setEpsilon(options.epsilon.value());
+    }
+    if (options.layout) {
+      instance_normalization_options->setLayout(options.layout.value());
+    }
+
+    auto* output_operand = builder->instanceNormalization(
+        input_operand, instance_normalization_options,
+        scope.GetExceptionState());
+    auto [graph, build_exception] =
+        helper.BuildGraph(scope, builder, {{"output", output_operand}});
+    ASSERT_NE(graph, nullptr);
+
+    auto graph_info = helper.GetGraphInfo();
+    // Verify the graph information of mojo are as expected.
+    ASSERT_EQ(graph_info->operations.size(), 1u);
+    auto& operation = graph_info->operations[0];
+    EXPECT_EQ(operation->is_instance_normalization(), true);
+    auto& instance_normalization = operation->get_instance_normalization();
+    EXPECT_EQ(instance_normalization->layout, expected_attributes.layout);
+    EXPECT_FLOAT_EQ(instance_normalization->epsilon,
+                    expected_attributes.epsilon);
+    if (options.scale) {
+      auto scale_operand_iter = graph_info->id_to_operand_map.find(
+          instance_normalization->scale_operand_id.value());
+      ASSERT_TRUE(scale_operand_iter != graph_info->id_to_operand_map.end());
+      EXPECT_EQ(scale_operand_iter->value->data_type,
+                expected_attributes.scale->data_type);
+      EXPECT_EQ(scale_operand_iter->value->dimensions,
+                expected_attributes.scale->dimensions);
+    }
+    if (options.bias) {
+      auto bias_operand_iter = graph_info->id_to_operand_map.find(
+          instance_normalization->bias_operand_id.value());
+      ASSERT_TRUE(bias_operand_iter != graph_info->id_to_operand_map.end());
+      EXPECT_EQ(bias_operand_iter->value->data_type,
+                expected_attributes.bias->data_type);
+      EXPECT_EQ(bias_operand_iter->value->dimensions,
+                expected_attributes.bias->dimensions);
+    }
+
+    EXPECT_EQ(graph_info->output_operands.size(), 1u);
+    auto output_operand_id = graph_info->output_operands[0];
+    auto output_operand_iter =
+        graph_info->id_to_operand_map.find(output_operand_id);
+    ASSERT_TRUE(output_operand_iter != graph_info->id_to_operand_map.end());
+    EXPECT_EQ(output_operand_iter->value->data_type,
+              expected_operand.data_type);
+    EXPECT_EQ(output_operand_iter->value->dimensions,
+              expected_operand.dimensions);
+  }
+};
+
+TEST_P(MLGraphTestMojo, InstanceNormalizationTest) {
+  V8TestingScope scope;
+  // Bind fake WebNN Context in the service for testing.
+  ScopedWebNNServiceBinder scoped_setup_binder(*this, scope);
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      webnn::features::kWebMachineLearningNeuralNetwork);
+  auto* options = MLContextOptions::Create();
+  // Create WebNN Context with GPU device type.
+  options->setDeviceType(V8MLDeviceType::Enum::kGpu);
+  auto* builder = CreateGraphBuilder(scope, options);
+  ASSERT_NE(builder, nullptr);
+  {
+    // Test instanceNormalization with default options.
+    InstanceNormalizationTester{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 3, 5, 5}},
+        .expected_operand = {.data_type =
+                                 blink_mojom::Operand::DataType::kFloat32,
+                             .dimensions = {1, 3, 5, 5}},
+        .expected_attributes =
+            {.scale = absl::nullopt,
+             .bias = absl::nullopt,
+             .epsilon = 1e-5,
+             .layout = blink_mojom::InputOperandLayout::kChannelsFirst}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test instanceNormalization with layout = nhwc.
+    InstanceNormalizationTester{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 3, 4, 5}},
+        .options = {.layout = V8MLInputOperandLayout::Enum::kNhwc},
+        .expected_operand = {.data_type =
+                                 blink_mojom::Operand::DataType::kFloat32,
+                             .dimensions = {1, 3, 4, 5}},
+        .expected_attributes =
+            {.scale = absl::nullopt,
+             .bias = absl::nullopt,
+             .epsilon = 1e-5,
+             .layout = blink_mojom::InputOperandLayout::kChannelsLast}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test instanceNormalization with epsilon = 0.01.
+    InstanceNormalizationTester{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 3, 4, 5}},
+        .options = {.epsilon = 0.01},
+        .expected_operand = {.data_type =
+                                 blink_mojom::Operand::DataType::kFloat32,
+                             .dimensions = {1, 3, 4, 5}},
+        .expected_attributes =
+            {.scale = absl::nullopt,
+             .bias = absl::nullopt,
+             .epsilon = 0.01,
+             .layout = blink_mojom::InputOperandLayout::kChannelsFirst}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test instanceNormalization with scale and bias.
+    InstanceNormalizationTester{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 3, 5, 5}},
+        .options = {.scale =
+                        OperandInfoBlink{
+                            .data_type = V8MLOperandDataType::Enum::kFloat32,
+                            .dimensions = {3}},
+                    .bias =
+                        OperandInfoBlink{
+                            .data_type = V8MLOperandDataType::Enum::kFloat32,
+                            .dimensions = {3}}},
+        .expected_operand = {.data_type =
+                                 blink_mojom::Operand::DataType::kFloat32,
+                             .dimensions = {1, 3, 5, 5}},
+        .expected_attributes =
+            {.scale =
+                 OperandInfoMojo{
+                     .data_type = blink_mojom::Operand::DataType::kFloat32,
+                     .dimensions = {3}},
+             .bias =
+                 OperandInfoMojo{
+                     .data_type = blink_mojom::Operand::DataType::kFloat32,
+                     .dimensions = {3}},
+             .epsilon = 1e-5,
+             .layout = blink_mojom::InputOperandLayout::kChannelsFirst}}
+        .Test(*this, scope, builder);
+  }
+}
+
 struct LayerNormalizationTester {
   OperandInfoBlink input;
   struct LayerNormalizationOptions {
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 a489d10..2b839d8 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
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_elu_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gather_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gemm_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_instance_normalization_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_layer_normalization_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_leaky_relu_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pad_options.h"
@@ -664,6 +665,35 @@
       std::move(layer_normalization_mojo));
 }
 
+base::expected<OperationPtr, String> CreateInstanceNormalizationOperation(
+    const OperandToIdMap& operand_to_id_map,
+    const MLOperator* instance_normalization) {
+  auto instance_normalization_mojo =
+      webnn::mojom::blink::InstanceNormalization::New();
+  instance_normalization_mojo->input_operand_id =
+      GetOperatorInputId(instance_normalization, operand_to_id_map, 0);
+  instance_normalization_mojo->output_operand_id =
+      GetOperatorOutputId(instance_normalization, operand_to_id_map);
+
+  const auto* options = static_cast<const MLInstanceNormalizationOptions*>(
+      instance_normalization->Options());
+  CHECK(options);
+  if (options->hasScale()) {
+    instance_normalization_mojo->scale_operand_id =
+        operand_to_id_map.at(options->scale());
+  }
+  if (options->hasBias()) {
+    instance_normalization_mojo->bias_operand_id =
+        operand_to_id_map.at(options->bias());
+  }
+  instance_normalization_mojo->layout =
+      BlinkInputOperandLayoutToMojo(options->layout().AsEnum());
+  instance_normalization_mojo->epsilon = options->epsilon();
+
+  return webnn::mojom::blink::Operation::NewInstanceNormalization(
+      std::move(instance_normalization_mojo));
+}
+
 OperationPtr CreateMatmulOperation(const OperandToIdMap& operand_to_id_map,
                                    const MLOperator* matmul) {
   auto matmul_mojo = blink_mojom::Matmul::New();
@@ -1081,6 +1111,8 @@
       return CreateGatherOperation(operand_to_id_map, op);
     case MLOperator::OperatorKind::kGemm:
       return CreateGemmOperation(operand_to_id_map, op);
+    case MLOperator::OperatorKind::kInstanceNormalization:
+      return CreateInstanceNormalizationOperation(operand_to_id_map, op);
     case MLOperator::OperatorKind::kLayerNormalization:
       return CreateLayerNormalizationOperation(operand_to_id_map, op);
     case MLOperator::OperatorKind::kLeakyRelu:
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.cc
index 5f1f954..6a0f986 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame.cc
@@ -136,8 +136,8 @@
   }
 
   if (RuntimeEnabledFeatures::RTCEncodedVideoFrameAdditionalMetadataEnabled()) {
-    if (delegate_->CaptureTimeIdentifier()) {
-      metadata->setCaptureTimestamp(delegate_->CaptureTimeIdentifier()->us());
+    if (delegate_->PresentationTimestamp()) {
+      metadata->setTimestamp(delegate_->PresentationTimestamp()->us());
     }
   }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.cc
index a668b73..9fae5e3 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.cc
@@ -46,7 +46,7 @@
 }
 
 absl::optional<webrtc::Timestamp>
-RTCEncodedVideoFrameDelegate::CaptureTimeIdentifier() const {
+RTCEncodedVideoFrameDelegate::PresentationTimestamp() const {
   base::AutoLock lock(lock_);
   return webrtc_frame_ ? webrtc_frame_->GetCaptureTimeIdentifier()
                        : absl::nullopt;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h
index 09617c4..544b7f4 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_delegate.h
@@ -34,7 +34,7 @@
   String Type() const;
   uint32_t RtpTimestamp() const;
   void SetRtpTimestamp(uint32_t timestamp, ExceptionState& exception_state);
-  absl::optional<webrtc::Timestamp> CaptureTimeIdentifier() const;
+  absl::optional<webrtc::Timestamp> PresentationTimestamp() const;
   DOMArrayBuffer* CreateDataBuffer() const;
   void SetData(const DOMArrayBuffer* data);
   absl::optional<uint8_t> PayloadType() const;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_metadata.idl b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_metadata.idl
index 3a4bb395..746a9d4 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_metadata.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_frame_metadata.idl
@@ -34,7 +34,7 @@
     octet payloadType;
     DOMString mimeType;
     [RuntimeEnabled=RTCEncodedVideoFrameAdditionalMetadata]
-    long long captureTimestamp;     // microseconds.
+    long long timestamp;     // Presentation timestamp, microseconds.
     [RuntimeEnabled=RTCEncodedFrameSetMetadata]
-    unsigned long rtpTimestamp;     // microseconds.
+    unsigned long rtpTimestamp;
 };
diff --git a/third_party/blink/renderer/modules/printing/web_printer_attributes.idl b/third_party/blink/renderer/modules/printing/web_printer_attributes.idl
index 5b62493..b800d35 100644
--- a/third_party/blink/renderer/modules/printing/web_printer_attributes.idl
+++ b/third_party/blink/renderer/modules/printing/web_printer_attributes.idl
@@ -21,6 +21,7 @@
   unsigned long copies;
 
   WebPrintingMultipleDocumentHandling multipleDocumentHandling;
+  WebPrintColorMode printColorMode;
   WebPrintQuality printQuality;
   WebPrintingSides sides;
 };
@@ -37,6 +38,9 @@
   WebPrintingMultipleDocumentHandling multipleDocumentHandlingDefault;
   sequence<WebPrintingMultipleDocumentHandling> multipleDocumentHandlingSupported;
 
+  WebPrintColorMode printColorModeDefault;
+  sequence<WebPrintColorMode> printColorModeSupported;
+
   WebPrintQuality printQualityDefault;
   sequence<WebPrintQuality> printQualitySupported;
 
diff --git a/third_party/blink/renderer/modules/printing/web_printing_enums.idl b/third_party/blink/renderer/modules/printing/web_printing_enums.idl
index 2cf3097..2378662 100644
--- a/third_party/blink/renderer/modules/printing/web_printing_enums.idl
+++ b/third_party/blink/renderer/modules/printing/web_printing_enums.idl
@@ -34,3 +34,8 @@
   "normal",
   "high",
 };
+
+enum WebPrintColorMode {
+  "color",
+  "monochrome",
+};
diff --git a/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc b/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc
index faca37c3..e1da858 100644
--- a/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc
+++ b/third_party/blink/renderer/modules/printing/web_printing_type_converters.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/printing/web_printing_type_converters.h"
 
 #include "third_party/blink/public/mojom/printing/web_printing.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_web_print_color_mode.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_web_print_job_template_attributes.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_web_printer_attributes.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_web_printing_mime_media_type.h"
@@ -25,6 +26,10 @@
 // state:
 using V8JobState = blink::V8WebPrintJobState;
 using MojomJobState = blink::mojom::blink::WebPrintJobState;
+
+// print-color-mode:
+using V8ColorMode = blink::V8WebPrintColorMode;
+using MojomColorMode = blink::mojom::blink::WebPrintColorMode;
 }  // namespace
 
 namespace mojo {
@@ -89,6 +94,30 @@
   }
 };
 
+template <>
+struct TypeConverter<V8ColorMode, MojomColorMode> {
+  static V8ColorMode Convert(const MojomColorMode& color_mode) {
+    switch (color_mode) {
+      case MojomColorMode::kColor:
+        return V8ColorMode(V8ColorMode::Enum::kColor);
+      case MojomColorMode::kMonochrome:
+        return V8ColorMode(V8ColorMode::Enum::kMonochrome);
+    }
+  }
+};
+
+template <>
+struct TypeConverter<MojomColorMode, V8ColorMode> {
+  static MojomColorMode Convert(const V8ColorMode& color_mode) {
+    switch (color_mode.AsEnum()) {
+      case V8ColorMode::Enum::kColor:
+        return MojomColorMode::kColor;
+      case V8ColorMode::Enum::kMonochrome:
+        return MojomColorMode::kMonochrome;
+    }
+  }
+};
+
 }  // namespace mojo
 
 namespace blink {
@@ -124,14 +153,14 @@
           new_attributes.multiple_document_handling_supported));
 }
 
-void ProcessMultipleDocumentHandling(
-    const blink::WebPrintJobTemplateAttributes& pjt_attributes,
-    mojom::blink::WebPrintJobTemplateAttributes* attributes) {
-  if (pjt_attributes.hasMultipleDocumentHandling()) {
-    attributes->multiple_document_handling =
-        mojo::ConvertTo<MojomMultipleDocumentHandling>(
-            pjt_attributes.multipleDocumentHandling());
-  }
+void ProcessPrintColorMode(
+    const mojom::blink::WebPrinterAttributes& new_attributes,
+    WebPrinterAttributes* current_attributes) {
+  current_attributes->setPrintColorModeDefault(
+      mojo::ConvertTo<V8ColorMode>(new_attributes.print_color_mode_default));
+  current_attributes->setPrintColorModeSupported(
+      mojo::ConvertTo<Vector<V8ColorMode>>(
+          new_attributes.print_color_mode_supported));
 }
 
 void ProcessSides(const mojom::blink::WebPrinterAttributes& new_attributes,
@@ -146,13 +175,6 @@
   }
 }
 
-void ProcessSides(const blink::WebPrintJobTemplateAttributes& pjt_attributes,
-                  mojom::blink::WebPrintJobTemplateAttributes* attributes) {
-  if (pjt_attributes.hasSides()) {
-    attributes->sides = mojo::ConvertTo<MojomSides>(pjt_attributes.sides());
-  }
-}
-
 }  // namespace
 
 }  // namespace blink
@@ -169,6 +191,7 @@
   blink::ProcessCopies(*printer_attributes, attributes);
   blink::ProcessDocumentFormat(*printer_attributes, attributes);
   blink::ProcessMultipleDocumentHandling(*printer_attributes, attributes);
+  blink::ProcessPrintColorMode(*printer_attributes, attributes);
   blink::ProcessSides(*printer_attributes, attributes);
 
   return attributes;
@@ -181,8 +204,18 @@
   auto attributes = blink::mojom::blink::WebPrintJobTemplateAttributes::New();
 
   attributes->copies = pjt_attributes->getCopiesOr(1);
-  blink::ProcessMultipleDocumentHandling(*pjt_attributes, attributes.get());
-  blink::ProcessSides(*pjt_attributes, attributes.get());
+  if (pjt_attributes->hasMultipleDocumentHandling()) {
+    attributes->multiple_document_handling =
+        mojo::ConvertTo<MojomMultipleDocumentHandling>(
+            pjt_attributes->multipleDocumentHandling());
+  }
+  if (pjt_attributes->hasPrintColorMode()) {
+    attributes->print_color_mode =
+        mojo::ConvertTo<MojomColorMode>(pjt_attributes->printColorMode());
+  }
+  if (pjt_attributes->hasSides()) {
+    attributes->sides = mojo::ConvertTo<MojomSides>(pjt_attributes->sides());
+  }
 
   return attributes;
 }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
index 374229e..5b911b44 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
@@ -52,9 +52,6 @@
   return false;
 }
 
-// TODO(crbug.com/1371756): Make URLPattern has a method to construct the
-// SafeURLPattern and remove the conversion from here.
-// The method should take a exception_state to raise on regex usage.
 absl::optional<SafeUrlPattern> RouterUrlPatternConditionToBlink(
     v8::Isolate* isolate,
     const V8URLPatternCompatible* url_pattern_compatible,
@@ -82,9 +79,6 @@
     CHECK(exception_state.HadException());
     return absl::nullopt;
   }
-  // TODO(crbug.com/1371756): support URLPatternOptions.
-  // Currently, URLPatternOptions are not included in URLPatternInit,
-  // and we do not pass the option to the browser side.
   return safe_url_pattern;
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 53c8e24a..6422e08 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -480,11 +480,13 @@
     shared_image_usage_flags = shared_image_usage_flags |
                                gpu::SHARED_IMAGE_USAGE_RASTER |
                                gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION |
-                               gpu::SHARED_IMAGE_USAGE_GLES2 |
+                               gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                               gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
                                gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
   } else {
     shared_image_usage_flags = shared_image_usage_flags |
-                               gpu::SHARED_IMAGE_USAGE_GLES2 |
+                               gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                               gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
                                gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
   }
 
@@ -1214,7 +1216,8 @@
     return;
 
   uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                   gpu::SHARED_IMAGE_USAGE_GLES2 |
+                   gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                   gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
                    gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
                    gpu::SHARED_IMAGE_USAGE_SCANOUT;
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 05a83dd9b..cbc474a 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -1902,7 +1902,8 @@
   GLenum texture_target = GL_TEXTURE_2D;
   GLuint texture_id = 0;
   std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
-  uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2 |
+  uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                   gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
                    gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
                    gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
   if (initial_gpu_ == gl::GpuPreference::kHighPerformance)
@@ -1978,13 +1979,21 @@
                 color_buffer_format_),
             buffer_usage, gpu::kNullSurfaceHandle, nullptr);
         if (gpu_memory_buffer) {
-#if BUILDFLAG(IS_MAC)
-          gpu_memory_buffer->SetColorSpace(color_space_);
-#endif
           auto client_shared_image = sii->CreateSharedImage(
               color_buffer_format_, size, color_space_, origin,
               back_buffer_alpha_type, usage | additional_usage_flags,
               "WebGLDrawingBuffer", gpu_memory_buffer->CloneHandle());
+#if BUILDFLAG(IS_MAC)
+          // Ensure that the backing IOSurface has its color space set to be the
+          // same as that of the just-created SharedImage (the former is used by
+          // CoreAnimation, while the latter is used by viz).
+          // TODO(crbug.com/924198): Explore moving to a CreateSharedImage()
+          // codepath that sets the color space of the IOSurface on the service
+          // side and eliminating the usage of GMB here altogether. Will require
+          // resolving issues with low-latency canvas tests that caused prior
+          // attempts to be reverted (crbug.com/1346737).
+          gpu_memory_buffer->SetColorSpace(color_space_);
+#endif
           CHECK(client_shared_image);
           back_buffer_mailbox = client_shared_image->mailbox();
 #if BUILDFLAG(IS_MAC)
diff --git a/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
index bac4c88..4089d434 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/xr_webgl_drawing_buffer.cc
@@ -492,7 +492,8 @@
       drawing_buffer_->client());
   auto* sii = drawing_buffer_->ContextProvider()->SharedImageInterface();
   uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                   gpu::SHARED_IMAGE_USAGE_GLES2 |
+                   gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                   gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
                    gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
   auto client_shared_image = sii->CreateSharedImage(
       alpha_ ? viz::SinglePlaneFormat::kRGBA_8888
diff --git a/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc b/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc
index 488dcbf8..3414f9d 100644
--- a/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc
+++ b/third_party/blink/renderer/platform/graphics/image_to_buffer_copier.cc
@@ -38,8 +38,10 @@
     dest_shared_image_ = sii_->CreateSharedImage(
         viz::SinglePlaneFormat::kRGBA_8888, size, gfx::ColorSpace(),
         kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
-        gpu::SHARED_IMAGE_USAGE_GLES2, "ImageToBufferCopier",
-        gpu::kNullSurfaceHandle, gfx::BufferUsage::SCANOUT);
+        gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+            gpu::SHARED_IMAGE_USAGE_GLES2_WRITE,
+        "ImageToBufferCopier", gpu::kNullSurfaceHandle,
+        gfx::BufferUsage::SCANOUT);
     CHECK(dest_shared_image_);
     gl_->WaitSyncTokenCHROMIUM(sii_->GenUnverifiedSyncToken().GetConstData());
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index ae5be8dd..d961671 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1075,7 +1075,7 @@
       TRACE_ID_WITH_SCOPE("BlinkResourceID", TRACE_ID_LOCAL(identifier)), "url",
       resource_request.Url());
   base::ScopedClosureRunner timer(base::BindOnce(
-      [](base::TimeTicks start, bool is_data) {
+      [](base::TimeTicks start, bool is_data, bool is_preload_request) {
         base::TimeDelta elapsed = base::TimeTicks::Now() - start;
         base::UmaHistogramMicrosecondsTimes("Blink.Fetch.RequestResourceTime2",
                                             elapsed);
@@ -1083,8 +1083,13 @@
           base::UmaHistogramMicrosecondsTimes(
               "Blink.Fetch.RequestResourceTime2.Data", elapsed);
         }
+        if (is_preload_request) {
+          base::UmaHistogramMicrosecondsTimes(
+              "Blink.Fetch.RequestResourceTime2.Preload", elapsed);
+        }
       },
-      base::TimeTicks::Now(), params.Url().ProtocolIsData()));
+      base::TimeTicks::Now(), params.Url().ProtocolIsData(),
+      params.IsSpeculativePreload() || params.IsLinkPreload()));
   TRACE_EVENT1("blink,blink.resource", "ResourceFetcher::requestResource",
                "url", params.Url().ElidedString().Utf8());
 
diff --git a/third_party/blink/renderer/platform/media/BUILD.gn b/third_party/blink/renderer/platform/media/BUILD.gn
index 7062313..5204e7c 100644
--- a/third_party/blink/renderer/platform/media/BUILD.gn
+++ b/third_party/blink/renderer/platform/media/BUILD.gn
@@ -104,8 +104,8 @@
 
   if (enable_hls_demuxer) {
     sources += [
-      "hls_data_source_provider_impl.cc",
-      "hls_data_source_provider_impl.h",
+      "multi_buffer_data_source_factory.cc",
+      "multi_buffer_data_source_factory.h",
     ]
   }
 }
@@ -149,10 +149,6 @@
     "//third_party/blink/renderer/platform:test_support",
   ]
 
-  if (enable_hls_demuxer) {
-    sources += [ "hls_data_source_provider_impl_unittest.cc" ]
-  }
-
   if (media_use_ffmpeg || !is_android) {
     sources += [
       "buffered_data_source_host_impl_unittest.cc",
diff --git a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h b/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h
deleted file mode 100644
index 9412c1b..0000000
--- a/third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIA_HLS_DATA_SOURCE_PROVIDER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIA_HLS_DATA_SOURCE_PROVIDER_IMPL_H_
-
-#include <deque>
-#include <memory>
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/time/tick_clock.h"
-#include "base/types/pass_key.h"
-#include "media/base/data_source.h"
-#include "media/base/media_log.h"
-#include "media/filters/hls_data_source_provider.h"
-#include "third_party/blink/public/platform/media/url_index.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace blink {
-
-class BufferedDataSourceHostImpl;
-
-class PLATFORM_EXPORT HlsDataSourceProviderImpl
-    : public media::HlsDataSourceProvider {
- public:
-  // An instance of DataSourceFactory allows separation of DataSource creation
-  // and DataSourceStream buffer management for easier testing.
-  class DataSourceFactory {
-   public:
-    using DataSourceCb =
-        base::OnceCallback<void(std::unique_ptr<media::DataSource>)>;
-    virtual ~DataSourceFactory() = 0;
-    virtual void CreateDataSource(GURL uri, DataSourceCb cb) = 0;
-  };
-
-  ~HlsDataSourceProviderImpl() override;
-  explicit HlsDataSourceProviderImpl(
-      std::unique_ptr<DataSourceFactory> factory);
-
-  // media::HlsDataSourceProvider implementation
-  void ReadFromUrl(GURL uri,
-                   absl::optional<media::hls::types::ByteRange> range,
-                   ReadCb callback) override;
-  void ReadFromExistingStream(
-      std::unique_ptr<media::HlsDataSourceStream> stream,
-      ReadCb callback) override;
-  void AbortPendingReads(base::OnceClosure cb) override;
-
- private:
-  void OnDataSourceReady(absl::optional<media::hls::types::ByteRange> range,
-                         ReadCb callback,
-                         std::unique_ptr<media::DataSource> data_source);
-  void OnStreamReleased(media::HlsDataSourceStream::StreamId stream_id);
-  void DataSourceInitialized(media::HlsDataSourceStream::StreamId stream_id,
-                             absl::optional<media::hls::types::ByteRange> range,
-                             ReadCb callback,
-                             bool success);
-
-  std::unique_ptr<DataSourceFactory> data_source_factory_;
-
-  media::HlsDataSourceStream::StreamId::Generator stream_id_generator_;
-
-  base::flat_map<media::HlsDataSourceStream::StreamId,
-                 std::unique_ptr<media::DataSource>>
-      data_source_map_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<HlsDataSourceProviderImpl> weak_factory_{this};
-};
-
-class PLATFORM_EXPORT MultiBufferDataSourceFactory
-    : public HlsDataSourceProviderImpl::DataSourceFactory {
- public:
-  using UrlDataCb = base::RepeatingCallback<
-      void(const GURL& url, base::OnceCallback<void(scoped_refptr<UrlData>)>)>;
-
-  ~MultiBufferDataSourceFactory() override;
-  MultiBufferDataSourceFactory(
-      media::MediaLog* media_log,
-      UrlDataCb get_url_data,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      const base::TickClock* tick_clock);
-
-  void CreateDataSource(GURL uri, DataSourceCb cb) override;
-
- private:
-  void OnUrlData(DataSourceCb cb,
-                 base::RepeatingCallback<void(bool)> download_cb,
-                 scoped_refptr<UrlData> data);
-
-  std::unique_ptr<media::MediaLog> media_log_;
-  UrlDataCb get_url_data_;
-  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
-  std::unique_ptr<BufferedDataSourceHostImpl> buffered_data_source_host_;
-  base::WeakPtrFactory<MultiBufferDataSourceFactory> weak_factory_{this};
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.cc
new file mode 100644
index 0000000..b8b8e01
--- /dev/null
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.cc
@@ -0,0 +1,60 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.h"
+
+#include "base/logging.h"
+#include "base/ranges/algorithm.h"
+#include "base/task/bind_post_task.h"
+#include "base/types/pass_key.h"
+#include "media/formats/hls/types.h"
+#include "third_party/blink/renderer/platform/media/buffered_data_source_host_impl.h"
+#include "third_party/blink/renderer/platform/media/multi_buffer_data_source.h"
+
+namespace blink {
+
+MultiBufferDataSourceFactory::~MultiBufferDataSourceFactory() = default;
+
+MultiBufferDataSourceFactory::MultiBufferDataSourceFactory(
+    media::MediaLog* media_log,
+    UrlDataCb get_url_data,
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    const base::TickClock* tick_clock)
+    : media_log_(media_log->Clone()),
+      get_url_data_(get_url_data),
+      main_task_runner_(std::move(main_task_runner)) {
+  buffered_data_source_host_ = std::make_unique<BufferedDataSourceHostImpl>(
+      base::DoNothing(), tick_clock);
+}
+
+void MultiBufferDataSourceFactory::CreateDataSource(GURL uri, DataSourceCb cb) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  auto download_cb =
+#if DCHECK_IS_ON()
+      base::BindRepeating(
+          [](const std::string url, bool is_downloading) {
+            DVLOG(1) << __func__ << "(" << url << ", " << is_downloading << ")";
+          },
+          uri.spec());
+#else
+      base::DoNothing();
+#endif
+
+  get_url_data_.Run(std::move(uri),
+                    base::BindOnce(&MultiBufferDataSourceFactory::OnUrlData,
+                                   weak_factory_.GetWeakPtr(), std::move(cb),
+                                   std::move(download_cb)));
+}
+
+void MultiBufferDataSourceFactory::OnUrlData(
+    DataSourceCb cb,
+    base::RepeatingCallback<void(bool)> download_cb,
+    scoped_refptr<UrlData> data) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  std::move(cb).Run(std::make_unique<MultiBufferDataSource>(
+      main_task_runner_, std::move(data), media_log_.get(),
+      buffered_data_source_host_.get(), std::move(download_cb)));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.h b/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.h
new file mode 100644
index 0000000..faac8b07
--- /dev/null
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.h
@@ -0,0 +1,55 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIA_MULTI_BUFFER_DATA_SOURCE_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIA_MULTI_BUFFER_DATA_SOURCE_FACTORY_H_
+
+#include <memory>
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/tick_clock.h"
+#include "base/types/pass_key.h"
+#include "media/base/data_source.h"
+#include "media/base/media_log.h"
+#include "media/filters/hls_data_source_provider_impl.h"
+#include "third_party/blink/public/platform/media/url_index.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+
+namespace blink {
+
+class BufferedDataSourceHostImpl;
+
+class PLATFORM_EXPORT MultiBufferDataSourceFactory
+    : public media::HlsDataSourceProviderImpl::DataSourceFactory {
+ public:
+  using UrlDataCb = base::RepeatingCallback<
+      void(const GURL& url, base::OnceCallback<void(scoped_refptr<UrlData>)>)>;
+
+  ~MultiBufferDataSourceFactory() override;
+  MultiBufferDataSourceFactory(
+      media::MediaLog* media_log,
+      UrlDataCb get_url_data,
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      const base::TickClock* tick_clock);
+
+  void CreateDataSource(GURL uri, DataSourceCb cb) override;
+
+ private:
+  void OnUrlData(DataSourceCb cb,
+                 base::RepeatingCallback<void(bool)> download_cb,
+                 scoped_refptr<UrlData> data);
+
+  std::unique_ptr<media::MediaLog> media_log_;
+  UrlDataCb get_url_data_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+  std::unique_ptr<BufferedDataSourceHostImpl> buffered_data_source_host_;
+  base::WeakPtrFactory<MultiBufferDataSourceFactory> weak_factory_{this};
+};
+
+}  // namespace blink
+
+#endif  // ifndef
+        // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MEDIA_MULTI_BUFFER_DATA_SOURCE_FACTORY_H_
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index 5fd973bc..d1f180d 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -95,7 +95,8 @@
 #include "ui/gfx/geometry/size.h"
 
 #if BUILDFLAG(ENABLE_HLS_DEMUXER)
-#include "third_party/blink/renderer/platform/media/hls_data_source_provider_impl.h"
+#include "media/filters/hls_data_source_provider_impl.h"
+#include "third_party/blink/renderer/platform/media/multi_buffer_data_source_factory.h"
 #endif  // BUILDFLAG(ENABLE_HLS_DEMUXER)
 
 #if BUILDFLAG(IS_ANDROID)
@@ -1585,7 +1586,7 @@
 base::SequenceBound<media::HlsDataSourceProvider>
 WebMediaPlayerImpl::GetHlsDataSourceProvider() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  return base::SequenceBound<HlsDataSourceProviderImpl>(
+  return base::SequenceBound<media::HlsDataSourceProviderImpl>(
       main_task_runner_,
       std::make_unique<MultiBufferDataSourceFactory>(
           media_log_.get(),
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
index 0610fba..02affbaf 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -540,8 +540,9 @@
   std::vector<gfx::BufferPlane> planes;
 
   uint32_t usage =
-      gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER |
-      gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | gpu::SHARED_IMAGE_USAGE_SCANOUT;
+      gpu::SHARED_IMAGE_USAGE_GLES2_READ | gpu::SHARED_IMAGE_USAGE_GLES2_WRITE |
+      gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
+      gpu::SHARED_IMAGE_USAGE_SCANOUT;
 #if BUILDFLAG(IS_APPLE)
   usage |= gpu::SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX;
 #endif
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
index cf705b2..d8ebce0 100644
--- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
+++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
@@ -2466,7 +2466,7 @@
 }
 
 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
-    defined(MEMORY_SANITIZER)
+    defined(MEMORY_SANITIZER) || defined(UNDEFINED_SANITIZER)
 // Flaky under sanitizers and in other "slow" bot configs:
 // https://crbug.com/1029250
 #define MAYBE_VSyncAlignedGestureScrollPinchScroll \
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index ee75008..4c3d992 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1536,14 +1536,11 @@
 # See https://docs.google.com/document/d/1FH0iG8G8mEebjMpVA_zvSfHBWUhWqC92jRFctaGcxrc/edit#heading=h.pacsgp238vkn
 
 crbug.com/1488371 virtual/deprecate-unload/http/tests/history/history-replace-updates-current-item.html [ Failure Skip Timeout ]
-crbug.com/1488371 virtual/deprecate-unload/http/tests/navigation/image-load-in-subframe-unload-handler.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/http/tests/navigation/image-load-in-unload-handler.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/back-forward-cache/events.html [ Failure Skip Timeout ]
-crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/unloading-documents/001.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/009.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html [ Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/the-window-object/open-close/close_unload.html [ Failure Skip Timeout ]
-crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/browsers/the-window-object/self-et-al.window.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/webappapis/scripting/events/event-handler-attributes-body-window.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Failure Skip Timeout ]
 crbug.com/1488371 virtual/deprecate-unload/external/wpt/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html [ Failure Skip Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index b6aa743..e86e8924 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1822,6 +1822,7 @@
     ],
     "exclusive_tests": "ALL",
     "args": ["--enable-features=NoForcedFrameUpdatesForWebTests",
+             "--disable-features=KeepAliveInBrowserMigration",
              "--disable-threaded-compositing", "--disable-threaded-animation"],
     "expires": "Dec 1, 2024"
   },
@@ -2016,7 +2017,8 @@
     ],
     "exclusive_tests": "ALL",
     "args": [
-      "--enable-features=Prerender2InNewTab,Prerender2AllowActivationInBackground"
+      "--enable-features=Prerender2InNewTab,Prerender2AllowActivationInBackground",
+      "--disable-features=KeepAliveInBrowserMigration"
     ],
     "owners": ["nhiroki@chromium.org"],
     "expires": "Jul 1, 2024"
@@ -2274,7 +2276,7 @@
       "--disable-features=DeprecateUnload",
       "--disable-threaded-compositing", "--disable-threaded-animation"
     ],
-    "expires": "Dec 1, 2023"
+    "expires": "Apr 1, 2024"
   },
   {
     "prefix": "clone-for-branch2-disabled",
@@ -2565,7 +2567,6 @@
       "http/tests/inspector-protocol/permissions-policy.js",
       "http/tests/navigation/history-back-across-form-submission-to-fragment.html",
       "http/tests/navigation/image-css-load-in-subframe-unload-handler.html",
-      "http/tests/navigation/image-load-in-subframe-unload-handler.html",
       "http/tests/navigation/image-load-in-unload-handler.html",
       "http/tests/navigation/redirect-on-back-updates-history-item.html",
       "http/tests/navigation/redirect-on-reload-updates-history-item.html",
@@ -2595,7 +2596,6 @@
       "external/wpt/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html",
       "external/wpt/html/browsers/the-window-object/BarProp.window.js",
       "external/wpt/html/browsers/the-window-object/open-close/close_unload.html",
-      "external/wpt/html/browsers/the-window-object/self-et-al.window.js",
       "external/wpt/html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.js",
       "external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js",
       "external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js",
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 111bf9df0..a1475e0 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
@@ -2471,6 +2471,13 @@
       ]
      ],
      "crashtests": {
+      "add-list-item-marker.html": [
+       "fa14315cabfdba936e5c81c53d9a0b2583a3cfe1",
+       [
+        null,
+        {}
+       ]
+      ],
       "as-baseline-aligned-grid-item.html": [
        "f9a9e1dad0d21f9b29c8643a57d9862582a4a1d0",
        [
@@ -4075,6 +4082,15 @@
       ]
      },
      "overflow-wrap": {
+      "crashtests": {
+       "overflow-wrap-leading-floats-crash.html": [
+        "0661cf7286494ca00c91e60b635c25501b3a8d87",
+        [
+         null,
+         {}
+        ]
+       ]
+      },
       "overflow-wrap-break-word-long-crash.html": [
        "e318386ded5bd3d1d61cf876fe420c8f5ada799f",
        [
@@ -139846,7 +139862,7 @@
          ]
         ],
         "masonry-item-placement-001.html": [
-         "2f8cfbfacc21aade2e06f858f83abb0af468d7bf",
+         "649e1edb7cb9bd903f795f6e605d12ae566390eb",
          [
           null,
           [
@@ -139859,7 +139875,7 @@
          ]
         ],
         "masonry-item-placement-002.html": [
-         "5f7083b173331f1e4593d4d97cc0513039606316",
+         "7d321bf731684173f483d6ba3abde11da307de8e",
          [
           null,
           [
@@ -139872,7 +139888,7 @@
          ]
         ],
         "masonry-item-placement-003.html": [
-         "4d490c18d5d1d79f960e82ded542e1de5bccadc6",
+         "8a183cffc6bd3f59fb0c7ca58b9a85588bdab3f8",
          [
           null,
           [
@@ -140058,7 +140074,7 @@
          ]
         ],
         "masonry-order-002.html": [
-         "ae68f4e631a2f44540a60a7eebb5ef9a3ac9b84a",
+         "abad3d44b8326535bb1f44832011a1a6145a47b9",
          [
           null,
           [
@@ -140114,7 +140130,7 @@
          ]
         ],
         "masonry-track-sizing-explicit-block.html": [
-         "05f60893900f44753d4873e60d4b348bd6270a07",
+         "3cc98708fe9aec94293eb5bcb296f01d3a4a7508",
          [
           null,
           [
@@ -140153,7 +140169,7 @@
          ]
         ],
         "masonry-track-sizing-span-row.html": [
-         "6058ca5e7441c87db5f29cdb37d09e55134ead82",
+         "475c27f1ebea5598c6e3fcec0e21d13b08bc9499",
          [
           null,
           [
@@ -320379,7 +320395,7 @@
          []
         ],
         "masonry-item-placement-001-ref.html": [
-         "7108a11a100e58ac89daec02c1e874f0c6c5ab95",
+         "2e100c3be619cbbb55ea430edb92d08dd2af4b2a",
          []
         ],
         "masonry-item-placement-002-ref.html": [
@@ -320439,11 +320455,11 @@
        },
        "order": {
         "masonry-order-001-ref.html": [
-         "371699981544487f6b7c6b1e8d084e746057a07d",
+         "6f20bd05838efed10a0915b30941ff7bcbb73b6a",
          []
         ],
         "masonry-order-002-ref.html": [
-         "5dd4e47d80b7777ab3e2473d33178cc00bb4cae8",
+         "15be3fde83710c6a7876a5befa8d91dc9f26f8e7",
          []
         ]
        },
@@ -387021,6 +387037,10 @@
       "1b63235b7cdffe9ebb43bfac3a01d5220e1519fb",
       []
      ],
+     "register-service-worker-iframe.https.html": [
+      "547ab1d93d9adb9cb82ea797ee5e900b9d0e067c",
+      []
+     ],
      "report.py": [
       "7d0fa36019ef58c8c7764767f267628cd05bc285",
       []
@@ -387046,7 +387066,7 @@
       []
      ],
      "shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html": [
-      "8229ce88d82ad05e8f7e1d1e9886f49c282bc805",
+      "3451d91477ddc7b417a207a1d7afcf2384e83e7a",
       []
      ],
      "shared-storage-writable-fetch-request-fallback-to-network-worker.js": [
@@ -387090,11 +387110,11 @@
       []
      ],
      "util.js": [
-      "f82765846c22a452f29cc6cd097080955499d1f8",
+      "4a7fcc4590ff53e41695e9a6c11304e287eb3384",
       []
      ],
      "util.sub.js": [
-      "970c33b7f2551e76c57d5cc2431b3131084fd025",
+      "f147209d6096375d9a5ccc5b1dc42a36d3be6bec",
       []
      ],
      "verify-get-undefined-module.js": [
@@ -436080,6 +436100,344 @@
      }
     },
     "css-align": {
+     "abspos": {
+      "align-self-htb-ltr-htb.html": [
+       "786cec7acf76607a92b44a76880c1a2543da25e4",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-htb-ltr-vlr.html": [
+       "917e50d5e694b470a034faeabb4cfb0d557c1ed8",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-htb-ltr-vrl.html": [
+       "b60d4615314440e0a1ba563737babfa5e8db69b5",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-htb-rtl-htb.html": [
+       "9bf919dd46522c46a0f563ba215858748271ef08",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-htb-rtl-vlr.html": [
+       "5c1e8c75c935e76466118ed1695d01c54c3271c0",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-htb-rtl-vrl.html": [
+       "b7f0056976893b0e093dbe63b7a7f669abf19162",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-ltr-htb.html": [
+       "98e3c0b9366591f26502263b8130861966d656d1",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-ltr-vlr.html": [
+       "73585d2db5a819b2a9be3fb2555ea45bf8546473",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-ltr-vrl.html": [
+       "39ecd388999cde7b344c8f8832060611580ad7bd",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-rtl-htb.html": [
+       "7a4167f62a5ac156d3e99985a5c8d3c6dfc36e93",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-rtl-vlr.html": [
+       "4ce7d46520a171a57ed4068e52d78a8f115e4862",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vlr-rtl-vrl.html": [
+       "0fe160442f460499385eefb3255a266e5d5f4f36",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-ltr-htb.html": [
+       "98e6145a6313409cfb55c8b7e3b5c0a573f2231d",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-ltr-vlr.html": [
+       "d22b347da3044c5e0da34162faa80f74429ac065",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-ltr-vrl.html": [
+       "602b7afb7b8b32bb8ccd0a3729629643a258be7b",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-rtl-htb.html": [
+       "1dcfd8709f0b7c17f9762d9e96d1d06bb5eb3fbc",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-rtl-vlr.html": [
+       "d22b347da3044c5e0da34162faa80f74429ac065",
+       [
+        null,
+        {}
+       ]
+      ],
+      "align-self-vrl-rtl-vrl.html": [
+       "602b7afb7b8b32bb8ccd0a3729629643a258be7b",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-ltr-htb.html": [
+       "cfef344e041ed1029f4d44ee9bf91745744527d9",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-ltr-vlr.html": [
+       "55680f4b2c46dad322677eb6d845187855349bd9",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-ltr-vrl.html": [
+       "57ee3af6408bde8597df863695c4cd6b2456ceb5",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-rtl-htb.html": [
+       "95e54c2b990b497ef000d2ab3e8a6e3cd3bd88dd",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-rtl-vlr.html": [
+       "e7224e76db6de9bd49080af30283a57981be48e1",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-htb-rtl-vrl.html": [
+       "ba7e98a6767831e38a9e5fa67f9d17a37979f0e2",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-ltr-htb.html": [
+       "d47c504679b1b543b13957e90059411b4fbaa71c",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-ltr-vlr.html": [
+       "71e3687f6f4ac3d35c3f28464aa2c08be31de869",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-ltr-vrl.html": [
+       "ae90d4da0d8f2277025bbefdfc2b7e2174001854",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-rtl-htb.html": [
+       "1a192b56924c95aeed27efbe1133f6b5f912f683",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-rtl-vlr.html": [
+       "cb9986db10159e2f591e0e577a95b01aa78ee3d0",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vlr-rtl-vrl.html": [
+       "fb717a051f2a2b4b16f134dae830d8b403af7b46",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-ltr-htb.html": [
+       "e2cbff322b3051a5c5c9b87cdab55c6dfaeb4d9f",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-ltr-vlr.html": [
+       "5aa2f482888be3ff299ff6291d65728aa0024403",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-ltr-vrl.html": [
+       "cf2db8d369bf195d40fd2c5e933297558aa269ca",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-rtl-htb.html": [
+       "317e53e92e0a40f3dad0b40194363ed1e9bba326",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-rtl-vlr.html": [
+       "2d144d16aa097880b85701b931ef7010319ca0ca",
+       [
+        null,
+        {}
+       ]
+      ],
+      "justify-self-vrl-rtl-vrl.html": [
+       "026c6e96816ffbb56bbb2e9f1275a0dfb2bdbf4f",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-align-self-htb.html": [
+       "9e259c1e630ad2184752e66f6db9142686fc4ea3",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-align-self-vlr.html": [
+       "d47b1836d52ed2bd8bf300080e09c6382055b286",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-align-self-vrl.html": [
+       "3432762007efe52af47712d15362280cfb5e3a13",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-justify-self-htb.html": [
+       "0fa5cc34d57347f69665507be6c4fea1a7f98cdb",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-justify-self-vlr.html": [
+       "7554975f1be1e1cbb990decb0ded47f53ad0763c",
+       [
+        null,
+        {}
+       ]
+      ],
+      "safe-justify-self-vrl.html": [
+       "fe2405cf798a601c41867c34f002b1f5a6d579e3",
+       [
+        null,
+        {}
+       ]
+      ],
+      "stretch-intrinsic-size-htb-htb.html": [
+       "dc7df332e403d838dea63a0e27bea948771b411b",
+       [
+        null,
+        {}
+       ]
+      ],
+      "stretch-intrinsic-size-htb-vrl.html": [
+       "cd2c9b9abc49764f8eb93ad49abd5fe32e110821",
+       [
+        null,
+        {}
+       ]
+      ],
+      "stretch-intrinsic-size-vrl-htb.html": [
+       "7b1002191f2fef22b0a95b4830cc24db807ab577",
+       [
+        null,
+        {}
+       ]
+      ],
+      "stretch-intrinsic-size-vrl-vrl.html": [
+       "10f11a9f12d36ee042db9d4fdc8134799615750e",
+       [
+        null,
+        {}
+       ]
+      ],
+      "table-align-self-stretch.html": [
+       "bedd0a56950d21ef9e3bd81ffb30fe9534a621ef",
+       [
+        null,
+        {}
+       ]
+      ],
+      "table-justify-self-stretch.html": [
+       "c409b10714095581523df4a4d8305b9d7ac249f7",
+       [
+        null,
+        {}
+       ]
+      ]
+     },
      "animation": {
       "align-no-interpolation.html": [
        "037743bdd32fc8de5c60e0608a08085cd3cd6fe7",
@@ -616574,7 +616932,7 @@
      ]
     ],
     "percent-encoding.html": [
-     "696734b663d2cbd49adbb6a2a400d0747be5ebc6",
+     "1f1794bdae09db3a501479717121d93938e9869a",
      [
       null,
       {
@@ -623708,8 +624066,22 @@
       {}
      ]
     ],
+    "shared-storage-writable-service-worker-fetch.tentative.https.sub.html": [
+     "ea7af527b540d303cf3e41c7afd8d88071bcd293",
+     [
+      null,
+      {}
+     ]
+    ],
+    "shared-storage-writable-service-worker-iframe.tentative.https.sub.html": [
+     "9eb2820145ea31c250e4a5003c0d5974941d71ca",
+     [
+      null,
+      {}
+     ]
+    ],
     "shared-storage-writable-service-worker-img.tentative.https.sub.html": [
-     "9e7326d3c4d62435ef7a344864341bdd318965fb",
+     "6d481559ee75e96955cc8f83c464200e4c4a9039",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001-ref.html
index 7108a11..2e100c3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001-ref.html
@@ -8,38 +8,38 @@
   <title>Reference: Masonry layout using `grid-column/row`</title>
   <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-template-columns: repeat(4,80px);
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-template-columns: repeat(4,80px);
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
+  <item style="grid-column:1">6</item>
+  <item style="grid-column:2">5</item>
+  <item style="grid-column:span 2">4</item>
   <item style="margin-top:10px">3</item>
   <item style="grid-column:span 2">1</item>
   <item>2</item>
-  <item style="grid-column:2">5</item>
-  <item style="grid-column:span 2">4</item>
-  <item style="grid-column:1">6</item>
 </grid>
 
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001.html
index 2f8cfbf..649e1ed 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-001.html
@@ -10,38 +10,38 @@
   <link rel="help" href="https://drafts.csswg.org/css-grid-2">
   <link rel="match" href="masonry-item-placement-001-ref.html">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-template-columns: repeat(4,80px);
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-template-columns: repeat(4,80px);
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
-  <item style="grid-column:2/span 2">1</item>
-  <item>2</item>
-  <item style="margin-top:10px">3</item>
-  <item style="grid-column:3/span 2">4</item>
+  <item style="grid-column:1">6</item>
   <item>5</item>
-  <item>6</item>
+  <item style="margin-top:10px">3</item>
+  <item style="grid-column:span 2">1</item>
+  <item>2</item>
+  <item style="grid-column:3/span 2">4</item>
 </grid>
 
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-002.html
index 5f7083b..7d321bf7 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-002.html
@@ -10,38 +10,38 @@
   <link rel="help" href="https://drafts.csswg.org/css-grid-2">
   <link rel="match" href="masonry-item-placement-002-ref.html">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-auto-columns: 80px;
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-auto-columns: 80px;
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
-  <item style="grid-column:foo 2; grid-row:span 2">2</item>
+  <item style="grid-column:1/span 4;">1</item>
   <item>3</item>
+  <item style="grid-column:foo 2; grid-row:span 2">2</item>
   <item style="grid-column:span 3">4</item>
   <item>5</item>
   <item>6</item>
-  <item style="grid-column:span 4; grid-row:-100">1</item>
 </grid>
 
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-003.html
index 4d490c18..8a183cff 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-003.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/item-placement/masonry-item-placement-003.html
@@ -10,37 +10,37 @@
   <link rel="help" href="https://drafts.csswg.org/css-grid-2">
   <link rel="match" href="masonry-item-placement-003-ref.html">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-auto-flow: dense;
-  grid-auto-columns: 80px;
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-auto-flow: dense;
+      grid-auto-columns: 80px;
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
   <item style="grid-row:-100">1</item>
+  <item>3</item>
   <item style="grid-column:foo 2; grid-row:span 2">2</item>
   <item style="grid-column:span 3">4</item>
-  <item>3</item>
   <item>5</item>
   <item>6</item>
 </grid>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001-ref.html
index 37169998..6f20bd0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-001-ref.html
@@ -8,28 +8,28 @@
   <title>Reference: Masonry layout using `order`</title>
   <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-template-columns:  repeat(4,auto);
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-template-columns:  repeat(4,auto);
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
@@ -38,6 +38,6 @@
   <item style="margin-top:10px">4</item>
   <item>6</item>
   <item>2</item>
+  <item style="grid-column: span 2">5</item>
   <item>3</item>
-  <item style="grid-column:3/span 2">5</item>
 </grid>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002-ref.html
index 5dd4e47d..15be3fd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002-ref.html
@@ -8,36 +8,36 @@
   <title>Reference: Masonry layout using `order` and `masonry-auto-flow: next`</title>
   <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-template-columns:  repeat(4,auto);
-  grid-template-rows: masonry;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-template-columns:  repeat(4,auto);
+      grid-template-rows: masonry;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
-  <item>1</item>
-  <item style="margin-top:10px">4</item>
-  <item>6</item>
-  <item>2</item>
-  <item style="grid-column:1/span 2">5</item>
-  <item style="grid-column:3">3</item>
+  <item style="grid-column: 1">1</item>
+  <item style="margin-top:10px; grid-column: 2;">4</item>
+  <item style="grid-column: 3">6</item>
+  <item style="grid-column: 4">2</item>
+  <item style="grid-column: 2/span 2">5</item>
+  <item>3</item>
 </grid>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002.html
index ae68f4e..abad3d4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/order/masonry-order-002.html
@@ -10,37 +10,37 @@
   <link rel="help" href="https://drafts.csswg.org/css-grid-2">
   <link rel="match" href="masonry-order-002-ref.html">
   <style>
-html,body {
-  color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
-}
+    html,body {
+      color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0;
+    }
 
-grid {
-  display: inline-grid;
-  gap: 10px 20px;
-  grid-template-columns:  repeat(4,auto);
-  grid-template-rows: masonry;
-  masonry-auto-flow: next;
-  color: #444;
-  border: 1px solid;
-  padding: 2px;
-}
+    grid {
+      display: inline-grid;
+      gap: 10px 20px;
+      grid-template-columns:  repeat(4,auto);
+      grid-template-rows: masonry;
+      masonry-auto-flow: next;
+      color: #444;
+      border: 1px solid;
+      padding: 2px;
+    }
 
-item {
-  background-color: #444;
-  color: #fff;
-  padding: 20px;
-  margin: 3px;
-  border: 5px solid blue;
-}
-</style>
+    item {
+      background-color: #444;
+      color: #fff;
+      padding: 20px;
+      margin: 3px;
+      border: 5px solid blue;
+    }
+  </style>
 </head>
 <body>
 
 <grid>
   <item>1</item>
   <item style="order:1">2</item>
-  <item style="order:2">3</item>
+  <item style="order:1">3</item>
   <item style="margin-top:10px">4</item>
-  <item style="order:1; grid-column:span 2">5</item>
+  <item style="order:2; grid-column:span 2">5</item>
   <item>6</item>
 </grid>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-explicit-block.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-explicit-block.html
index 05f6089..3cc98708 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-explicit-block.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-explicit-block.html
@@ -11,37 +11,35 @@
 
 <body>
 <style>
-grid {
-    display: grid;
-    grid-template-columns: auto 1fr;
-    grid-template-rows: masonry;
-    width: 300px;
-    height: 100px;
-}
+    grid {
+        display: grid;
+        grid-template-columns: 100px 1fr;
+        grid-template-rows: masonry;
+        width: 300px;
+        height: 100px;
+    }
 
-box1 {
-    height: 50px;
-    width: 30px;
-    background-color: blue;
-}
+    box1 {
+        height: 50px;
+        width: 30px;
+        background-color: blue;
+    }
 
-box2 {
-    height: 50px;
-    background-color: red;
-}
+    box2 {
+        height: 50px;
+        background-color: red;
+    }
 
-box3 {
-    height: 50px;
-    width: 100px;
-    grid-row: 2;
-    grid-column: 1;
-    background-color: purple;
-}
+    box3 {
+        height: 50px;
+        width: 100px;
+        background-color: purple;
+    }
 
-box4 {
-    height: 50px;
-    background-color: green;
-}
+    box4 {
+        height: 50px;
+        background-color: green;
+    }
 
 </style>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-span-row.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-span-row.html
index 6058ca5..475c27f1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-span-row.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/track-sizing/masonry-track-sizing-span-row.html
@@ -11,46 +11,45 @@
 
 <body>
 <style>
-grid {
-    display: grid;
-    grid-template-columns: auto 1fr;
-    grid-template-rows: masonry;
-    width: 300px;
-    height: 100px;
-}
+    grid {
+        display: grid;
+        grid-template-columns: 50px 1fr;
+        grid-template-rows: masonry;
+        width: 300px;
+        height: 100px;
+    }
 
-box1 {
-    height: 50px;
-    width: 50px;
-    background-color: blue;
-}
+    box1 {
+        height: 50px;
+        width: 50px;
+        background-color: blue;
+    }
 
-box2 {
-    height: 50px;
-    background-color: red;
-}
+    box2 {
+        height: 50px;
+        background-color: red;
+    }
 
-box3 {
-    width: 100px;
-    height: 50px;
-    background-color: purple;
-    z-index: 1;
-}
+    box3 {
+        width: 100px;
+        height: 50px;
+        background-color: purple;
+        z-index: 1;
+    }
 
-box4 {
-    height: 50px;
-    width: 300px;
-    grid-column-start: 1;
-    grid-column-end: 3;
-    background-color: green;
-}
+    box4 {
+        height: 50px;
+        width: 300px;
+        grid-column: span 2;
+        background-color: green;
+    }
 </style>
 
 <grid>
     <box1>1</box1>
     <box2>2</box2>
-    <box3>3</box3>
     <box4>4</box4>
+    <box3>3</box3>
 </grid>
 
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/fenced-frame/permission-geolocation.https.html b/third_party/blink/web_tests/external/wpt/fenced-frame/permission-geolocation.https.html
index 98b5a72b..e9ad535 100644
--- a/third_party/blink/web_tests/external/wpt/fenced-frame/permission-geolocation.https.html
+++ b/third_party/blink/web_tests/external/wpt/fenced-frame/permission-geolocation.https.html
@@ -35,13 +35,14 @@
     win.onload = resolve;
   });
 
-  const unloadPromise = new Promise(resolve => {
-    win.onunload = resolve;
+  // Pagehide can be used to detect the document destruction.
+  const pagehidePromise = new Promise(resolve => {
+    win.onpagehide = resolve;
   });
 
   await win.runTest(fenced_frame_url);
   win.close();
-  await unloadPromise;
+  await pagehidePromise;
 }
 
 promise_test(async t => {
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js
index 1b0fa121..c425228 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js
@@ -28,8 +28,8 @@
   async_test(t => {
     const otherW = window.open();
     assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} is broken`);
-    otherW.onunload = t.step_func(() => {
-      assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context unload`);
+    otherW.onpagehide = t.step_func(() => {
+      assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context pagehide`);
       t.step_timeout(() => {
         assert_equals(otherW.opener, null); // Ensure browsing context is discarded
         assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context removal`);
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/resources/router-rules.js b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/resources/router-rules.js
index 67871a2..f8fe403 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/resources/router-rules.js
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/resources/router-rules.js
@@ -12,6 +12,18 @@
   'condition-urlpattern-string-source-network': [
     {condition: {urlPattern: '/**/direct.txt'}, source: 'network'},
   ],
+  'condition-urlpattern-constructed-ignore-case-source-network': [{
+    condition: {
+      urlPattern: new URLPattern(
+          {pathname: '/**/DiReCT.TxT'},
+          {ignoreCase: true})
+    },
+    source: 'network'
+  }],
+  'condition-urlpattern-constructed-respect-case-source-network': [{
+    condition: {urlPattern: new URLPattern({pathname: '/**/DiReCT.TxT'})},
+    source: 'network'
+  }],
   'condition-request-source-network':
       [{condition: {requestMode: 'no-cors'}, source: 'network'}],
   'condition-or-source-network': [{
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html
index 523ececf..1673b97 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html
@@ -11,6 +11,10 @@
 <script>
 const SCRIPT = 'resources/static-router-sw.js';
 const ROUTER_RULE_KEY = 'condition-urlpattern-constructed-source-network';
+const ROUTER_RULE_KEY_IGNORE_CASE =
+  'condition-urlpattern-constructed-ignore-case-source-network';
+const ROUTER_RULE_KEY_RESPECT_CASE =
+  'condition-urlpattern-constructed-respect-case-source-network';
 const SCOPE = 'resources/';
 const REGISTERED_ROUTE = 'resources/direct.txt';
 const NON_REGISTERED_ROUTE = 'resources/simple.html';
@@ -48,6 +52,19 @@
   assert_equals(iwin.document.body.innerText, "Network\n");
 }, 'Main resource load matched with the condition');
 
+iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_IGNORE_CASE, async (t, iwin, worker) => {
+  const fetched_urls = await get_fetched_urls(worker);
+  const {requests} = fetched_urls.data;
+  assert_equals(requests.length, 0);
+  assert_equals(iwin.document.body.innerText, "Network\n");
+}, 'Main resource load matched with the ignore case condition');
+
+iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_RESPECT_CASE, async (t, iwin, worker) => {
+  const fetched_urls = await get_fetched_urls(worker);
+  const {requests} = fetched_urls.data;
+  assert_equals(requests.length, 1);
+}, 'Main resource load matched without the ignore case condition');
+
 iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => {
   const fetched_urls = await get_fetched_urls(worker);
   const {requests} = fetched_urls.data;
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html
index 1fd3880..6154c38 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html
@@ -10,6 +10,10 @@
 const SCRIPT = 'resources/static-router-sw.js';
 const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED =
   'condition-urlpattern-constructed-source-network';
+const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_IGNORE_CASE =
+  'condition-urlpattern-constructed-ignore-case-source-network';
+const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_RESPECT_CASE =
+  'condition-urlpattern-constructed-respect-case-source-network';
 const ROUTER_RULE_KEY_URL_PATTERN_URLPATTERNINIT =
   'condition-urlpattern-urlpatterninit-source-network';
 const ROUTER_RULE_KEY_URL_PATTERN_STRING =
@@ -89,6 +93,18 @@
   assert_equals(response.type, 'opaque');
 }, 'Subresource cross origin load matched with URLPattern condition via constructed object');
 
+iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_IGNORE_CASE, async (t, iwin) => {
+  const rnd = randomString();
+  const response = await iwin.fetch('?nonce=' + rnd);
+  assert_equals(await response.text(), "Network\n");
+}, 'Subresource load matched with ignoreCase URLPattern condition');
+
+iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_RESPECT_CASE, async (t, iwin) => {
+  const rnd = randomString();
+  const response = await iwin.fetch('?nonce=' + rnd);
+  assert_equals(await response.text(), rnd);
+}, 'Subresource load matched without ignoreCase URLPattern condition');
+
 iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_URLPATTERNINIT, async (t, iwin) => {
   const rnd = randomString();
   const response = await iwin.fetch('?nonce=' + rnd);
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/resources/utils.js b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/resources/utils.js
index 687f6a4..56ab603 100644
--- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/resources/utils.js
@@ -29,6 +29,9 @@
       while (this.#active) {
         // Add the "keepalive" option to avoid fetch() results in unhandled
         // rejection with fetch abortion due to window.close().
+        // TODO(crbug.com/1356128): After this migration, "keepalive" will not
+        // be able to extend the lifetime of a Document, such that it cannot be
+        // used here to guarantee the promise resolution.
         const messages = await (await fetch(this.#url, {keepalive: true})).json();
         for (const {data, id} of messages) {
           if (!this.#ids.has(id))
diff --git a/third_party/blink/web_tests/fast/css/annotated-regions-expected.txt b/third_party/blink/web_tests/fast/css/annotated-regions-expected.txt
index 49bfba6..b99c8ffd 100644
--- a/third_party/blink/web_tests/fast/css/annotated-regions-expected.txt
+++ b/third_party/blink/web_tests/fast/css/annotated-regions-expected.txt
@@ -12,6 +12,12 @@
 PASS nonDraggableRegions() is '45,25+30x10'
 PASS draggableRegions() is '20,10+100x60'
 PASS nonDraggableRegions() is '20,10+60x20'
+PASS draggableRegions() is ''
+PASS nonDraggableRegions() is ''
+PASS draggableRegions() is ''
+PASS nonDraggableRegions() is ''
+PASS draggableRegions() is ''
+PASS nonDraggableRegions() is ''
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/css/annotated-regions.html b/third_party/blink/web_tests/fast/css/annotated-regions.html
index e9042b4..fb8f826e 100644
--- a/third_party/blink/web_tests/fast/css/annotated-regions.html
+++ b/third_party/blink/web_tests/fast/css/annotated-regions.html
@@ -50,6 +50,10 @@
 }
 
 function startTest() {
+    // Verify that app regions are correctly collected when the frame supports
+    // app regions.
+    internals.SetSupportsAppRegion(true);
+
     shouldBe("draggableRegions()", "''");
     shouldBe("nonDraggableRegions()", "''");
 
@@ -69,6 +73,26 @@
     shouldBe("draggableRegions()", "'20,10+100x60'");
     shouldBe("nonDraggableRegions()", "'20,10+60x20'");
 
+    // Verify that app regions are reset when the frame does not support
+    // app regions.
+    internals.SetSupportsAppRegion(false);
+    shouldBe("draggableRegions()", "''");
+    shouldBe("nonDraggableRegions()", "''");
+
+    draggable.classList.remove('drag');
+    draggable.classList.remove('nodrag');
+
+    // App regions should continue to be empty when new app regions are added
+    // or resized.
+    draggable.classList.add("drag");
+    nondraggable.classList.add('nodrag');
+    shouldBe("draggableRegions()", "''");
+    shouldBe("nonDraggableRegions()", "''");
+
+    draggable.classList.add('transform');
+    shouldBe("draggableRegions()", "''");
+    shouldBe("nonDraggableRegions()", "''");
+
     finishJSTest();
 }
 
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrame-capture-timestamp-id.html b/third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html
similarity index 85%
rename from third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrame-capture-timestamp-id.html
rename to third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html
index 2db7d2c..81262cf 100644
--- a/third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrame-capture-timestamp-id.html
+++ b/third_party/blink/web_tests/fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>Test RTCEncodedVideoFrame.capture_time_identifier_ms in a RTCPeerConnection</title>
+<title>Test RTCEncodedVideoFrameMetadata.timestamp matches a unencoded frame timestamp</title>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="resources/RTCPeerConnection-helper.js"></script>
@@ -37,6 +37,6 @@
 
 trackProcessor.readable.pipeThrough(transformer).pipeTo(trackGenerator.writable);
 const metadata = (await senderReader.read()).value.getMetadata();
-assert_equals(originalTimestamp, metadata.captureTimestamp);
-}, "captureTimestamp identifier is propagated from VideoFrame to RTCEncodedVideoFrame");
+assert_equals(originalTimestamp, metadata.timestamp);
+}, "timestamp identifier is propagated from VideoFrame to RTCEncodedVideoFrame");
 </script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler-expected.txt b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler-expected.txt
new file mode 100644
index 0000000..a44def3
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler-expected.txt
@@ -0,0 +1 @@
+This test triggers an pagehide handler that starts an image load in a different frame (and deletes both frames), but ensures the main frame is not destroyed. We pass if we don't crash.
diff --git a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler.html b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler.html
new file mode 100644
index 0000000..cd76c3e
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-pagehide-handler.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+
+<body>
+  <script>
+    if (window.testRunner) {
+      testRunner.dumpAsText();
+      testRunner.waitUntilDone();
+    }
+
+    function test() {
+      document.getElementsByTagName("body")[0].removeChild(document.getElementById("target"));
+    }
+
+    function finish() {
+      setTimeout(function () {
+        if (window.testRunner)
+          testRunner.notifyDone();
+      }, 300);
+    }
+  </script>
+  <iframe id="target" name="target" src="resources/image-load-in-subframe-pagehide-handler-helper.html"></iframe>
+  This test triggers an pagehide handler that starts an image load in a different frame (and deletes both frames), but
+  ensures the main frame is not destroyed. We pass if we don't crash.
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler-expected.txt b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler-expected.txt
deleted file mode 100644
index f817783..0000000
--- a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test triggers an unload handler that starts an image load in a different frame (and deletes both frames), but ensures the main frame is not destroyed. We pass if we don't crash.
diff --git a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler.html b/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler.html
deleted file mode 100644
index c00aa79e..0000000
--- a/third_party/blink/web_tests/http/tests/navigation/image-load-in-subframe-unload-handler.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-<body>
-<script>
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-    
-    function test() {
-        document.getElementsByTagName("body")[0].removeChild(document.getElementById("target"));
-    }
-    
-    function finish() {
-        setTimeout(function() {
-            if (window.testRunner)
-                testRunner.notifyDone();
-        }, 300);
-    }
-</script>
-<iframe id="target" name="target" src="resources/image-load-in-subframe-unload-handler-helper.html"></iframe>
-This test triggers an unload handler that starts an image load in a different frame (and deletes both frames), but ensures the main frame is not destroyed. We pass if we don't crash.
-</body>
-</html>
diff --git a/third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-unload-handler-helper.html b/third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-pagehide-handler-helper.html
similarity index 85%
rename from third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-unload-handler-helper.html
rename to third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-pagehide-handler-helper.html
index f289000..30af3d4d 100644
--- a/third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-unload-handler-helper.html
+++ b/third_party/blink/web_tests/http/tests/navigation/resources/image-load-in-subframe-pagehide-handler-helper.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <html>
 <body>
 <script>
@@ -11,6 +12,6 @@
         window.top.finish();
     }
 </script>
-<iframe src="subframe-with-unload-handler-in-parent.html">
+<iframe src="subframe-with-pagehide-handler-in-parent.html">
 </body>
 </html>
diff --git a/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-pagehide-handler-in-parent.html b/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-pagehide-handler-in-parent.html
new file mode 100644
index 0000000..8886c14
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-pagehide-handler-in-parent.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <script>
+    function unload() {
+      window.parent.imageLoad();
+    }
+
+    function load() {
+      window.top.test();
+    }
+  </script>
+</head>
+
+<body onload="load();" onpagehide="unload();">
+  This subframe has an pagehide handler.
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-unload-handler-in-parent.html b/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-unload-handler-in-parent.html
deleted file mode 100644
index eec5d3e..0000000
--- a/third_party/blink/web_tests/http/tests/navigation/resources/subframe-with-unload-handler-in-parent.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<head>
-<script>
-function unload() { 
-    window.parent.imageLoad();
-}
-
-function load() {
-    window.top.test();
-}
-</script>
-</head>
-<body onload="load();" onunload="unload();">
-This subframe has an unload handler.
-</body>
-</html>
diff --git a/third_party/blink/web_tests/virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/unloading-documents/001-expected.txt b/third_party/blink/web_tests/virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/unloading-documents/001-expected.txt
new file mode 100644
index 0000000..2c74bc75f
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/deprecate-unload/external/wpt/html/browsers/browsing-the-web/unloading-documents/001-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] document.open in unload
+  assert_equals: expected "0123456789" but got "01238"
+Harness: the test ran to completion.
+
diff --git a/third_party/catapult b/third_party/catapult
index b142d41..d12e688 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit b142d415308e1f3ace94f0f39807bf0198ee004f
+Subproject commit d12e6887dd534569117c06f92e8c69c91e0ad12b
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 510ec37..62652a4 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 510ec37c3f2bf8431f8c6f1a573d6826ed01d9e6
+Subproject commit 62652a482c1bc8658057a7fa7b216f638d0dfaae
diff --git a/third_party/cros-components/src b/third_party/cros-components/src
index b1b1b0b..b7deff8 160000
--- a/third_party/cros-components/src
+++ b/third_party/cros-components/src
@@ -1 +1 @@
-Subproject commit b1b1b0b6ff08289f3f5d960947aa12db68775d41
+Subproject commit b7deff896ee3186e7d33a52ddde07da2400de2ad
diff --git a/third_party/dawn b/third_party/dawn
index 109e648..3c117aa 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 109e648f2f452424d2d1d0b1eba1e1b9fe036645
+Subproject commit 3c117aa551537c3e7cc0f8cbb05d85fe76d466fc
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index d4775b3..14464a6 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit d4775b3834d55829a429cf165089e92261a9e426
+Subproject commit 14464a6787e9a358a6acdc532568e6fe3a347344
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 7781523..c7e8227 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 7781523a3fc8f16c45a382676e73b1f7f28a58e5
+Subproject commit c7e8227f786e657d8f82d6e9f1de859ed60280df
diff --git a/third_party/pdfium b/third_party/pdfium
index cb1cd2f..dda631d 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit cb1cd2f12898d7cdc0d9435be2244ce27f88afe3
+Subproject commit dda631d81103d0af8fa2fe4bd81e9da08435f989
diff --git a/third_party/skia b/third_party/skia
index 3a3475d..9d220eb 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 3a3475d12f220b795821eabae517ab7cb6f12c9f
+Subproject commit 9d220ebe40a0e8537f3e37d8ac1fbe4ac4dfa43a
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 7a6ef73..666950d 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 7a6ef7301b5d84f751b483f9d5466b3696749c26
+Subproject commit 666950d6de30c9c26773208b0f861463b25ae37c
diff --git a/third_party/webrtc b/third_party/webrtc
index 21edbe5..e6df126b 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 21edbe5d0dc7a506ff42b858969d16d0cbdd3a0b
+Subproject commit e6df126b798c0644010afeaddeb2e13053d8f192
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index fbcaf3b..4e01d9d3 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -35,7 +35,7 @@
 # https://chromium.googlesource.com/chromium/src/+/main/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
-CLANG_REVISION = 'llvmorg-18-init-12938-geb1d5065'
+CLANG_REVISION = 'llvmorg-18-init-14420-gea3a3b25'
 CLANG_SUB_REVISION = 1
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index 96530ad..494cc1fa 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -1916,19 +1916,24 @@
   </summary>
 </histogram>
 
-<histogram name="Blink.Fetch.RequestResourceTime2{Scheme}" units="microseconds"
-    expires_after="2023-05-02">
+<histogram name="Blink.Fetch.RequestResourceTime2{SchemeOrPreload}"
+    units="microseconds" expires_after="2024-03-12">
   <owner>cduvall@chromium.org</owner>
   <owner>csharrison@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
   <summary>
     The total microseconds spent in ResourceFetcher::requestResource for
-    {Scheme}.
+    {SchemeOrPreload}.
 
     This histogram only records metrics on machines with high-resolution clocks.
+
+    Warning: this histogram was expired from 2023-05-02 to 2023-12-12; data may
+    be missing.
   </summary>
-  <token key="Scheme">
+  <token key="SchemeOrPreload">
     <variant name="" summary="all URLs"/>
     <variant name=".Data" summary="data URLs"/>
+    <variant name=".Preload" summary="preloaded URLs"/>
   </token>
 </histogram>
 
@@ -2701,6 +2706,23 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Blink.LCPP.NavigationToStartPreload.MainFrame.{SubresourceType}.Time"
+    units="ms" expires_after="2024-02-01">
+  <owner>chikamune@chromium.org</owner>
+  <owner>yyanagisawa@chromium.org</owner>
+  <owner>kouhei@chromium.org</owner>
+  <summary>
+    Record when the page's main frame starts preloading {SubresourceType}.
+    Measures the duration between when the navigation starts, to when preloading
+    subresource is started.
+  </summary>
+  <token key="SubresourceType">
+    <variant name="EachSubresource" summary="each subresources"/>
+    <variant name="FirstSubresource" summary="the first subresource"/>
+  </token>
+</histogram>
+
 <histogram name="Blink.LCPP.PotentiallyLCPResourcePriorityBoosts" units="count"
     expires_after="2024-01-27">
   <owner>kouhei@chromium.org</owner>
@@ -3164,13 +3186,29 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.PreloadRequestStartDuration" units="microseconds"
+    expires_after="2024-03-12">
+  <owner>sisidovski@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Measures the time from the time when PreloadRequest::Start is called to when
+    PreloadRequest::Start is finished.
+
+    This histogram only records metrics on machines with high-resolution clocks.
+  </summary>
+</histogram>
+
 <histogram name="Blink.PreloadRequestWaitTime" units="ms"
-    expires_after="2023-10-22">
+    expires_after="2024-03-12">
   <owner>cduvall@chromium.org</owner>
   <owner>swarm-team@google.com</owner>
+  <owner>chrome-loading@google.com</owner>
   <summary>
     Measures the time from the creation of a PreloadRequest to when
     PreloadRequest::Start is called. Logged for each PreloadRequest::Start call.
+
+    Warning: this histogram was expired from 2023-10-22 to 2023-12-12; data may
+    be missing.
   </summary>
 </histogram>
 
@@ -3291,6 +3329,9 @@
   <owner>jam@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
+    Blink.ScanAndPreloadTime2 is the newer one of this histogram, which records
+    the time with microseconds.
+
     Measures the time it takes to scan and preload subresources for a document
     in a {FrameType}. Logged every time the {IsInitial} preload scan is
     performed.
@@ -3308,6 +3349,31 @@
   </token>
 </histogram>
 
+<histogram name="Blink.ScanAndPreloadTime2{Task}.{FrameType}.{IsInitial}"
+    units="microseconds" expires_after="2024-03-13">
+  <owner>sisidovski@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Measures the time it takes to {Task} for a document in a {FrameType}. Logged
+    every time the {IsInitial} preload scan is performed.
+
+    This histogram only records metrics on machines with high-resolution clocks.
+  </summary>
+  <token key="Task">
+    <variant name="" summary="scan and preload subresources"/>
+    <variant name=".Preload" summary="preload subresources"/>
+    <variant name=".Scan" summary="scan"/>
+  </token>
+  <token key="FrameType">
+    <variant name="MainFrame"/>
+    <variant name="Subframe"/>
+  </token>
+  <token key="IsInitial">
+    <variant name="Initial"/>
+    <variant name="NonInitial"/>
+  </token>
+</histogram>
+
 <histogram name="Blink.ScanPendingActivityDuration" units="ms"
     expires_after="M85">
   <owner>haraken@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 63cace6..3c53af0 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -3928,17 +3928,6 @@
   </summary>
 </histogram>
 
-<histogram name="Net.QuicSession.ReceivedSettings.EnableExtendedConnect"
-    enum="Boolean" expires_after="2024-01-21">
-  <owner>momoka@google.com</owner>
-  <owner>ricea@chromium.org</owner>
-  <owner>src/net/quic/OWNERS</owner>
-  <summary>
-    The value of the SETTINGS_ENABLE_CONNECT_PROTOCOL parameter received on an
-    HTTP/3 connection, if the parameter is not present log false.
-  </summary>
-</histogram>
-
 <histogram name="Net.QuicSession.ReceivedSettings.MaxHeaderListSize2"
     units="bytes" expires_after="2023-09-24">
   <owner>dschinazi@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 6247873..2f15042 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1614,7 +1614,7 @@
 </histogram>
 
 <histogram name="Omnibox.SetText.Duration" units="ms"
-    expires_after="2024-05-26">
+    expires_after="2024-06-01">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1624,7 +1624,7 @@
 </histogram>
 
 <histogram name="Omnibox.SetText.TextLength" units="characters"
-    expires_after="2024-06-02">
+    expires_after="2024-06-01">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1634,7 +1634,7 @@
 </histogram>
 
 <histogram name="Omnibox.setText.TruncatedTooMuch" enum="Boolean"
-    expires_after="2023-12-24">
+    expires_after="2024-06-01">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index bbea9bc2..b9eaa34 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -798,6 +798,48 @@
 </histogram>
 
 <histogram
+    name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalLoaderCallback"
+    units="ms" expires_after="2024-03-19">
+  <owner>nidhijaju@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    The time relative to navigation start that a callback for the navigation
+    loader is last invoked for the main resource of a main frame navigation, for
+    Google Search page loads. Only recorded for Search navigations that happen
+    entirely in the foreground. The metric is emitted when the navigation is
+    completed or the app is backgrounded on Android.
+  </summary>
+</histogram>
+
+<histogram
+    name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalRequestStart"
+    units="ms" expires_after="2024-03-19">
+  <owner>nidhijaju@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    The time relative to navigation start that the final HTTP request is sent
+    for the main resource of a main frame navigation, for Google Search page
+    loads. Only recorded for Search navigations that happen entirely in the
+    foreground. The metric is emitted when the navigation is completed or the
+    app is backgrounded on Android.
+  </summary>
+</histogram>
+
+<histogram
+    name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFinalResponseStart"
+    units="ms" expires_after="2024-03-19">
+  <owner>nidhijaju@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    The time relative to navigation start that the headers of the final HTTP
+    response is received for the main resource of a main frame navigation, for
+    Google Search page loads. Only recorded for Search navigations that happen
+    entirely in the foreground. The metric is emitted when the navigation is
+    completed or the app is backgrounded on Android.
+  </summary>
+</histogram>
+
+<histogram
     name="PageLoad.Clients.GoogleSearch.NavigationTiming.NavigationStartToFirstLoaderCallback"
     units="ms" expires_after="2024-03-19">
   <owner>kouhei@chromium.org</owner>
diff --git a/tools/polymer/css_to_wrapper_test.py b/tools/polymer/css_to_wrapper_test.py
index d20c49e..adeab81 100755
--- a/tools/polymer/css_to_wrapper_test.py
+++ b/tools/polymer/css_to_wrapper_test.py
@@ -58,7 +58,7 @@
   def testCssToWrapperStylePolymer(self):
     self._run_test('css_to_wrapper/foo_style.css',
                    'css_to_wrapper/foo_style.css.ts',
-                   'css_to_wrapper/foo_style_expected.css.ts')
+                   'css_to_wrapper/expected/foo_style.css.ts')
 
   def testCssToWrapperStyleLit(self):
     self._run_test('css_to_wrapper/foo_style_lit.css',
@@ -68,12 +68,12 @@
   def testCssToWrapperStyleNoIncludes(self):
     self._run_test('css_to_wrapper/foo_no_includes_style.css',
                    'css_to_wrapper/foo_no_includes_style.css.ts',
-                   'css_to_wrapper/foo_no_includes_style_expected.css.ts')
+                   'css_to_wrapper/expected/foo_no_includes_style.css.ts')
 
   def testCssToWrapperVarsPolymer(self):
     self._run_test('css_to_wrapper/foo_vars.css',
                    'css_to_wrapper/foo_vars.css.ts',
-                   'css_to_wrapper/foo_vars_expected.css.ts')
+                   'css_to_wrapper/expected/foo_vars.css.ts')
 
   def testCssToWrapperVarsLit(self):
     self._run_test('css_to_wrapper/foo_vars_lit.css',
@@ -83,19 +83,19 @@
   def testCssToWrapperMinify(self):
     self._run_test('css_to_wrapper/foo_style.css',
                    'css_to_wrapper/foo_style.css.ts',
-                   'css_to_wrapper/foo_style_expected.min.css.ts',
+                   'css_to_wrapper/expected/foo_style.min.css.ts',
                    minify=True)
 
   def testCssToWrapperUseJs(self):
     self._run_test('css_to_wrapper/foo_style.css',
                    'css_to_wrapper/foo_style.css.js',
-                   'css_to_wrapper/foo_style_expected.css.ts',
+                   'css_to_wrapper/expected/foo_style.css.ts',
                    use_js=True)
 
   def testCssToWrapperSchemeRelative(self):
     self._run_test('css_to_wrapper/foo_relative_style.css',
                    'css_to_wrapper/foo_relative_style.css.ts',
-                   'css_to_wrapper/foo_relative_style_expected.css.ts')
+                   'css_to_wrapper/expected/foo_relative_style.css.ts')
 
 
 if __name__ == '__main__':
diff --git a/tools/polymer/html_to_wrapper_test.py b/tools/polymer/html_to_wrapper_test.py
index eefa4ce..b1dc959 100755
--- a/tools/polymer/html_to_wrapper_test.py
+++ b/tools/polymer/html_to_wrapper_test.py
@@ -64,12 +64,12 @@
 
   def testHtmlToWrapperPolymerElement(self):
     self._run_test('html_to_wrapper/foo.html', 'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_expected.html.ts')
+                   'html_to_wrapper/expected/foo.html.ts')
 
   def testHtmlToWrapperPolymerElement_Detect(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_expected.html.ts',
+                   'html_to_wrapper/expected/foo.html.ts',
                    template='detect')
 
   def testHtmlToWrapperLitElement(self):
@@ -87,56 +87,56 @@
   def testHtmlToWrapperNativeElement(self):
     self._run_test('html_to_wrapper/foo_native.html',
                    'html_to_wrapper/foo_native.html.ts',
-                   'html_to_wrapper/foo_native_expected.html.ts',
+                   'html_to_wrapper/expected/foo_native.html.ts',
                    template='native')
 
   def testHtmlToWrapperNativeElement_Detect(self):
     self._run_test('html_to_wrapper/foo_native.html',
                    'html_to_wrapper/foo_native.html.ts',
-                   'html_to_wrapper/foo_native_expected.html.ts',
+                   'html_to_wrapper/expected/foo_native.html.ts',
                    template='detect')
 
   def testHtmlToWrapperIcons(self):
     self._run_test('html_to_wrapper/icons.html',
                    'html_to_wrapper/icons.html.ts',
-                   'html_to_wrapper/icons_expected.html.ts')
+                   'html_to_wrapper/expected/icons.html.ts')
 
   def testHtmlToWrapper_Minify(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_expected.min.html.ts',
+                   'html_to_wrapper/expected/foo.min.html.ts',
                    minify=True)
 
   def testHtmlToWrapper_MinifyDetect(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_expected.min.html.ts',
+                   'html_to_wrapper/expected/foo.min.html.ts',
                    minify=True,
                    template='detect')
 
   def testHtmlToWrapper_UseJs(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.js',
-                   'html_to_wrapper/foo_expected.html.ts',
+                   'html_to_wrapper/expected/foo.html.ts',
                    use_js=True)
 
   def testHtmlToWrapper_UseJsDetect(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.js',
-                   'html_to_wrapper/foo_expected.html.ts',
+                   'html_to_wrapper/expected/foo.html.ts',
                    use_js=True,
                    template='detect')
 
   def testHtmlToWrapperSchemeRelative(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_expected.html.ts',
+                   'html_to_wrapper/expected/foo.html.ts',
                    scheme='relative')
 
   def testHtmlToWrapperSchemeChrome(self):
     self._run_test('html_to_wrapper/foo.html',
                    'html_to_wrapper/foo.html.ts',
-                   'html_to_wrapper/foo_chrome_expected.html.ts',
+                   'html_to_wrapper/expected/foo_chrome.html.ts',
                    scheme='chrome')
 
 
diff --git a/tools/polymer/tests/css_to_wrapper/foo_no_includes_style_expected.css.ts b/tools/polymer/tests/css_to_wrapper/expected/foo_no_includes_style.css.ts
similarity index 100%
rename from tools/polymer/tests/css_to_wrapper/foo_no_includes_style_expected.css.ts
rename to tools/polymer/tests/css_to_wrapper/expected/foo_no_includes_style.css.ts
diff --git a/tools/polymer/tests/css_to_wrapper/foo_relative_style_expected.css.ts b/tools/polymer/tests/css_to_wrapper/expected/foo_relative_style.css.ts
similarity index 100%
rename from tools/polymer/tests/css_to_wrapper/foo_relative_style_expected.css.ts
rename to tools/polymer/tests/css_to_wrapper/expected/foo_relative_style.css.ts
diff --git a/tools/polymer/tests/css_to_wrapper/foo_style_expected.css.ts b/tools/polymer/tests/css_to_wrapper/expected/foo_style.css.ts
similarity index 100%
rename from tools/polymer/tests/css_to_wrapper/foo_style_expected.css.ts
rename to tools/polymer/tests/css_to_wrapper/expected/foo_style.css.ts
diff --git a/tools/polymer/tests/css_to_wrapper/foo_style_expected.min.css.ts b/tools/polymer/tests/css_to_wrapper/expected/foo_style.min.css.ts
similarity index 100%
rename from tools/polymer/tests/css_to_wrapper/foo_style_expected.min.css.ts
rename to tools/polymer/tests/css_to_wrapper/expected/foo_style.min.css.ts
diff --git a/tools/polymer/tests/css_to_wrapper/foo_vars_expected.css.ts b/tools/polymer/tests/css_to_wrapper/expected/foo_vars.css.ts
similarity index 100%
rename from tools/polymer/tests/css_to_wrapper/foo_vars_expected.css.ts
rename to tools/polymer/tests/css_to_wrapper/expected/foo_vars.css.ts
diff --git a/tools/polymer/tests/html_to_wrapper/foo_expected.html.ts b/tools/polymer/tests/html_to_wrapper/expected/foo.html.ts
similarity index 100%
rename from tools/polymer/tests/html_to_wrapper/foo_expected.html.ts
rename to tools/polymer/tests/html_to_wrapper/expected/foo.html.ts
diff --git a/tools/polymer/tests/html_to_wrapper/foo_expected.min.html.ts b/tools/polymer/tests/html_to_wrapper/expected/foo.min.html.ts
similarity index 100%
rename from tools/polymer/tests/html_to_wrapper/foo_expected.min.html.ts
rename to tools/polymer/tests/html_to_wrapper/expected/foo.min.html.ts
diff --git a/tools/polymer/tests/html_to_wrapper/foo_chrome_expected.html.ts b/tools/polymer/tests/html_to_wrapper/expected/foo_chrome.html.ts
similarity index 100%
rename from tools/polymer/tests/html_to_wrapper/foo_chrome_expected.html.ts
rename to tools/polymer/tests/html_to_wrapper/expected/foo_chrome.html.ts
diff --git a/tools/polymer/tests/html_to_wrapper/foo_native_expected.html.ts b/tools/polymer/tests/html_to_wrapper/expected/foo_native.html.ts
similarity index 100%
rename from tools/polymer/tests/html_to_wrapper/foo_native_expected.html.ts
rename to tools/polymer/tests/html_to_wrapper/expected/foo_native.html.ts
diff --git a/tools/polymer/tests/html_to_wrapper/icons_expected.html.ts b/tools/polymer/tests/html_to_wrapper/expected/icons.html.ts
similarity index 100%
rename from tools/polymer/tests/html_to_wrapper/icons_expected.html.ts
rename to tools/polymer/tests/html_to_wrapper/expected/icons.html.ts
diff --git a/tools/rust/build_rust.py b/tools/rust/build_rust.py
index cbaa4c6b..3143842 100755
--- a/tools/rust/build_rust.py
+++ b/tools/rust/build_rust.py
@@ -749,6 +749,11 @@
                       '81cd7c5b11766ed1e3214a2233371fb6d72ed89c')
 
         # TODO: Remove once
+        # https://github.com/rust-lang/rust/pull/118610 has been merged.
+        GitCherryPick(RUST_SRC_DIR, 'https://github.com/rust-lang/rust.git',
+                      'b378059e6b2573c5356423fa31d184a89a3b6029')
+
+        # TODO: Remove once
         # https://github.com/rust-lang/rust/pull/118818 has been merged.
         GitCherryPick(RUST_SRC_DIR, 'https://github.com/rust-lang/rust.git',
                       'a0c5079889b1f86dd9e246d8863a5c8b44fbdb78')
diff --git a/ui/gfx/image/image.cc b/ui/gfx/image/image.cc
index 3d831e9d..eca2ea8 100644
--- a/ui/gfx/image/image.cc
+++ b/ui/gfx/image/image.cc
@@ -122,13 +122,8 @@
 };
 
 ImageStorage::ImageStorage(Image::RepresentationType default_type)
-    : default_representation_type_(default_type)
-#if BUILDFLAG(IS_MAC)
-      ,
-      default_representation_color_space_(base::mac::GetGenericRGBColorSpace())
-#endif  // BUILDFLAG(IS_MAC)
-{
-}
+    : default_representation_type_(default_type) {}
+
 ImageStorage::~ImageStorage() = default;
 
 Image::RepresentationType ImageStorage::default_representation_type() const {
@@ -316,22 +311,19 @@
   const internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
   if (!rep) {
     std::unique_ptr<internal::ImageRep> scoped_rep;
-    CGColorSpaceRef default_representation_color_space =
-        storage()->default_representation_color_space();
 
     switch (DefaultRepresentationType()) {
       case kImageRepPNG: {
         const internal::ImageRepPNG* png_rep =
             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
-        scoped_rep = internal::MakeImageRepCocoa(internal::NSImageFromPNG(
-            png_rep->image_reps(), default_representation_color_space));
+        scoped_rep = internal::MakeImageRepCocoa(
+            internal::NSImageFromPNG(png_rep->image_reps()));
         break;
       }
       case kImageRepSkia: {
         const internal::ImageRepSkia* skia_rep =
             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
-        NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
-            default_representation_color_space);
+        NSImage* image = NSImageFromImageSkia(*skia_rep->image());
         scoped_rep = internal::MakeImageRepCocoa(image);
         break;
       }
@@ -453,13 +445,6 @@
   return GetRepresentation(DefaultRepresentationType(), true)->Size();
 }
 
-#if BUILDFLAG(IS_MAC)
-void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
-  if (storage())
-    storage()->set_default_representation_color_space(color_space);
-}
-#endif  // BUILDFLAG(IS_MAC)
-
 Image::RepresentationType Image::DefaultRepresentationType() const {
   CHECK(storage());
   return storage()->default_representation_type();
diff --git a/ui/gfx/image/image.h b/ui/gfx/image/image.h
index 9cb9b1f3..c3d1c85a 100644
--- a/ui/gfx/image/image.h
+++ b/ui/gfx/image/image.h
@@ -163,7 +163,8 @@
   // Set the default representation's color space. This is used for converting
   // to NSImage. This is used to compensate for PNGCodec not writing or reading
   // colorspace ancillary chunks. (sRGB, iCCP).
-  void SetSourceColorSpace(CGColorSpaceRef color_space);
+  // TODO(https://crbug.com/1495334): Remove callers of this function.
+  void SetSourceColorSpace(CGColorSpaceRef color_space) {}
 #endif  // BUILDFLAG(IS_MAC)
 
  private:
diff --git a/ui/gfx/image/image_internal.h b/ui/gfx/image/image_internal.h
index 1226b33..11fdbbb 100644
--- a/ui/gfx/image/image_internal.h
+++ b/ui/gfx/image/image_internal.h
@@ -90,14 +90,8 @@
   const ImageRep* AddRepresentation(std::unique_ptr<ImageRep> rep) const;
 
 #if BUILDFLAG(IS_MAC)
-  void set_default_representation_color_space(CGColorSpaceRef color_space) {
-    DCHECK(IsOnValidSequence());
-    default_representation_color_space_ = color_space;
-  }
-  CGColorSpaceRef default_representation_color_space() const {
-    DCHECK(IsOnValidSequence());
-    return default_representation_color_space_;
-  }
+  // TODO(https://crbug.com/1495334): Remove callers of this function.
+  void set_default_representation_color_space(CGColorSpaceRef color_space) {}
 #endif  // BUILDFLAG(IS_MAC)
 
  private:
@@ -109,14 +103,6 @@
   // exist in the |representations_| map.
   Image::RepresentationType default_representation_type_;
 
-#if BUILDFLAG(IS_MAC)
-  // The default representation's colorspace. This is used for converting to
-  // NSImage. This field exists to compensate for PNGCodec not writing or
-  // reading colorspace ancillary chunks. (sRGB, iCCP).
-  // Not owned.
-  CGColorSpaceRef default_representation_color_space_;
-#endif  // BUILDFLAG(IS_MAC)
-
   // All the representations of an Image. Size will always be at least one, with
   // more for any converted representations.
   mutable std::map<Image::RepresentationType,
diff --git a/ui/gfx/image/image_mac.mm b/ui/gfx/image/image_mac.mm
index 0beedf45..8c1e9c86 100644
--- a/ui/gfx/image/image_mac.mm
+++ b/ui/gfx/image/image_mac.mm
@@ -97,8 +97,7 @@
   return refcounted_bytes;
 }
 
-NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
-                        CGColorSpaceRef color_space) {
+NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps) {
   if (image_png_reps.empty()) {
     LOG(ERROR) << "Unable to decode PNG.";
     return GetErrorNSImage();
@@ -116,24 +115,6 @@
       LOG(ERROR) << "Unable to decode PNG at " << image_png_rep.scale << ".";
       return GetErrorNSImage();
     }
-
-    // PNGCodec ignores colorspace related ancillary chunks (sRGB, iCCP). Ignore
-    // colorspace information when decoding directly from PNG to an NSImage so
-    // that the conversions: PNG -> SkBitmap -> NSImage and PNG -> NSImage
-    // produce visually similar results.
-    CGColorSpaceModel decoded_color_space_model =
-        CGColorSpaceGetModel(ns_image_rep.colorSpace.CGColorSpace);
-    CGColorSpaceModel color_space_model = CGColorSpaceGetModel(color_space);
-    if (decoded_color_space_model == color_space_model) {
-      NSColorSpace* ns_color_space =
-          [[NSColorSpace alloc] initWithCGColorSpace:color_space];
-      NSBitmapImageRep* ns_retagged_image_rep =
-          [ns_image_rep
-              bitmapImageRepByRetaggingWithColorSpace:ns_color_space];
-      if (ns_retagged_image_rep && ns_retagged_image_rep != ns_image_rep)
-        ns_image_rep = ns_retagged_image_rep;
-    }
-
     if (!image) {
       float scale = image_png_rep.scale;
       NSSize image_size = NSMakeSize(ns_image_rep.pixelsWide / scale,
diff --git a/ui/gfx/image/image_platform.h b/ui/gfx/image/image_platform.h
index 766b927..590b0be1 100644
--- a/ui/gfx/image/image_platform.h
+++ b/ui/gfx/image/image_platform.h
@@ -46,8 +46,14 @@
 #elif BUILDFLAG(IS_MAC)
 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
     NSImage* nsimage);
-NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
-                        CGColorSpaceRef color_space);
+
+NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
+                               CGColorSpaceRef color_space) {
+  return NSImageFromPNG(image_png_reps);
+}
 
 NSImage* NSImageOfImageRepCocoa(const ImageRepCocoa* image_rep);
 std::unique_ptr<ImageRep> MakeImageRepCocoa(NSImage* image);
diff --git a/ui/gfx/image/image_skia_util_mac.h b/ui/gfx/image/image_skia_util_mac.h
index 1dff65ea..22fa57c 100644
--- a/ui/gfx/image/image_skia_util_mac.h
+++ b/ui/gfx/image/image_skia_util_mac.h
@@ -30,10 +30,15 @@
 // Converts to NSImage from ImageSkia. Uses the sRGB color space.
 GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
 
-// Converts to NSImage from given ImageSkia and a color space.
-GFX_EXPORT NSImage* NSImageFromImageSkiaWithColorSpace(
+// Converts to NSImage from given ImageSkia.
+GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
+
+// TODO(https://crbug.com/1495334): Remove callers to this function.
+inline NSImage* NSImageFromImageSkiaWithColorSpace(
     const gfx::ImageSkia& image_skia,
-    CGColorSpaceRef color_space);
+    CGColorSpaceRef color_space) {
+  return NSImageFromImageSkia(image_skia);
+}
 
 }  // namespace gfx
 
diff --git a/ui/gfx/image/image_skia_util_mac.mm b/ui/gfx/image/image_skia_util_mac.mm
index e61cfc0..43870ef65 100644
--- a/ui/gfx/image/image_skia_util_mac.mm
+++ b/ui/gfx/image/image_skia_util_mac.mm
@@ -69,9 +69,8 @@
     NSImageRep* ns_image_rep = GetNSImageRepWithPixelSize(image,
         desired_size_for_scale);
 
-    SkBitmap bitmap(skia::NSImageRepToSkBitmapWithColorSpace(
-        ns_image_rep, desired_size_for_scale, false,
-        base::mac::GetSRGBColorSpace()));
+    SkBitmap bitmap(skia::NSImageRepToSkBitmap(ns_image_rep,
+                                               desired_size_for_scale, false));
     if (bitmap.isNull())
       continue;
 
@@ -81,12 +80,6 @@
 }
 
 NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) {
-  return NSImageFromImageSkiaWithColorSpace(image_skia,
-                                            base::mac::GetSRGBColorSpace());
-}
-
-NSImage* NSImageFromImageSkiaWithColorSpace(const gfx::ImageSkia& image_skia,
-                                            CGColorSpaceRef color_space) {
   if (image_skia.isNull())
     return nil;
 
@@ -94,8 +87,7 @@
   image_skia.EnsureRepsForSupportedScales();
   std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps();
   for (const auto& rep : image_reps) {
-    [image addRepresentation:skia::SkBitmapToNSBitmapImageRepWithColorSpace(
-                                 rep.GetBitmap(), color_space)];
+    [image addRepresentation:skia::SkBitmapToNSBitmapImageRep(rep.GetBitmap())];
   }
 
   image.size = NSMakeSize(image_skia.width(), image_skia.height());
diff --git a/ui/gfx/image/image_unittest_util.cc b/ui/gfx/image/image_unittest_util.cc
index cdbc16d..10d4cd5 100644
--- a/ui/gfx/image/image_unittest_util.cc
+++ b/ui/gfx/image/image_unittest_util.cc
@@ -205,8 +205,7 @@
       skia::SkBitmapToUIImageWithColorSpace(bitmap, scale, color_space.get());
   return image;
 #elif BUILDFLAG(IS_MAC)
-  NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
-      bitmap, base::mac::GetGenericRGBColorSpace());
+  NSImage* image = skia::SkBitmapToNSImage(bitmap);
   return image;
 #else
   return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index d61030f..dfae20e 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -4175,7 +4175,9 @@
   testing::NiceMock<MockWaylandPlatformWindowDelegate> delegate_2;
   auto toplevel = CreateWaylandWindowWithParams(
       PlatformWindowType::kWindow, gfx::Rect(10, 10, 200, 200), &delegate_2);
-  toplevel->HandleAuraToplevelConfigure(0, 0, 0, 0, {false, false, true});
+  toplevel->HandleAuraToplevelConfigure(
+      0, 0, 0, 0,
+      {.is_maximized = false, .is_fullscreen = false, .is_activated = true});
   toplevel->HandleSurfaceConfigure(2);
   EXPECT_EQ(gfx::Rect(10, 10, 200, 200), toplevel->GetBoundsInDIP());
 }
diff --git a/ui/webui/resources/cr_components/most_visited/most_visited.ts b/ui/webui/resources/cr_components/most_visited/most_visited.ts
index 33b8c62..8cf75bf 100644
--- a/ui/webui/resources/cr_components/most_visited/most_visited.ts
+++ b/ui/webui/resources/cr_components/most_visited/most_visited.ts
@@ -425,18 +425,15 @@
   }
 
   /**
-   * If a pointer is over a tile rect that is different from the one being
-   * dragged, the dragging tile is moved to the new position. The reordering
-   * is done in the DOM and the by the |reorderMostVisitedTile()| call. This is
-   * done to prevent flicking between the time when the tiles are moved back to
-   * their original positions (by removing position absolute) and when the
-   * tiles are updated via the |setMostVisitedInfo| handler.
+   * This method is always called when the drag and drop was finished.
+   * If the tiles were reordered successfully, there should be a tile with the
+   * "dropped" class.
    *
    * |reordering_| is not set to false when the tiles are reordered. The callers
    * will need to set it to false. This is necessary to handle a mouse drag
    * issue.
    */
-  private dragEnd_(x: number, y: number) {
+  private dragEnd_() {
     if (!this.customLinksEnabled_) {
       this.reordering_ = false;
       return;
@@ -446,15 +443,50 @@
 
     const dragElement =
         this.shadowRoot!.querySelector<HTMLElement>('.tile.dragging');
-    if (!dragElement) {
+    const droppedElement =
+        this.shadowRoot!.querySelector<HTMLElement>('.tile.dropped');
+
+    if (!dragElement && !droppedElement) {
       this.reordering_ = false;
       return;
     }
 
-    dragElement.classList.remove('dragging');
+    if (dragElement) {
+      dragElement.classList.remove('dragging');
 
-    this.tileElements_.forEach(el => resetTilePosition(el));
-    resetTilePosition(this.$.addShortcut);
+      this.tileElements_.forEach(el => resetTilePosition(el));
+      resetTilePosition(this.$.addShortcut);
+    } else if (droppedElement) {
+      droppedElement.classList.remove('dropped');
+
+      // Note that resetTilePosition has already been called on drop_.
+    }
+  }
+
+  /**
+   * This method is called on "drop" events (i.e. when the user drops the tile
+   * on a valid region.)
+   *
+   * If a pointer is over a tile rect that is different from the one being
+   * dragged, the dragging tile is moved to the new position. The reordering is
+   * done in the DOM and by the |reorderMostVisitedTile()| call. This is done to
+   * prevent flicking between the time when the tiles are moved back to their
+   * original positions (by removing position absolute) and when the tiles are
+   * updated via the |setMostVisitedInfo| handler.
+   *
+   * We remove the "dragging" class in this method, and add "dropped" to
+   * indicate that the dragged tile was successfully dropped.
+   */
+  private drop_(x: number, y: number) {
+    if (!this.customLinksEnabled_) {
+      return;
+    }
+
+    const dragElement =
+        this.shadowRoot!.querySelector<HTMLElement>('.tile.dragging');
+    if (!dragElement) {
+      return;
+    }
 
     const dragIndex = (this.$.tiles.modelForElement(dragElement) as unknown as {
                         index: number,
@@ -480,6 +512,16 @@
         },
       ]);
       this.pageHandler_.reorderMostVisitedTile(draggingTile.url, dropIndex);
+
+      // Remove the "dragging" class here to prevent flickering.
+      dragElement.classList.remove('dragging');
+
+      // Add "dropped" class so that we can skip disabling `reordering_` in
+      // `dragEnd_`.
+      dragElement.classList.add('dropped');
+
+      this.tileElements_.forEach(el => resetTilePosition(el));
+      resetTilePosition(this.$.addShortcut);
     }
   }
 
@@ -674,19 +716,21 @@
     }
 
     this.dragStart_(e.target as HTMLElement, e.x, e.y);
+
     const dragOver = (e: DragEvent) => {
       e.preventDefault();
       e.dataTransfer!.dropEffect = 'move';
       this.dragOver_(e.x, e.y);
     };
-    this.ownerDocument.addEventListener('dragover', dragOver);
-    this.ownerDocument.addEventListener('dragend', e => {
-      this.ownerDocument.removeEventListener('dragover', dragOver);
-      this.dragEnd_(e.x, e.y);
+
+    const drop = (e: DragEvent) => {
+      this.drop_(e.x, e.y);
+
       const dropIndex = getHitIndex(this.tileRects_, e.x, e.y);
       if (dropIndex !== -1) {
         this.enableForceHover_(dropIndex);
       }
+
       this.addEventListener('pointermove', () => {
         this.clearForceHover_();
         // When |reordering_| is true, the normal hover style is not shown.
@@ -694,6 +738,14 @@
         // after the mouse moves.
         this.reordering_ = false;
       }, {once: true});
+    };
+
+    this.ownerDocument.addEventListener('dragover', dragOver);
+    this.ownerDocument.addEventListener('drop', drop);
+    this.ownerDocument.addEventListener('dragend', _ => {
+      this.ownerDocument.removeEventListener('dragover', dragOver);
+      this.ownerDocument.removeEventListener('drop', drop);
+      this.dragEnd_();
     }, {once: true});
   }
 
@@ -857,7 +909,8 @@
       tileElement.removeEventListener('touchend', touchEnd);
       tileElement.removeEventListener('touchcancel', touchEnd);
       const {clientX, clientY} = e.changedTouches[0];
-      this.dragEnd_(clientX, clientY);
+      this.drop_(clientX, clientY);
+      this.dragEnd_();
       this.reordering_ = false;
     };
     this.ownerDocument.addEventListener('touchmove', touchMove);
diff --git a/url/url_canon.h b/url/url_canon.h
index 71343b8..8c48f98 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -699,7 +699,6 @@
 // Use for standard URLs with authorities and paths.
 COMPONENT_EXPORT(URL)
 bool CanonicalizeStandardURL(const char* spec,
-                             int spec_len,
                              const Parsed& parsed,
                              SchemeType scheme_type,
                              CharsetConverter* query_converter,
@@ -707,7 +706,6 @@
                              Parsed* new_parsed);
 COMPONENT_EXPORT(URL)
 bool CanonicalizeStandardURL(const char16_t* spec,
-                             int spec_len,
                              const Parsed& parsed,
                              SchemeType scheme_type,
                              CharsetConverter* query_converter,
@@ -749,14 +747,12 @@
 // Use for filesystem URLs.
 COMPONENT_EXPORT(URL)
 bool CanonicalizeFileSystemURL(const char* spec,
-                               int spec_len,
                                const Parsed& parsed,
                                CharsetConverter* query_converter,
                                CanonOutput* output,
                                Parsed* new_parsed);
 COMPONENT_EXPORT(URL)
 bool CanonicalizeFileSystemURL(const char16_t* spec,
-                               int spec_len,
                                const Parsed& parsed,
                                CharsetConverter* query_converter,
                                CanonOutput* output,
diff --git a/url/url_canon_filesystemurl.cc b/url/url_canon_filesystemurl.cc
index f1a9f1c..2510005 100644
--- a/url/url_canon_filesystemurl.cc
+++ b/url/url_canon_filesystemurl.cc
@@ -17,7 +17,7 @@
 
 // We use the URLComponentSource for the outer URL, as it can have replacements,
 // whereas the inner_url can't, so it uses spec.
-template<typename CHAR, typename UCHAR>
+template <typename CHAR>
 bool DoCanonicalizeFileSystemURL(const CHAR* spec,
                                  const URLComponentSource<CHAR>& source,
                                  const Parsed& parsed,
@@ -56,9 +56,9 @@
       // Strip out the user information from the inner URL, if any.
       inner_scheme_type = SCHEME_WITH_HOST_AND_PORT;
     }
-    success = CanonicalizeStandardURL(
-        spec, inner_parsed->Length(), *inner_parsed, inner_scheme_type,
-        charset_converter, output, &new_inner_parsed);
+    success =
+        CanonicalizeStandardURL(spec, *inner_parsed, inner_scheme_type,
+                                charset_converter, output, &new_inner_parsed);
   } else {
     // TODO(ericu): The URL is wrong, but should we try to output more of what
     // we were given?  Echoing back filesystem:mailto etc. doesn't seem all that
@@ -84,25 +84,21 @@
 }  // namespace
 
 bool CanonicalizeFileSystemURL(const char* spec,
-                               int spec_len,
                                const Parsed& parsed,
                                CharsetConverter* charset_converter,
                                CanonOutput* output,
                                Parsed* new_parsed) {
-  return DoCanonicalizeFileSystemURL<char, unsigned char>(
-      spec, URLComponentSource<char>(spec), parsed, charset_converter, output,
-      new_parsed);
+  return DoCanonicalizeFileSystemURL(spec, URLComponentSource(spec), parsed,
+                                     charset_converter, output, new_parsed);
 }
 
 bool CanonicalizeFileSystemURL(const char16_t* spec,
-                               int spec_len,
                                const Parsed& parsed,
                                CharsetConverter* charset_converter,
                                CanonOutput* output,
                                Parsed* new_parsed) {
-  return DoCanonicalizeFileSystemURL<char16_t, char16_t>(
-      spec, URLComponentSource<char16_t>(spec), parsed, charset_converter,
-      output, new_parsed);
+  return DoCanonicalizeFileSystemURL(spec, URLComponentSource(spec), parsed,
+                                     charset_converter, output, new_parsed);
 }
 
 bool ReplaceFileSystemURL(const char* base,
@@ -114,8 +110,8 @@
   URLComponentSource<char> source(base);
   Parsed parsed(base_parsed);
   SetupOverrideComponents(base, replacements, &source, &parsed);
-  return DoCanonicalizeFileSystemURL<char, unsigned char>(
-      base, source, parsed, charset_converter, output, new_parsed);
+  return DoCanonicalizeFileSystemURL(base, source, parsed, charset_converter,
+                                     output, new_parsed);
 }
 
 bool ReplaceFileSystemURL(const char* base,
@@ -128,8 +124,8 @@
   URLComponentSource<char> source(base);
   Parsed parsed(base_parsed);
   SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed);
-  return DoCanonicalizeFileSystemURL<char, unsigned char>(
-      base, source, parsed, charset_converter, output, new_parsed);
+  return DoCanonicalizeFileSystemURL(base, source, parsed, charset_converter,
+                                     output, new_parsed);
 }
 
 }  // namespace url
diff --git a/url/url_canon_stdurl.cc b/url/url_canon_stdurl.cc
index 304ca4c0..3afc9d8 100644
--- a/url/url_canon_stdurl.cc
+++ b/url/url_canon_stdurl.cc
@@ -13,7 +13,7 @@
 
 namespace {
 
-template <typename CHAR, typename UCHAR>
+template <typename CHAR>
 bool DoCanonicalizeStandardURL(const URLComponentSource<CHAR>& source,
                                const Parsed& parsed,
                                SchemeType scheme_type,
@@ -145,27 +145,25 @@
 }
 
 bool CanonicalizeStandardURL(const char* spec,
-                             int spec_len,
                              const Parsed& parsed,
                              SchemeType scheme_type,
                              CharsetConverter* query_converter,
                              CanonOutput* output,
                              Parsed* new_parsed) {
-  return DoCanonicalizeStandardURL<char, unsigned char>(
-      URLComponentSource<char>(spec), parsed, scheme_type, query_converter,
-      output, new_parsed);
+  return DoCanonicalizeStandardURL(URLComponentSource(spec), parsed,
+                                   scheme_type, query_converter, output,
+                                   new_parsed);
 }
 
 bool CanonicalizeStandardURL(const char16_t* spec,
-                             int spec_len,
                              const Parsed& parsed,
                              SchemeType scheme_type,
                              CharsetConverter* query_converter,
                              CanonOutput* output,
                              Parsed* new_parsed) {
-  return DoCanonicalizeStandardURL<char16_t, char16_t>(
-      URLComponentSource<char16_t>(spec), parsed, scheme_type, query_converter,
-      output, new_parsed);
+  return DoCanonicalizeStandardURL(URLComponentSource(spec), parsed,
+                                   scheme_type, query_converter, output,
+                                   new_parsed);
 }
 
 // It might be nice in the future to optimize this so unchanged components don't
@@ -187,8 +185,8 @@
   URLComponentSource<char> source(base);
   Parsed parsed(base_parsed);
   SetupOverrideComponents(base, replacements, &source, &parsed);
-  return DoCanonicalizeStandardURL<char, unsigned char>(
-      source, parsed, scheme_type, query_converter, output, new_parsed);
+  return DoCanonicalizeStandardURL(source, parsed, scheme_type, query_converter,
+                                   output, new_parsed);
 }
 
 // For 16-bit replacements, we turn all the replacements into UTF-8 so the
@@ -204,8 +202,8 @@
   URLComponentSource<char> source(base);
   Parsed parsed(base_parsed);
   SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed);
-  return DoCanonicalizeStandardURL<char, unsigned char>(
-      source, parsed, scheme_type, query_converter, output, new_parsed);
+  return DoCanonicalizeStandardURL(source, parsed, scheme_type, query_converter,
+                                   output, new_parsed);
 }
 
 }  // namespace url
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index fd10ca0..edf664401 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -1769,8 +1769,8 @@
     std::string out_str;
     StdStringCanonOutput output(&out_str);
     bool success = CanonicalizeStandardURL(
-        i.input, url_len, parsed, SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION,
-        nullptr, &output, &out_parsed);
+        i.input, parsed, SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr,
+        &output, &out_parsed);
     output.Complete();
 
     EXPECT_EQ(i.expected_success, success);
@@ -2342,8 +2342,8 @@
     Parsed out_parsed;
     std::string out_str;
     StdStringCanonOutput output(&out_str);
-    bool success = CanonicalizeFileSystemURL(i.input, url_len, parsed, nullptr,
-                                             &output, &out_parsed);
+    bool success = CanonicalizeFileSystemURL(i.input, parsed, nullptr, &output,
+                                             &out_parsed);
     output.Complete();
 
     EXPECT_EQ(i.expected_success, success);
diff --git a/url/url_parse_perftest.cc b/url/url_parse_perftest.cc
index f06e019..317f1a78 100644
--- a/url/url_parse_perftest.cc
+++ b/url/url_parse_perftest.cc
@@ -66,21 +66,21 @@
     url::ParseStandardURL(kTypicalUrl1.data(), kTypicalUrl1.size(), &parsed1);
     output.set_length(0);
     url::CanonicalizeStandardURL(
-        kTypicalUrl1.data(), kTypicalUrl1.size(), parsed1,
+        kTypicalUrl1.data(), parsed1,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output,
         &out_parsed);
 
     url::ParseStandardURL(kTypicalUrl2.data(), kTypicalUrl2.size(), &parsed2);
     output.set_length(0);
     url::CanonicalizeStandardURL(
-        kTypicalUrl2.data(), kTypicalUrl2.size(), parsed2,
+        kTypicalUrl2.data(), parsed2,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output,
         &out_parsed);
 
     url::ParseStandardURL(kTypicalUrl3.data(), kTypicalUrl3.size(), &parsed3);
     output.set_length(0);
     url::CanonicalizeStandardURL(
-        kTypicalUrl3.data(), kTypicalUrl3.size(), parsed3,
+        kTypicalUrl3.data(), parsed3,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output,
         &out_parsed);
   }
@@ -100,7 +100,7 @@
     std::string out1;
     url::StdStringCanonOutput output1(&out1);
     url::CanonicalizeStandardURL(
-        kTypicalUrl1.data(), kTypicalUrl1.size(), parsed1,
+        kTypicalUrl1.data(), parsed1,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output1,
         &out_parsed);
 
@@ -108,7 +108,7 @@
     std::string out2;
     url::StdStringCanonOutput output2(&out2);
     url::CanonicalizeStandardURL(
-        kTypicalUrl2.data(), kTypicalUrl2.size(), parsed2,
+        kTypicalUrl2.data(), parsed2,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output2,
         &out_parsed);
 
@@ -116,7 +116,7 @@
     std::string out3;
     url::StdStringCanonOutput output3(&out3);
     url::CanonicalizeStandardURL(
-        kTypicalUrl3.data(), kTypicalUrl3.size(), parsed3,
+        kTypicalUrl3.data(), parsed3,
         url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, nullptr, &output3,
         &out_parsed);
   }
diff --git a/url/url_util.cc b/url/url_util.cc
index 9258cfc..6f83f33 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -273,14 +273,13 @@
   } else if (DoCompareSchemeComponent(spec, scheme, url::kFileSystemScheme)) {
     // Filesystem URLs are special.
     ParseFileSystemURL(spec, spec_len, &parsed_input);
-    success = CanonicalizeFileSystemURL(spec, spec_len, parsed_input,
-                                        charset_converter, output,
-                                        output_parsed);
+    success = CanonicalizeFileSystemURL(spec, parsed_input, charset_converter,
+                                        output, output_parsed);
 
   } else if (DoIsStandard(spec, scheme, &scheme_type)) {
     // All "normal" URLs.
     ParseStandardURL(spec, spec_len, &parsed_input);
-    success = CanonicalizeStandardURL(spec, spec_len, parsed_input, scheme_type,
+    success = CanonicalizeStandardURL(spec, parsed_input, scheme_type,
                                       charset_converter, output, output_parsed);
 
   } else if (DoCompareSchemeComponent(spec, scheme, url::kMailToScheme)) {
diff --git a/v8 b/v8
index b057218..13b0f9f 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit b057218023961f8b94b0313dd6ddbcc274c06e74
+Subproject commit 13b0f9f24b88983f07952beb652e1bce97a4deb6