diff --git a/DEPS b/DEPS
index a978af6..bbe8781 100644
--- a/DEPS
+++ b/DEPS
@@ -271,7 +271,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8ad30fcbbe5ad4580ed8622ecc43cb89028dd46b',
+  'skia_revision': '45ecc5862826d3cdd89228f937cd3fbb2358415b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -279,7 +279,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2f0b6429b41c9024f6eb9d7938e7de5e42ad61bb',
+  'angle_revision': '7a243dbe249568d97581624ae3ffe516ab27ba9a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -342,7 +342,7 @@
   # 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': 'f2b13af9411351b29ed8317d6b4ad03f590ae6de',
+  'catapult_revision': '01d3c4cd99238ce3466284a7d07737dbd2bc474c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -350,7 +350,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': '79a7fc9c426881822e8ffc6033059035449c74ce',
+  'devtools_frontend_revision': '367472876cbd308076352cd7da6b787b4c7b8827',
   # 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.
@@ -743,7 +743,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '397a315a13f93bfb4fb9932393677220a80a9252',
+    'url': Var('chromium_git') + '/website.git' + '@' + '5cbb421191e5c407a70a7a0193fd65a41560468f',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1112,7 +1112,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '84ce7a768c7aa98899398747a739e034a157a93d',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5fbfdc976815edabe9fb68de0047b50b43d84ce7',
       'condition': 'checkout_chromeos',
   },
 
@@ -1135,7 +1135,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '26a1d24c04f7a911bebef82ba392a1fc8d6544f3',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd67468faa024b22f56bd5a9585889a01adfa03ef',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1515,7 +1515,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '8803ea4ea78c8151948be1dcca4e51eb84ad5732',
+    Var('chromium_git') + '/openscreen' + '@' + 'd7b6a03bc015d1580d00cd978a1b73d30d1cc6fb',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@@ -1532,7 +1532,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd099a600a3410a602cee37a19e875f1a974d493a',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd1cb81f2aa43df0d60a387e49c7ca570b685ca7f',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1707,7 +1707,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9618103c4aa25ea342ddad65848ff8bb0c1cee9a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '2a2f3ece157ef365ae6a8332efb91d044b98ad87',
+    Var('webrtc_git') + '/src.git' + '@' + '7df247af56fc66e78b0f91bc42fc88d351aef703',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1780,7 +1780,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c6d498a98bd042af9eee8d7a398c79f0a0f3d417',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8a1cb0a0fae66bcdd79110b43d6562935b73c604',
     'condition': 'checkout_src_internal',
   },
 
@@ -1810,7 +1810,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'q17ZIX2CbSTU3GnFjTqgyfkPh8F0QK4g5mTGTpzM9AAC',
+        'version': '4B5x_vqKIMCk0gIas0VxxlgTZVoVXU4Dyt65Q21onuEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1821,7 +1821,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'Ap_Nmod1IBnYMdDD7eGL74vxSTBBp6JQUFdfSNHPJoAC',
+        'version': 'cmYXP33FinAwR0nqGKpg5r9Xlr_ziji9HO8kIBdnalUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 85e858d..d71a086 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -69,18 +69,15 @@
   }
 }
 
-# This version of the WebView APK doesn't include WebLayer.
+# This version of the WebView APK doesn't include WebLayer java and resources.
 # It's used to define the allowlist of resources to be pulled out of language
 # splits. See |shared_resources_allowlist_target|.
 standalone_system_webview_apk_tmpl("system_webview_no_weblayer_apk") {
   exclude_weblayer_java = true
   apk_name = "SystemWebViewNoWebLayer"
 
-  # Don't include any code to speed up compilation. This is used only for the
-  # resources allowlist.
   include_32_bit_webview = false
   include_64_bit_webview = false
-  omit_dex = true
 
   # Adding deps on recycler view in the base WebView APK will end up keeping the
   # Java in the base APK instead of the WebLayer DFM, even though it is not
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 795fb15..39aba546 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -29,7 +29,6 @@
 #include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/cpu.h"
-#include "base/cpu_affinity_posix.h"
 #include "base/i18n/icu_util.h"
 #include "base/i18n/rtl.h"
 #include "base/posix/global_descriptors.h"
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn
index 54e7ab1..338deaad 100644
--- a/android_webview/nonembedded/BUILD.gn
+++ b/android_webview/nonembedded/BUILD.gn
@@ -119,6 +119,7 @@
     "java/src/org/chromium/android_webview/services/VariationsSeedServer.java",
   ]
   deps = [
+    ":devui_resources",
     ":system_webview_manifest",
     "//android_webview:common_aidl_java",
     "//android_webview:common_crash_java",
@@ -137,6 +138,7 @@
     "//third_party/android_deps:protobuf_lite_runtime_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
   ]
+  resources_package = "org.chromium.android_webview.devui"
 }
 
 source_set("nonembedded") {
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/services/DeveloperUiService.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/services/DeveloperUiService.java
index e95d7de2..02ae2ba 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/services/DeveloperUiService.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/services/DeveloperUiService.java
@@ -54,10 +54,9 @@
     private static final int FRAGMENT_ID_CRASHES = 1;
     private static final int FRAGMENT_ID_FLAGS = 2;
 
-    public static final String NOTIFICATION_TITLE =
-            "WARNING: experimental WebView features enabled";
-    public static final String NOTIFICATION_CONTENT = "Tap to see experimental features.";
-    public static final String NOTIFICATION_TICKER = "Experimental WebView features enabled";
+    public static final String NOTIFICATION_TITLE = "Experimental WebView features active";
+    public static final String NOTIFICATION_CONTENT = "Tap to see experimental WebView features.";
+    public static final String NOTIFICATION_TICKER = "Experimental WebView features active";
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
@@ -238,14 +237,15 @@
         PendingIntent pendingIntent = PendingIntent.getActivity(
                 this, 0, notificationIntent, IntentUtils.getPendingIntentMutabilityFlag(false));
 
-        Notification.Builder builder = createNotificationBuilder()
-                                               .setContentTitle(NOTIFICATION_TITLE)
-                                               .setContentText(NOTIFICATION_CONTENT)
-                                               .setSmallIcon(android.R.drawable.stat_notify_error)
-                                               .setContentIntent(pendingIntent)
-                                               .setOngoing(true)
-                                               .setVisibility(Notification.VISIBILITY_PUBLIC)
-                                               .setTicker(NOTIFICATION_TICKER);
+        Notification.Builder builder =
+                createNotificationBuilder()
+                        .setContentTitle(NOTIFICATION_TITLE)
+                        .setContentText(NOTIFICATION_CONTENT)
+                        .setSmallIcon(org.chromium.android_webview.devui.R.drawable.ic_flag)
+                        .setContentIntent(pendingIntent)
+                        .setOngoing(true)
+                        .setVisibility(Notification.VISIBILITY_PUBLIC)
+                        .setTicker(NOTIFICATION_TICKER);
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             builder = builder
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 8b3da5cb..86f8504 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -45,8 +45,6 @@
                              "include_64_bit_webview",
                            ])
 
-    _omit_dex = defined(omit_dex) && omit_dex
-
     deps += [
       "//android_webview:locale_pak_assets",
       "//android_webview:pak_file_assets",
@@ -82,9 +80,7 @@
       }
     }
 
-    if (!_omit_dex) {
-      product_config_java_packages = [ webview_product_config_java_package ]
-    }
+    product_config_java_packages = [ webview_product_config_java_package ]
 
     if (webview_includes_weblayer) {
       if (_is_bundle_module) {
@@ -92,9 +88,7 @@
       } else {
         deps += [ "//weblayer:locale_pak_assets" ]
       }
-      if (!_omit_dex) {
-        product_config_java_packages += [ weblayer_product_config_java_package ]
-      }
+      product_config_java_packages += [ weblayer_product_config_java_package ]
     }
 
     if (!defined(alternative_android_sdk_dep)) {
@@ -112,18 +106,14 @@
         "If trichrome library is used, static_library_provider must be set " +
             "so that a dep can be added on the library APK.")
 
-    _include_32_bit_webview = !defined(invoker.include_32_bit_webview) ||
-                              invoker.include_32_bit_webview
-    if (android_64bit_target_cpu) {
-      _include_64_bit_webview = !defined(invoker.include_64_bit_webview) ||
-                                invoker.include_64_bit_webview
-    }
-
     # Pure 32-bit implies a 32-bit only Webview built on a 64-bit configuration.
-    _pure_32_bit = android_64bit_target_cpu && !_include_64_bit_webview
-    _pure_64_bit = android_64bit_target_cpu && !_include_32_bit_webview
+    _pure_32_bit =
+        android_64bit_target_cpu && defined(invoker.include_64_bit_webview) &&
+        !invoker.include_64_bit_webview
+    _pure_64_bit =
+        android_64bit_target_cpu && defined(invoker.include_32_bit_webview) &&
+        !invoker.include_32_bit_webview
     not_needed([
-                 "_include_32_bit_webview",
                  "_pure_32_bit",
                  "_pure_64_bit",
                ])
@@ -135,8 +125,7 @@
     if (!_use_trichrome_library) {
       shared_resources = true
 
-      if ((!android_64bit_target_cpu && _include_32_bit_webview) ||
-          (android_64bit_target_cpu && !_pure_32_bit)) {
+      if (!android_64bit_target_cpu || !_pure_32_bit) {
         shared_libraries = [ "//android_webview:libwebviewchromium" ]
         _include_primary_support = true
       }
@@ -154,26 +143,16 @@
       if (android_64bit_target_cpu) {
         if (invoker.is_64_bit_browser) {
           native_lib_placeholders = [ "libdummy.so" ]
-          if (_include_32_bit_webview) {
+          if (invoker.include_32_bit_webview) {
             secondary_abi_shared_libraries = [ "//android_webview:monochrome_64($android_secondary_abi_toolchain)" ]
             _include_secondary_support = true
           }
         } else {
-          if (_include_64_bit_webview) {
+          if (invoker.include_64_bit_webview) {
             shared_libraries = [ "//android_webview:monochrome" ]
             _include_primary_support = true
           }
           secondary_native_lib_placeholders = [ "libdummy.so" ]
-          static_library_provider_use_secondary_abi = true
-        }
-
-        # http://crbug.com/1042107.
-        if (is_component_build) {
-          if (invoker.is_64_bit_browser) {
-            main_component_library = "libmonochrome_64.cr.so"
-          } else {
-            main_component_library = "libmonochrome.cr.so"
-          }
         }
       } else {
         native_lib_placeholders = [ "libdummy.so" ]
@@ -267,7 +246,7 @@
       command_line_flags_file = "webview-command-line"
     }
 
-    if (!is_java_debug && !_omit_dex) {
+    if (!is_java_debug) {
       proguard_enabled = true
       if (!defined(proguard_configs)) {
         proguard_configs = []
@@ -284,13 +263,13 @@
       if (_use_trichrome_library) {
         if (android_64bit_target_cpu) {
           if (invoker.is_64_bit_browser) {
-            if (_include_32_bit_webview) {
+            if (invoker.include_32_bit_webview) {
               version_code = trichrome_64_32_version_code
             } else {
               version_code = trichrome_64_version_code
             }
           } else {
-            if (_include_64_bit_webview) {
+            if (invoker.include_64_bit_webview) {
               version_code = trichrome_32_64_version_code
             } else {
               version_code = trichrome_32_version_code
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7bc74fe..727e036 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -3387,6 +3387,7 @@
     "//ash/app_list:test_support",
     "//ash/app_menu",
     "//ash/assistant/model:model",
+    "//ash/assistant/ui:constants",
     "//ash/assistant/ui:ui",
     "//ash/components/attestation:test_support",
     "//ash/components/audio",
diff --git a/ash/app_list/views/assistant/app_list_bubble_assistant_page.cc b/ash/app_list/views/assistant/app_list_bubble_assistant_page.cc
index 86d7dbe45..6266ffd 100644
--- a/ash/app_list/views/assistant/app_list_bubble_assistant_page.cc
+++ b/ash/app_list/views/assistant/app_list_bubble_assistant_page.cc
@@ -8,6 +8,8 @@
 
 #include "ash/app_list/views/assistant/assistant_dialog_plate.h"
 #include "ash/app_list/views/assistant/assistant_main_stage.h"
+#include "ash/assistant/model/assistant_ui_model.h"
+#include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/compositor/layer.h"
 #include "ui/views/layout/box_layout.h"
@@ -38,6 +40,13 @@
   dialog_plate_->RequestFocus();
 }
 
+void AppListBubbleAssistantPage::OnBoundsChanged(
+    const gfx::Rect& previous_bounds) {
+  // AssistantUiController::Get() can be nullptr in test.
+  if (AssistantUiController::Get())
+    AssistantUiController::Get()->SetAppListBubbleWidth(size().width());
+}
+
 BEGIN_METADATA(AppListBubbleAssistantPage, views::View)
 END_METADATA
 
diff --git a/ash/app_list/views/assistant/app_list_bubble_assistant_page.h b/ash/app_list/views/assistant/app_list_bubble_assistant_page.h
index 5ca6a3f..6da445d 100644
--- a/ash/app_list/views/assistant/app_list_bubble_assistant_page.h
+++ b/ash/app_list/views/assistant/app_list_bubble_assistant_page.h
@@ -29,6 +29,7 @@
 
   // views::View:
   void RequestFocus() override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
  private:
   // The text and microphone input area. Owned by views hierarchy.
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc
index 20c8cca..f72c645 100644
--- a/ash/app_list/views/folder_header_view.cc
+++ b/ash/app_list/views/folder_header_view.cc
@@ -27,7 +27,6 @@
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/focus/focus_manager.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/painter.h"
 #include "ui/views/view_targeter_delegate.h"
 
@@ -107,8 +106,8 @@
     SetNameViewBorderAndBackground(is_active);
   }
 
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override {
-    return views::GetNativeIBeamCursor();
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override {
+    return ui::mojom::CursorType::kIBeam;
   }
 
   void SetNameViewBorderAndBackground(bool is_active) {
diff --git a/ash/assistant/assistant_interaction_controller_impl.cc b/ash/assistant/assistant_interaction_controller_impl.cc
index 3b11ea11..ca08814f 100644
--- a/ash/assistant/assistant_interaction_controller_impl.cc
+++ b/ash/assistant/assistant_interaction_controller_impl.cc
@@ -492,9 +492,11 @@
     return;
   }
 
+  DCHECK(AssistantUiController::Get());
   AssistantResponse* response = GetResponseForActiveInteraction();
-  response->AddUiElement(
-      std::make_unique<AssistantCardElement>(html, fallback));
+  response->AddUiElement(std::make_unique<AssistantCardElement>(
+      html, fallback,
+      AssistantUiController::Get()->GetModel()->AppListBubbleWidth()));
 
   // If |response| is pending, commit it to cause the response for the
   // previous interaction, if one exists, to be animated off stage and the new
diff --git a/ash/assistant/assistant_interaction_controller_impl_unittest.cc b/ash/assistant/assistant_interaction_controller_impl_unittest.cc
index 3737ce5..00f0afe 100644
--- a/ash/assistant/assistant_interaction_controller_impl_unittest.cc
+++ b/ash/assistant/assistant_interaction_controller_impl_unittest.cc
@@ -12,13 +12,17 @@
 #include "ash/assistant/model/assistant_interaction_model_observer.h"
 #include "ash/assistant/model/assistant_response.h"
 #include "ash/assistant/model/assistant_response_observer.h"
+#include "ash/assistant/model/ui/assistant_card_element.h"
 #include "ash/assistant/model/ui/assistant_error_element.h"
 #include "ash/assistant/model/ui/assistant_ui_element.h"
 #include "ash/assistant/test/assistant_ash_test_base.h"
+#include "ash/assistant/ui/assistant_view_ids.h"
 #include "ash/assistant/ui/main_stage/assistant_error_element_view.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
 #include "ash/public/cpp/assistant/controller/assistant_suggestions_controller.h"
 #include "ash/test/fake_android_intent_helper.h"
+#include "ash/test/test_ash_web_view.h"
 #include "base/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
@@ -100,6 +104,16 @@
   }
 };
 
+AssistantCardElement* GetAssistantCardElement(
+    const std::vector<std::unique_ptr<AssistantUiElement>>& ui_elements) {
+  if (ui_elements.size() != 1lu ||
+      ui_elements.front()->type() != AssistantUiElementType::kCard) {
+    return nullptr;
+  }
+
+  return static_cast<AssistantCardElement*>(ui_elements.front().get());
+}
+
 }  // namespace
 
 TEST_F(AssistantInteractionControllerImplTest,
@@ -253,4 +267,75 @@
 
   EXPECT_NEAR(actual.InSeconds(), expected.InSeconds(), 1);
 }
+
+TEST_F(AssistantInteractionControllerImplTest, CompactBubbleLauncher) {
+  static constexpr int kStandardLayoutAshWebViewWidth = 592;
+  static constexpr int kNarrowLayoutAshWebViewWidth = 496;
+
+  base::test::ScopedFeatureList scoped_feature_list(
+      app_list_features::kCompactBubbleLauncher);
+
+  UpdateDisplay("1200x800");
+  ShowAssistantUi();
+  StartInteraction();
+
+  interaction_controller()->OnHtmlResponse("<html></html>", "fallback");
+
+  base::RunLoop().RunUntilIdle();
+
+  AssistantCardElement* card_element = GetAssistantCardElement(
+      interaction_controller()->GetModel()->response()->GetUiElements());
+  ASSERT_TRUE(card_element);
+  EXPECT_EQ(card_element->viewport_width(), 638);
+  EXPECT_EQ(
+      page_view()->GetViewByID(AssistantViewID::kAshWebView)->size().width(),
+      kStandardLayoutAshWebViewWidth);
+
+  ASSERT_TRUE(page_view()->GetViewByID(AssistantViewID::kAshWebView) !=
+              nullptr);
+  TestAshWebView* ash_web_view = static_cast<TestAshWebView*>(
+      page_view()->GetViewByID(AssistantViewID::kAshWebView));
+  // max_size and min_size in AshWebView::InitParams are different from the view
+  // size. min_size affects to the size of rendered content, i.e. renderer will
+  // try to render the content to the size. But View::Size() doesn't.
+  ASSERT_TRUE(ash_web_view->init_params_for_testing().max_size);
+  ASSERT_TRUE(ash_web_view->init_params_for_testing().min_size);
+  EXPECT_EQ(ash_web_view->init_params_for_testing().max_size.value().width(),
+            kStandardLayoutAshWebViewWidth);
+  EXPECT_EQ(ash_web_view->init_params_for_testing().min_size.value().width(),
+            kStandardLayoutAshWebViewWidth);
+
+  CloseAssistantUi();
+
+  // Change work area width < 1200 and confirm that the viewport width gets
+  // updated to narrow layout one.
+  UpdateDisplay("1199x800");
+  ShowAssistantUi();
+  StartInteraction();
+
+  interaction_controller()->OnHtmlResponse("<html></html>", "fallback");
+
+  base::RunLoop().RunUntilIdle();
+
+  card_element = GetAssistantCardElement(
+      interaction_controller()->GetModel()->response()->GetUiElements());
+  ASSERT_TRUE(card_element);
+  ASSERT_TRUE(page_view()->GetViewByID(AssistantViewID::kAshWebView) !=
+              nullptr);
+  EXPECT_EQ(card_element->viewport_width(), 542);
+  EXPECT_EQ(
+      page_view()->GetViewByID(AssistantViewID::kAshWebView)->size().width(),
+      kNarrowLayoutAshWebViewWidth);
+
+  ASSERT_TRUE(page_view()->GetViewByID(AssistantViewID::kAshWebView) !=
+              nullptr);
+  ash_web_view = static_cast<TestAshWebView*>(
+      page_view()->GetViewByID(AssistantViewID::kAshWebView));
+  ASSERT_TRUE(ash_web_view->init_params_for_testing().max_size);
+  ASSERT_TRUE(ash_web_view->init_params_for_testing().min_size);
+  EXPECT_EQ(ash_web_view->init_params_for_testing().max_size.value().width(),
+            kNarrowLayoutAshWebViewWidth);
+  EXPECT_EQ(ash_web_view->init_params_for_testing().min_size.value().width(),
+            kNarrowLayoutAshWebViewWidth);
+}
 }  // namespace ash
diff --git a/ash/assistant/assistant_ui_controller_impl.cc b/ash/assistant/assistant_ui_controller_impl.cc
index 62470929..43d0b47 100644
--- a/ash/assistant/assistant_ui_controller_impl.cc
+++ b/ash/assistant/assistant_ui_controller_impl.cc
@@ -152,6 +152,10 @@
       weak_factory_for_delayed_visibility_changes_.GetWeakPtr(), exit_point));
 }
 
+void AssistantUiControllerImpl::SetAppListBubbleWidth(int width) {
+  model_.SetAppListBubbleWidth(width);
+}
+
 void AssistantUiControllerImpl::ToggleUi(
     absl::optional<AssistantEntryPoint> entry_point,
     absl::optional<AssistantExitPoint> exit_point) {
diff --git a/ash/assistant/assistant_ui_controller_impl.h b/ash/assistant/assistant_ui_controller_impl.h
index 1a09822..d346d116 100644
--- a/ash/assistant/assistant_ui_controller_impl.h
+++ b/ash/assistant/assistant_ui_controller_impl.h
@@ -66,6 +66,7 @@
                 absl::optional<AssistantExitPoint> exit_point) override;
   absl::optional<base::ScopedClosureRunner> CloseUi(
       AssistantExitPoint exit_point) override;
+  void SetAppListBubbleWidth(int width) override;
 
   // AssistantInteractionModelObserver:
   void OnInputModalityChanged(InputModality input_modality) override;
diff --git a/ash/assistant/model/DEPS b/ash/assistant/model/DEPS
index 545bcaa..97b2397 100644
--- a/ash/assistant/model/DEPS
+++ b/ash/assistant/model/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "-ash",
   "+ash/assistant/ui/assistant_ui_constants.h",
+  "+ash/assistant/ui/assistant_view_ids.h",
   "+ash/assistant/model",
   "+ash/public/cpp",
   "+ash/public/cpp/app_list",
diff --git a/ash/assistant/model/assistant_ui_model.cc b/ash/assistant/model/assistant_ui_model.cc
index 1de1240..37c74bd3 100644
--- a/ash/assistant/model/assistant_ui_model.cc
+++ b/ash/assistant/model/assistant_ui_model.cc
@@ -72,6 +72,10 @@
   NotifyKeyboardTraversalModeChanged();
 }
 
+void AssistantUiModel::SetAppListBubbleWidth(int width) {
+  app_list_bubble_width_ = width;
+}
+
 void AssistantUiModel::SetVisibility(
     AssistantVisibility visibility,
     absl::optional<AssistantEntryPoint> entry_point,
diff --git a/ash/assistant/model/assistant_ui_model.h b/ash/assistant/model/assistant_ui_model.h
index baca690..dfb11a0c 100644
--- a/ash/assistant/model/assistant_ui_model.h
+++ b/ash/assistant/model/assistant_ui_model.h
@@ -7,6 +7,7 @@
 
 #include <ostream>
 
+#include "ash/assistant/ui/assistant_ui_constants.h"
 #include "base/component_export.h"
 #include "base/observer_list.h"
 #include "chromeos/services/assistant/public/cpp/assistant_service.h"
@@ -92,6 +93,9 @@
   // Returns the current keyboard traversal mode.
   bool keyboard_traversal_mode() const { return keyboard_traversal_mode_; }
 
+  int AppListBubbleWidth() const { return app_list_bubble_width_; }
+  void SetAppListBubbleWidth(int width);
+
  private:
   void SetVisibility(AssistantVisibility visibility,
                      absl::optional<AssistantEntryPoint> entry_point,
@@ -108,6 +112,7 @@
   AssistantUiMode ui_mode_ = AssistantUiMode::kLauncherEmbeddedUi;
   AssistantVisibility visibility_ = AssistantVisibility::kClosed;
   AssistantEntryPoint entry_point_ = AssistantEntryPoint::kUnspecified;
+  int app_list_bubble_width_ = kPreferredWidthDip;
 
   mutable base::ObserverList<AssistantUiModelObserver> observers_;
 
diff --git a/ash/assistant/model/ui/assistant_card_element.cc b/ash/assistant/model/ui/assistant_card_element.cc
index d0d5324629..e3d4efd 100644
--- a/ash/assistant/model/ui/assistant_card_element.cc
+++ b/ash/assistant/model/ui/assistant_card_element.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "ash/assistant/ui/assistant_ui_constants.h"
+#include "ash/assistant/ui/assistant_view_ids.h"
 #include "ash/public/cpp/ash_web_view_factory.h"
 #include "base/base64.h"
 
@@ -31,11 +32,12 @@
   }
 
   void Process() {
-    // TODO(dmblack): Find a better way of determining desired card size.
-    const int width_dip =
-        kPreferredWidthDip - 2 * assistant::ui::GetHorizontalMargin();
+    const int width_dip = card_element_->viewport_width() -
+                          2 * assistant::ui::GetHorizontalMargin();
 
-    // Configure parameters for the card.
+    // Configure parameters for the card. We want to configure the size as:
+    // - width: It should be width_dip.
+    // - height: It should be calculated from the content.
     AshWebView::InitParams contents_params;
     contents_params.enable_auto_resize = true;
     contents_params.min_size = gfx::Size(width_dip, 1);
@@ -45,6 +47,7 @@
     // Create |contents_view_| and retain ownership until it is added to the
     // view hierarchy. If that never happens, it will be still be cleaned up.
     contents_view_ = AshWebViewFactory::Get()->Create(contents_params);
+    contents_view_->SetID(AssistantViewID::kAshWebView);
 
     // Observe |contents_view_| so that we are notified when loading is
     // complete.
@@ -80,10 +83,12 @@
 // AssistantCardElement --------------------------------------------------------
 
 AssistantCardElement::AssistantCardElement(const std::string& html,
-                                           const std::string& fallback)
+                                           const std::string& fallback,
+                                           int viewport_width)
     : AssistantUiElement(AssistantUiElementType::kCard),
       html_(html),
-      fallback_(fallback) {}
+      fallback_(fallback),
+      viewport_width_(viewport_width) {}
 
 AssistantCardElement::~AssistantCardElement() {
   // |processor_| should be destroyed before |this| has been deleted.
diff --git a/ash/assistant/model/ui/assistant_card_element.h b/ash/assistant/model/ui/assistant_card_element.h
index 8e40212e..63e37aa 100644
--- a/ash/assistant/model/ui/assistant_card_element.h
+++ b/ash/assistant/model/ui/assistant_card_element.h
@@ -19,8 +19,9 @@
 class COMPONENT_EXPORT(ASSISTANT_MODEL) AssistantCardElement
     : public AssistantUiElement {
  public:
-  explicit AssistantCardElement(const std::string& html,
-                                const std::string& fallback);
+  AssistantCardElement(const std::string& html,
+                       const std::string& fallback,
+                       int viewport_width);
 
   AssistantCardElement(const AssistantCardElement&) = delete;
   AssistantCardElement& operator=(const AssistantCardElement&) = delete;
@@ -33,6 +34,7 @@
   bool has_contents_view() const;
   const std::string& html() const { return html_; }
   const std::string& fallback() const { return fallback_; }
+  int viewport_width() const { return viewport_width_; }
   std::unique_ptr<AshWebView> MoveContentsView() {
     return std::move(contents_view_);
   }
@@ -46,6 +48,7 @@
 
   const std::string html_;
   const std::string fallback_;
+  const int viewport_width_;
   std::unique_ptr<AshWebView> contents_view_;
 
   std::unique_ptr<Processor> processor_;
diff --git a/ash/assistant/ui/BUILD.gn b/ash/assistant/ui/BUILD.gn
index bec87982..c2c14f5 100644
--- a/ash/assistant/ui/BUILD.gn
+++ b/ash/assistant/ui/BUILD.gn
@@ -13,6 +13,7 @@
   sources = [
     "assistant_ui_constants.cc",
     "assistant_ui_constants.h",
+    "assistant_view_ids.h",
   ]
 
   deps = [
@@ -30,7 +31,6 @@
 
   sources = [
     "assistant_view_delegate.h",
-    "assistant_view_ids.h",
     "assistant_web_container_view.cc",
     "assistant_web_container_view.h",
     "assistant_web_view_delegate.h",
diff --git a/ash/assistant/ui/assistant_ui_constants.cc b/ash/assistant/ui/assistant_ui_constants.cc
index 946da7e..9c744ee 100644
--- a/ash/assistant/ui/assistant_ui_constants.cc
+++ b/ash/assistant/ui/assistant_ui_constants.cc
@@ -21,7 +21,10 @@
 }
 
 int GetHorizontalMargin() {
-  return features::IsProductivityLauncherEnabled() ? 24 : 32;
+  // Expected margin for productivity launcher case is 24. But
+  // AppListBubbleAssistantPage is shifted by 1px, i.e. has 1px margin. See
+  // b/233384263 for details.
+  return features::IsProductivityLauncherEnabled() ? 23 : 32;
 }
 
 int GetHorizontalPadding() {
diff --git a/ash/assistant/ui/assistant_ui_constants.h b/ash/assistant/ui/assistant_ui_constants.h
index bd08a28..2b39134 100644
--- a/ash/assistant/ui/assistant_ui_constants.h
+++ b/ash/assistant/ui/assistant_ui_constants.h
@@ -17,6 +17,8 @@
 namespace ash {
 
 // Appearance.
+// TODO(b/233386078): Usage of kPreferredWidthDip is discouraged as it can
+// change
 constexpr int kPreferredWidthDip = 640;
 constexpr int kSpacingDip = 8;
 constexpr int kMarginDip = 8;
diff --git a/ash/assistant/ui/assistant_view_ids.h b/ash/assistant/ui/assistant_view_ids.h
index fd0d066c..a2a6ab5 100644
--- a/ash/assistant/ui/assistant_view_ids.h
+++ b/ash/assistant/ui/assistant_view_ids.h
@@ -45,6 +45,7 @@
 
   // UIs in UiElementContainer
   kOverflowIndicator,
+  kAshWebView,
 
   // UIs in AssistantOnboardingSuggestionView
   kAssistantOnboardingSuggestionViewLabel,
diff --git a/ash/assistant/ui/main_stage/assistant_card_element_view.cc b/ash/assistant/ui/main_stage/assistant_card_element_view.cc
index 87c0d2d..d1f8fef 100644
--- a/ash/assistant/ui/main_stage/assistant_card_element_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_card_element_view.cc
@@ -80,6 +80,10 @@
 }
 
 ui::Layer* AssistantCardElementView::GetLayerForAnimating() {
+  // native_view() can be nullptr if this runs in unit test.
+  if (!native_view())
+    return nullptr;
+
   return native_view()->layer();
 }
 
@@ -88,6 +92,10 @@
 }
 
 void AssistantCardElementView::AddedToWidget() {
+  // native_view() can be nullptr if this runs in unit test.
+  if (!native_view())
+    return;
+
   aura::Window* const top_level_window = native_view()->GetToplevelWindow();
 
   // Find the window for the Assistant card.
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc
index bc3909a9..416dea4b 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -224,6 +224,14 @@
 
   // Add the view to the hierarchy and prepare its animation layer for entry.
   auto* view_ptr = content_view()->AddChildView(std::move(view));
+
+  // If this runs in test, AssistantCardElement can use TestAshWebView. It does
+  // not return a native view. We cannot obtain a layer for animation. We want
+  // to add it to the UI tree as a test is going to interact with it. But we
+  // skip an animation.
+  if (is_card && !view_ptr->GetLayerForAnimating())
+    return nullptr;
+
   view_ptr->GetLayerForAnimating()->SetOpacity(0.f);
 
   // Return the animator that will be used to animate the view.
diff --git a/ash/public/cpp/assistant/controller/assistant_ui_controller.h b/ash/public/cpp/assistant/controller/assistant_ui_controller.h
index df4d505..1100a5a 100644
--- a/ash/public/cpp/assistant/controller/assistant_ui_controller.h
+++ b/ash/public/cpp/assistant/controller/assistant_ui_controller.h
@@ -51,6 +51,11 @@
   virtual absl::optional<base::ScopedClosureRunner> CloseUi(
       chromeos::assistant::AssistantExitPoint) = 0;
 
+  // Sets current AppListBubbleWidth. AssistantCardElement needs to know the
+  // width of AppListBubbleWidth to render its html content.
+  // AssistantCardElement will take the value via AssistantUiModel.
+  virtual void SetAppListBubbleWidth(int width) = 0;
+
  protected:
   AssistantUiController();
   virtual ~AssistantUiController();
diff --git a/ash/system/network/managed_sim_lock_notifier.cc b/ash/system/network/managed_sim_lock_notifier.cc
index 044bd406..0b3b1ee3 100644
--- a/ash/system/network/managed_sim_lock_notifier.cc
+++ b/ash/system/network/managed_sim_lock_notifier.cc
@@ -24,6 +24,17 @@
 
 const char kNotifierManagedSimLock[] = "ash.managed-simlock";
 
+chromeos::network_config::mojom::DeviceStatePropertiesPtr
+GetCellularDeviceIfExists(
+    std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr>&
+        devices) {
+  for (auto& device : devices) {
+    if (device->type == chromeos::network_config::mojom::NetworkType::kCellular)
+      return std::move(device);
+  }
+  return nullptr;
+}
+
 }  // namespace
 
 // static
@@ -50,6 +61,49 @@
   }
 }
 
+void ManagedSimLockNotifier::OnDeviceStateListChanged() {
+  remote_cros_network_config_->GetDeviceStateList(
+      base::BindOnce(&ManagedSimLockNotifier::OnGetDeviceStateList,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ManagedSimLockNotifier::OnGetDeviceStateList(
+    std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr>
+        devices) {
+  chromeos::network_config::mojom::DeviceStatePropertiesPtr cellular_device =
+      GetCellularDeviceIfExists(devices);
+
+  // Remove Notification and reset |primary_iccid_| if no cellular device or
+  // the cellular device is currently not enabled.
+  if (!cellular_device ||
+      cellular_device->device_state !=
+          chromeos::network_config::mojom::DeviceStateType::kEnabled) {
+    primary_iccid_.clear();
+    RemoveNotification();
+    return;
+  }
+
+  // If the SIM Lock setting is disabled, remove notification.
+  if (!cellular_device->sim_lock_status->lock_enabled) {
+    RemoveNotification();
+    return;
+  }
+
+  // If the primary SIM changes, check if the restrict SIM Lock Global Network
+  // Configuration is enabled. If it is, identify the primary cellular network,
+  // and surface the notification if the SIM lock setting is enabled.
+  for (const auto& sim_info : *cellular_device->sim_infos) {
+    if (!sim_info->is_primary)
+      continue;
+    std::string old_primary_iccid = primary_iccid_;
+    primary_iccid_ = sim_info->iccid;
+    if (primary_iccid_ != old_primary_iccid)
+      CheckGlobalNetworkConfiguration();
+
+    return;
+  }
+}
+
 void ManagedSimLockNotifier::OnPoliciesApplied(const std::string& userhash) {
   CheckGlobalNetworkConfiguration();
 }
@@ -101,6 +155,10 @@
             // When clicked, open the SIM Unlock dialog in Cellular settings if
             // we can open WebUI settings, otherwise do nothing.
             if (TrayPopupUtils::CanOpenWebUISettings()) {
+              // TODO(b/228093904): Using GUID of network, take user to cellular
+              // details page with dialog open. Change dialog logic so that if
+              // the SIM is currently locked, entering the PIN will unlock the
+              // SIM and disable the PIN lock setting.
               Shell::Get()
                   ->system_tray_model()
                   ->client()
diff --git a/ash/system/network/managed_sim_lock_notifier.h b/ash/system/network/managed_sim_lock_notifier.h
index 9e3c0eef..201b640e 100644
--- a/ash/system/network/managed_sim_lock_notifier.h
+++ b/ash/system/network/managed_sim_lock_notifier.h
@@ -14,12 +14,8 @@
 
 namespace ash {
 
-// Notifies the user to unlock the currently active PIN locked SIM.
-// TODO(b/228093904): Surface notification if active network changes to network
-// with SIM locked and policy is set to true.
-// TODO(b/228093904): Remove notification if user successfully unlocks SIM.
-// TODO(b/228093904): Remove notification if active network changes to network
-// without SIM locked and policy is set to true.
+// Notifies the user to unlock the currently active PIN locked SIM if the
+// restrict cellular SIM lock Global Network Configuration is set to true.
 class ASH_EXPORT ManagedSimLockNotifier
     : public SessionObserver,
       public chromeos::network_config::mojom::CrosNetworkConfigObserver {
@@ -43,11 +39,14 @@
   void OnNetworkStateChanged(
       chromeos::network_config::mojom::NetworkStatePropertiesPtr network)
       override {}
-  void OnDeviceStateListChanged() override {}
+  void OnDeviceStateListChanged() override;
   void OnVpnProvidersChanged() override {}
   void OnNetworkCertificatesChanged() override {}
   void OnPoliciesApplied(const std::string& userhash) override;
 
+  void OnGetDeviceStateList(
+      std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr>
+          devices);
   void OnCellularNetworksList(
       std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>
           networks);
@@ -61,6 +60,7 @@
 
   static const char kManagedSimLockNotificationId[];
 
+  std::string primary_iccid_ = std::string();
   mojo::Remote<chromeos::network_config::mojom::CrosNetworkConfig>
       remote_cros_network_config_;
   mojo::Receiver<chromeos::network_config::mojom::CrosNetworkConfigObserver>
diff --git a/ash/system/network/managed_sim_lock_notifier_unittest.cc b/ash/system/network/managed_sim_lock_notifier_unittest.cc
index abdd536be..bb6750c 100644
--- a/ash/system/network/managed_sim_lock_notifier_unittest.cc
+++ b/ash/system/network/managed_sim_lock_notifier_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_handler_test_helper.h"
+#include "chromeos/network/network_state_handler.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
@@ -67,6 +68,13 @@
     return NetworkHandler::Get()->managed_network_configuration_handler();
   }
 
+  void SetCellularEnabled(bool enabled) {
+    NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled(
+        NetworkTypePattern::Cellular(), enabled,
+        network_handler::ErrorCallback());
+    base::RunLoop().RunUntilIdle();
+  }
+
   void SetCellularSimLockEnabled(bool enable) {
     // Simulate a locked SIM.
     base::Value sim_lock_status(base::Value::Type::DICTIONARY);
@@ -214,4 +222,66 @@
   EXPECT_FALSE(GetManagedSimLockNotification());
 }
 
+TEST_F(ManagedSimLockNotifierTest, HideNotificationOnLockDisabled) {
+  AddCellularDevice();
+  AddCellularService();
+  SetCellularSimLockEnabled(true);
+  SetAllowCellularSimLock(false);
+
+  EXPECT_TRUE(GetManagedSimLockNotification());
+
+  // Notification will disappear once user disables SIM Lock setting.
+  SetCellularSimLockEnabled(false);
+  EXPECT_FALSE(GetManagedSimLockNotification());
+}
+
+TEST_F(ManagedSimLockNotifierTest, PrimarySimIccidChanged) {
+  AddCellularDevice();
+  AddCellularService();
+  SetCellularSimLockEnabled(true);
+  SetAllowCellularSimLock(false);
+
+  EXPECT_TRUE(GetManagedSimLockNotification());
+  RemoveNotification();
+
+  EXPECT_FALSE(GetManagedSimLockNotification());
+  // Simulate primary ICCID changed. Notification should be shown after.
+  base::Value::ListStorage sim_slot_infos;
+  base::Value slot_info_item(base::Value::Type::DICTIONARY);
+  slot_info_item.SetKey(shill::kSIMSlotInfoICCID, base::Value(kTestIccid));
+  slot_info_item.SetBoolKey(shill::kSIMSlotInfoPrimary, false);
+  sim_slot_infos.push_back(std::move(slot_info_item));
+
+  base::Value slot_info_item_2(base::Value::Type::DICTIONARY);
+  slot_info_item_2.SetKey(shill::kSIMSlotInfoICCID, base::Value("kTestIccid2"));
+  slot_info_item_2.SetBoolKey(shill::kSIMSlotInfoPrimary, true);
+  sim_slot_infos.push_back(std::move(slot_info_item_2));
+
+  network_config_helper_->network_state_helper()
+      .device_test()
+      ->SetDeviceProperty(kTestCellularDevicePath, shill::kSIMSlotInfoProperty,
+                          base::Value(sim_slot_infos), /*notify_changed=*/true);
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(GetManagedSimLockNotification());
+}
+
+TEST_F(ManagedSimLockNotifierTest, NotificationOnCellularOnOrOff) {
+  AddCellularDevice();
+  AddCellularService();
+  SetCellularSimLockEnabled(true);
+  SetAllowCellularSimLock(false);
+
+  EXPECT_TRUE(GetManagedSimLockNotification());
+
+  // Notification will disappear if user turns off Cellular.
+  SetCellularEnabled(false);
+  EXPECT_FALSE(GetManagedSimLockNotification());
+
+  // Notification will appear if user turns on Cellular.
+  SetCellularEnabled(true);
+  EXPECT_TRUE(GetManagedSimLockNotification());
+}
+
 }  // namespace ash
diff --git a/ash/test/test_ash_web_view.cc b/ash/test/test_ash_web_view.cc
index 5dd6e0ee..a7b5311 100644
--- a/ash/test/test_ash_web_view.cc
+++ b/ash/test/test_ash_web_view.cc
@@ -10,7 +10,8 @@
 
 namespace ash {
 
-TestAshWebView::TestAshWebView() = default;
+TestAshWebView::TestAshWebView(const AshWebView::InitParams& init_params)
+    : init_params_(init_params) {}
 
 TestAshWebView::~TestAshWebView() = default;
 
diff --git a/ash/test/test_ash_web_view.h b/ash/test/test_ash_web_view.h
index 5cc754e..e86c675 100644
--- a/ash/test/test_ash_web_view.h
+++ b/ash/test/test_ash_web_view.h
@@ -16,7 +16,7 @@
 // An implementation of AshWebView for use in unittests.
 class TestAshWebView : public AshWebView {
  public:
-  TestAshWebView();
+  explicit TestAshWebView(const AshWebView::InitParams& init_params);
   ~TestAshWebView() override;
 
   TestAshWebView(const TestAshWebView&) = delete;
@@ -32,9 +32,14 @@
   void RequestFocus() override;
   bool HasFocus() const override;
 
+  const AshWebView::InitParams& init_params_for_testing() const {
+    return init_params_;
+  }
+
  private:
   base::ObserverList<Observer> observers_;
   bool focused_ = false;
+  AshWebView::InitParams init_params_;
 
   base::WeakPtrFactory<TestAshWebView> weak_factory_{this};
 };
diff --git a/ash/test/test_ash_web_view_factory.cc b/ash/test/test_ash_web_view_factory.cc
index 9671339..c2c0dd0 100644
--- a/ash/test/test_ash_web_view_factory.cc
+++ b/ash/test/test_ash_web_view_factory.cc
@@ -14,7 +14,7 @@
 
 std::unique_ptr<AshWebView> TestAshWebViewFactory::Create(
     const AshWebView::InitParams& params) {
-  return std::make_unique<TestAshWebView>();
+  return std::make_unique<TestAshWebView>(params);
 }
 
 }  // namespace ash
diff --git a/ash/webui/personalization_app/BUILD.gn b/ash/webui/personalization_app/BUILD.gn
index c3e1cc8..f25079dc 100644
--- a/ash/webui/personalization_app/BUILD.gn
+++ b/ash/webui/personalization_app/BUILD.gn
@@ -27,6 +27,7 @@
 
   deps = [
     "search:mojo_bindings",
+    "//ash",
     "//ash/constants:constants",
     "//ash/public/cpp",
     "//ash/webui/personalization_app/mojom",
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc
index 0e48749..724eb73 100644
--- a/ash/webui/personalization_app/personalization_app_ui.cc
+++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -6,6 +6,8 @@
 
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ambient/ambient_client.h"
+#include "ash/rgb_keyboard/rgb_keyboard_manager.h"
+#include "ash/shell.h"
 #include "ash/webui/grit/ash_personalization_app_resources.h"
 #include "ash/webui/grit/ash_personalization_app_resources_map.h"
 #include "ash/webui/personalization_app/personalization_app_ambient_provider.h"
@@ -255,7 +257,10 @@
 
   source->AddBoolean("isAmbientModeAllowed", IsAmbientModeAllowed());
 
-  source->AddBoolean("isRgbKeyboardEnabled", features::IsRgbKeyboardEnabled());
+  source->AddBoolean(
+      "isRgbKeyboardSupported",
+      features::IsRgbKeyboardEnabled() &&
+          Shell::Get()->rgb_keyboard_manager()->IsRgbKeyboardSupported());
 }
 
 }  // namespace
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
index f32dfef3..6616ae2 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
+++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
@@ -64,7 +64,7 @@
       </ambient-preview>
     </template>
   </div>
-  <template is="dom-if" if="[[isRgbKeyboardEnabled_()]]">
+  <template is="dom-if" if="[[isRgbKeyboardSupported_()]]">
     <keyboard-backlight></keyboard-backlight>
   </template>
 </div>
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
index 6fb4ad5..6eb752c 100644
--- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
@@ -42,8 +42,8 @@
     return isAmbientModeAllowed();
   }
 
-  private isRgbKeyboardEnabled_(): boolean {
-    return loadTimeData.getBoolean('isRgbKeyboardEnabled');
+  private isRgbKeyboardSupported_(): boolean {
+    return loadTimeData.getBoolean('isRgbKeyboardSupported');
   }
 
   private onClickAmbientSubpageLink_() {
diff --git a/ash/webui/shimless_rma/resources/onboarding_network_page.js b/ash/webui/shimless_rma/resources/onboarding_network_page.js
index fa01f1b..077237b 100644
--- a/ash/webui/shimless_rma/resources/onboarding_network_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_network_page.js
@@ -107,7 +107,7 @@
       },
 
       /**
-       * Set to true to show the 'connect' button instead of 'disconnect'.
+       * Tracks whether network shows connect button or disconnect button.
        * @protected
        */
       networkShowConnect_: {
@@ -315,10 +315,7 @@
    * @protected
    */
   getDialogTitle_() {
-    // TODO(gavindodd): Is disconnect ever needed? Currently it is not used as
-    // networkShowConnect_ is always true.
     if (this.networkName_ && !this.networkShowConnect_) {
-      // TODO(gavindodd): Confirm other i18n strings don't need HTMLEscape
       return this.i18n('internetConfigName', HTMLEscape(this.networkName_));
     }
     const type = this.i18n('OncType' + this.networkType_);
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
index 22c63fb7..c2531fbb 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
+++ b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
@@ -160,7 +160,7 @@
     .gradient {
       background-image: linear-gradient(to bottom,
         rgba(255,255,255,0), rgba(255,255,255,1));
-      bottom: calc(var(--header-footer-height) + var(--content-container-padding));
+      bottom: calc(var(--header-footer-height) + var(--container-vertical-padding));
       height: 40px;
       position: fixed;
     }
diff --git a/ash/wm/desks/desks_textfield.cc b/ash/wm/desks/desks_textfield.cc
index f02b82d..ce2cd11 100644
--- a/ash/wm/desks/desks_textfield.cc
+++ b/ash/wm/desks/desks_textfield.cc
@@ -15,7 +15,6 @@
 #include "ui/views/accessibility/accessibility_paint_checks.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/focus_ring.h"
-#include "ui/views/native_cursor.h"
 
 namespace ash {
 
@@ -120,8 +119,8 @@
   UpdateFocusRingState();
 }
 
-gfx::NativeCursor DesksTextfield::GetCursor(const ui::MouseEvent& event) {
-  return views::GetNativeIBeamCursor();
+ui::Cursor DesksTextfield::GetCursor(const ui::MouseEvent& event) {
+  return ui::mojom::CursorType::kIBeam;
 }
 
 void DesksTextfield::OnFocus() {
diff --git a/ash/wm/desks/desks_textfield.h b/ash/wm/desks/desks_textfield.h
index fa923f2..1507427d 100644
--- a/ash/wm/desks/desks_textfield.h
+++ b/ash/wm/desks/desks_textfield.h
@@ -42,7 +42,7 @@
   void OnMouseEntered(const ui::MouseEvent& event) override;
   void OnMouseExited(const ui::MouseEvent& event) override;
   void OnThemeChanged() override;
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void OnFocus() override;
   void OnBlur() override;
   void OnDragEntered(const ui::DropTargetEvent& event) override;
diff --git a/ash/wm/desks/templates/saved_desk_presenter.cc b/ash/wm/desks/templates/saved_desk_presenter.cc
index c2ee4a2..fc2efef 100644
--- a/ash/wm/desks/templates/saved_desk_presenter.cc
+++ b/ash/wm/desks/templates/saved_desk_presenter.cc
@@ -195,7 +195,6 @@
   auto desk_template_clone = desk_template->Clone();
 
   // Save or update `desk_template` as an entry in DeskModel.
-  weak_ptr_factory_.InvalidateWeakPtrs();
   GetDeskModel()->AddOrUpdateEntry(
       std::move(desk_template),
       base::BindOnce(&SavedDeskPresenter::OnAddOrUpdateEntry,
@@ -225,8 +224,6 @@
   if (status != desks_storage::DeskModel::GetAllEntriesStatus::kOk)
     return;
 
-  DCHECK_EQ(GetEntryCount(), entries.size());
-
   // This updates `should_show_templates_ui_`.
   UpdateDesksTemplatesUI();
 
diff --git a/ash/wm/desks/templates/saved_desk_test_util.cc b/ash/wm/desks/templates/saved_desk_test_util.cc
index 2e455d0..447b9e1 100644
--- a/ash/wm/desks/templates/saved_desk_test_util.cc
+++ b/ash/wm/desks/templates/saved_desk_test_util.cc
@@ -84,6 +84,11 @@
   presenter_->on_update_ui_closure_for_testing_ = std::move(closure);
 }
 
+void SavedDeskPresenterTestApi::MaybeWaitForModel() {
+  if (presenter_->weak_ptr_factory_.HasWeakPtrs())
+    WaitForDesksTemplatesUI();
+}
+
 SavedDeskLibraryViewTestApi::SavedDeskLibraryViewTestApi(
     SavedDeskLibraryView* library_view)
     : library_view_(library_view) {}
@@ -146,14 +151,18 @@
   return grid_items;
 }
 
-SavedDeskItemView* GetItemViewFromTemplatesGrid(int grid_item_index) {
-  const auto* overview_grid = GetPrimaryOverviewGrid();
-  if (!overview_grid)
-    return nullptr;
+SavedDeskItemView* GetItemViewFromTemplatesGrid(size_t grid_item_index) {
+  auto* overview_grid = GetPrimaryOverviewGrid();
+  DCHECK(overview_grid);
+
+  SavedDeskPresenterTestApi(
+      overview_grid->overview_session()->saved_desk_presenter())
+      .MaybeWaitForModel();
 
   auto grid_items = GetItemViewsFromDeskLibrary(overview_grid);
-  SavedDeskItemView* item_view = grid_items.at(grid_item_index);
+  DCHECK_LT(grid_item_index, grid_items.size());
 
+  SavedDeskItemView* item_view = grid_items[grid_item_index];
   DCHECK(item_view);
   return item_view;
 }
diff --git a/ash/wm/desks/templates/saved_desk_test_util.h b/ash/wm/desks/templates/saved_desk_test_util.h
index 4280ccc..3ead912 100644
--- a/ash/wm/desks/templates/saved_desk_test_util.h
+++ b/ash/wm/desks/templates/saved_desk_test_util.h
@@ -44,6 +44,10 @@
 
   void SetOnUpdateUiClosure(base::OnceClosure closure);
 
+  // If there are outstanding operations on the desk model, this blocks until
+  // they are done.
+  void MaybeWaitForModel();
+
  private:
   SavedDeskPresenter* const presenter_;
 };
@@ -152,7 +156,7 @@
 
 // Return the `grid_item_index`th `SavedDeskItemView` from the first
 // `OverviewGrid`'s `SavedDeskGridView` in `GetOverviewGridList()`.
-SavedDeskItemView* GetItemViewFromTemplatesGrid(int grid_item_index);
+SavedDeskItemView* GetItemViewFromTemplatesGrid(size_t grid_item_index);
 
 // These buttons are the ones on the primary root window.
 views::Button* GetZeroStateDesksTemplatesButton();
diff --git a/ash/wm/desks/templates/saved_desk_unittest.cc b/ash/wm/desks/templates/saved_desk_unittest.cc
index da68d7b..2e44483 100644
--- a/ash/wm/desks/templates/saved_desk_unittest.cc
+++ b/ash/wm/desks/templates/saved_desk_unittest.cc
@@ -3000,8 +3000,10 @@
       /*grid_item_index=*/1);
   // Show replace dialogs.
   auto* dialog_controller = saved_desk_util::GetSavedDeskDialogController();
-  auto callback = base::BindLambdaForTesting(
-      [&]() { item_view->ReplaceTemplate(uuid_1.AsLowercaseString()); });
+  auto callback = base::BindLambdaForTesting([&]() {
+    item_view->name_view()->SetText(base::UTF8ToUTF16(name_1));
+    item_view->ReplaceTemplate(uuid_1.AsLowercaseString());
+  });
 
   dialog_controller->ShowReplaceDialog(
       Shell::GetPrimaryRootWindow(), base::UTF8ToUTF16(name_1),
@@ -3015,10 +3017,19 @@
       ->AsDialogDelegate()
       ->AcceptDialog();
 
+  WaitForDesksTemplatesUI();
+
   // Only one template left.
   EXPECT_EQ(1ul, desk_model()->GetEntryCount());
+
+  // And we expect one template in the UI.
+  OverviewGrid* overview_grid = GetOverviewGridList()[0].get();
+  const std::vector<SavedDeskItemView*> grid_items =
+      GetItemViewsFromDeskLibrary(overview_grid);
+  EXPECT_EQ(1u, grid_items.size());
+
   // The Template has been replaced.
-  SavedDeskNameView* name_view = GetItemViewFromTemplatesGrid(0)->name_view();
+  SavedDeskNameView* name_view = grid_items[0]->name_view();
   EXPECT_EQ(base::UTF8ToUTF16(name_1), name_view->GetText());
   std::vector<const DeskTemplate*> entries = GetAllEntries();
   EXPECT_EQ(uuid_2, entries[0]->uuid());
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e8bd097d..31133823 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1006,8 +1006,6 @@
 
     if (!is_nacl && !is_apple) {
       sources += [
-        "cpu_affinity_posix.cc",
-        "cpu_affinity_posix.h",
         "profiler/stack_copier_signal.cc",
         "profiler/stack_copier_signal.h",
         "profiler/stack_sampler_posix.cc",
@@ -3507,7 +3505,6 @@
     ]
     if (!is_nacl && !is_apple) {
       sources += [
-        "cpu_affinity_posix_unittest.cc",
         "profiler/stack_copier_signal_unittest.cc",
         "profiler/thread_delegate_posix_unittest.cc",
       ]
diff --git a/base/cpu_affinity_posix.cc b/base/cpu_affinity_posix.cc
deleted file mode 100644
index d230da8..0000000
--- a/base/cpu_affinity_posix.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/cpu_affinity_posix.h"
-
-#include <sched.h>
-
-#include "base/cpu.h"
-#include "base/process/internal_linux.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace base {
-
-namespace {
-
-const cpu_set_t& AllCores() {
-  static const cpu_set_t kAllCores = []() {
-    cpu_set_t set;
-    CPU_ZERO(&set);
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty()) {
-      memset(&set, 0xff, sizeof(set));
-    } else {
-      for (size_t index = 0; index < core_types.size(); index++)
-        CPU_SET(index, &set);
-    }
-    return set;
-  }();
-  return kAllCores;
-}
-
-const cpu_set_t& LittleCores() {
-  static const cpu_set_t kLittleCores = []() {
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty())
-      return AllCores();
-
-    cpu_set_t set;
-    CPU_ZERO(&set);
-    for (size_t core_index = 0; core_index < core_types.size(); core_index++) {
-      switch (core_types[core_index]) {
-        case CPU::CoreType::kUnknown:
-        case CPU::CoreType::kOther:
-        case CPU::CoreType::kSymmetric:
-          // In the presence of an unknown core type or symmetric architecture,
-          // fall back to allowing all cores.
-          return AllCores();
-        case CPU::CoreType::kBigLittle_Little:
-        case CPU::CoreType::kBigLittleBigger_Little:
-          CPU_SET(core_index, &set);
-          break;
-        case CPU::CoreType::kBigLittle_Big:
-        case CPU::CoreType::kBigLittleBigger_Big:
-        case CPU::CoreType::kBigLittleBigger_Bigger:
-          break;
-      }
-    }
-    return set;
-  }();
-  return kLittleCores;
-}
-
-const cpu_set_t& BigCores() {
-  static const cpu_set_t kBigCores = []() {
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty())
-      return AllCores();
-
-    cpu_set_t set;
-    CPU_ZERO(&set);
-    for (size_t core_index = 0; core_index < core_types.size(); core_index++) {
-      switch (core_types[core_index]) {
-        case CPU::CoreType::kUnknown:
-        case CPU::CoreType::kOther:
-        case CPU::CoreType::kSymmetric:
-          // In the presence of an unknown core type or symmetric architecture,
-          // fall back to allowing all cores.
-          return AllCores();
-        case CPU::CoreType::kBigLittle_Little:
-        case CPU::CoreType::kBigLittleBigger_Little:
-          break;
-        case CPU::CoreType::kBigLittle_Big:
-        case CPU::CoreType::kBigLittleBigger_Big:
-        case CPU::CoreType::kBigLittleBigger_Bigger:
-          CPU_SET(core_index, &set);
-          break;
-      }
-    }
-    return set;
-  }();
-  return kBigCores;
-}
-
-const cpu_set_t& BiggerCores() {
-  static const cpu_set_t kBiggerCores = []() {
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty())
-      return AllCores();
-
-    cpu_set_t set;
-    CPU_ZERO(&set);
-    for (size_t core_index = 0; core_index < core_types.size(); core_index++) {
-      switch (core_types[core_index]) {
-        case CPU::CoreType::kUnknown:
-        case CPU::CoreType::kOther:
-        case CPU::CoreType::kSymmetric:
-          // In the presence of an unknown core type or symmetric architecture,
-          // fall back to allowing all cores.
-          return AllCores();
-        case CPU::CoreType::kBigLittle_Little:
-        case CPU::CoreType::kBigLittleBigger_Little:
-        case CPU::CoreType::kBigLittle_Big:
-        case CPU::CoreType::kBigLittleBigger_Big:
-          break;
-        case CPU::CoreType::kBigLittleBigger_Bigger:
-          CPU_SET(core_index, &set);
-          break;
-      }
-    }
-    return set;
-  }();
-  return kBiggerCores;
-}
-
-}  // anonymous namespace
-
-bool HasBigCpuCores() {
-  static const bool kHasBigCores = []() {
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty())
-      return false;
-    for (CPU::CoreType core_type : core_types) {
-      switch (core_type) {
-        case CPU::CoreType::kUnknown:
-        case CPU::CoreType::kOther:
-        case CPU::CoreType::kSymmetric:
-          return false;
-        case CPU::CoreType::kBigLittle_Little:
-        case CPU::CoreType::kBigLittleBigger_Little:
-        case CPU::CoreType::kBigLittle_Big:
-        case CPU::CoreType::kBigLittleBigger_Big:
-        case CPU::CoreType::kBigLittleBigger_Bigger:
-          return true;
-      }
-    }
-    return false;
-  }();
-  return kHasBigCores;
-}
-
-bool HasBiggerCpuCores() {
-  static const bool kHasBiggerCores = []() {
-    const std::vector<CPU::CoreType>& core_types = CPU::GetGuessedCoreTypes();
-    if (core_types.empty())
-      return false;
-    for (CPU::CoreType core_type : core_types) {
-      switch (core_type) {
-        case CPU::CoreType::kUnknown:
-        case CPU::CoreType::kOther:
-        case CPU::CoreType::kSymmetric:
-          return false;
-        case CPU::CoreType::kBigLittle_Little:
-        case CPU::CoreType::kBigLittleBigger_Little:
-        case CPU::CoreType::kBigLittle_Big:
-        case CPU::CoreType::kBigLittleBigger_Big:
-          continue;
-        case CPU::CoreType::kBigLittleBigger_Bigger:
-          return true;
-      }
-    }
-    return false;
-  }();
-  return kHasBiggerCores;
-}
-
-bool SetThreadCpuAffinityMode(PlatformThreadId thread_id,
-                              CpuAffinityMode affinity) {
-  int result = 0;
-  switch (affinity) {
-    case CpuAffinityMode::kDefault: {
-      const cpu_set_t& all_cores = AllCores();
-      result = sched_setaffinity(thread_id, sizeof(all_cores), &all_cores);
-      break;
-    }
-    case CpuAffinityMode::kLittleCoresOnly: {
-      const cpu_set_t& little_cores = LittleCores();
-      result =
-          sched_setaffinity(thread_id, sizeof(little_cores), &little_cores);
-      break;
-    }
-    case CpuAffinityMode::kBigCoresOnly: {
-      const cpu_set_t& big_cores = BigCores();
-      result = sched_setaffinity(thread_id, sizeof(big_cores), &big_cores);
-      break;
-    }
-    case CpuAffinityMode::kBiggerCoresOnly: {
-      const cpu_set_t& bigger_cores = BiggerCores();
-      result =
-          sched_setaffinity(thread_id, sizeof(bigger_cores), &bigger_cores);
-      break;
-    }
-  }
-  return result == 0;
-}
-
-bool SetProcessCpuAffinityMode(ProcessHandle process_handle,
-                               CpuAffinityMode affinity) {
-  bool any_threads = false;
-  bool result = true;
-
-  internal::ForEachProcessTask(
-      process_handle, [&any_threads, &result, affinity](
-                          PlatformThreadId tid, const FilePath& /*task_path*/) {
-        any_threads = true;
-        result &= SetThreadCpuAffinityMode(tid, affinity);
-      });
-
-  return any_threads && result;
-}
-
-absl::optional<CpuAffinityMode> CurrentThreadCpuAffinityMode() {
-  if (HasBigCpuCores()) {
-    cpu_set_t set;
-    sched_getaffinity(PlatformThread::CurrentId(), sizeof(set), &set);
-    if (CPU_EQUAL(&set, &AllCores()))
-      return CpuAffinityMode::kDefault;
-    if (CPU_EQUAL(&set, &LittleCores()))
-      return CpuAffinityMode::kLittleCoresOnly;
-    if (CPU_EQUAL(&set, &BigCores()))
-      return CpuAffinityMode::kBigCoresOnly;
-    if (CPU_EQUAL(&set, &BiggerCores()))
-      return CpuAffinityMode::kBiggerCoresOnly;
-  }
-  return absl::nullopt;
-}
-
-}  // namespace base
diff --git a/base/cpu_affinity_posix.h b/base/cpu_affinity_posix.h
deleted file mode 100644
index b456d539..0000000
--- a/base/cpu_affinity_posix.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_CPU_AFFINITY_POSIX_H_
-#define BASE_CPU_AFFINITY_POSIX_H_
-
-#include "base/base_export.h"
-#include "base/process/process_handle.h"
-#include "base/threading/platform_thread.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace base {
-
-enum class CpuAffinityMode {
-  // No restrictions on affinity.
-  kDefault,
-  // Restrict execution to LITTLE cores only. Only has an effect on platforms
-  // where we detect presence of big.LITTLE-like CPU architectures.
-  kLittleCoresOnly,
-  // Restrict execution to big cores only. Only has an effect on platforms
-  // where we detect presence of big.LITTLE-like CPU architectures.
-  kBigCoresOnly,
-  // Restrict execution to bigger cores only. Only has an effect on platforms
-  // where we detect presence of big.LITTLE-like CPU architectures. If there
-  // are no bigger cores but there are big cores it will return an empty set.
-  kBiggerCoresOnly,
-};
-
-// Sets or clears restrictions on the CPU affinity of the specified thread.
-// Returns false if updating the affinity failed.
-BASE_EXPORT bool SetThreadCpuAffinityMode(PlatformThreadId thread_id,
-                                          CpuAffinityMode affinity);
-// Like SetThreadAffinityMode, but affects all current and future threads of
-// the given process. Note that this may not apply to threads that are created
-// in parallel to the execution of this function.
-BASE_EXPORT bool SetProcessCpuAffinityMode(ProcessHandle process_handle,
-                                           CpuAffinityMode affinity);
-
-// Return true if the current architecture has big or bigger cores.
-BASE_EXPORT bool HasBigCpuCores();
-
-// Return true if the current architecture has bigger cores.
-BASE_EXPORT bool HasBiggerCpuCores();
-
-// For architectures with big cores, return the affinity mode that matches
-// the CPU affinity of the current thread. If no affinity mode exactly matches,
-// or if the architecture doesn't have different types of cores,
-// return nullopt.
-BASE_EXPORT absl::optional<CpuAffinityMode> CurrentThreadCpuAffinityMode();
-
-}  // namespace base
-
-#endif  // BASE_CPU_AFFINITY_POSIX_H_
diff --git a/base/cpu_affinity_posix_unittest.cc b/base/cpu_affinity_posix_unittest.cc
deleted file mode 100644
index a364c3c..0000000
--- a/base/cpu_affinity_posix_unittest.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/cpu_affinity_posix.h"
-
-#include <sched.h>
-
-#include <string>
-
-#include "base/synchronization/waitable_event.h"
-#include "base/system/sys_info.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-
-namespace {
-
-class TestThread : public PlatformThread::Delegate {
- public:
-  TestThread()
-      : termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
-                           WaitableEvent::InitialState::NOT_SIGNALED),
-        terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
-                          WaitableEvent::InitialState::NOT_SIGNALED) {}
-  TestThread(const TestThread&) = delete;
-  TestThread& operator=(const TestThread&) = delete;
-  ~TestThread() override {
-    EXPECT_TRUE(terminate_thread_.IsSignaled())
-        << "Need to mark thread for termination and join the underlying thread "
-        << "before destroying a FunctionTestThread as it owns the "
-        << "WaitableEvent blocking the underlying thread's main.";
-  }
-
-  // Grabs |thread_id_|, signals |termination_ready_|, and then waits for
-  // |terminate_thread_| to be signaled before exiting.
-  void ThreadMain() override {
-    thread_id_ = PlatformThread::CurrentId();
-    EXPECT_NE(thread_id_, kInvalidThreadId);
-
-    // Make sure that the thread ID is the same across calls.
-    EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
-
-    termination_ready_.Signal();
-    terminate_thread_.Wait();
-
-    done_ = true;
-  }
-
-  PlatformThreadId thread_id() const {
-    EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
-    return thread_id_;
-  }
-
-  bool IsRunning() const { return termination_ready_.IsSignaled() && !done_; }
-
-  // Blocks until this thread is started and ready to be terminated.
-  void WaitForTerminationReady() { termination_ready_.Wait(); }
-
-  // Marks this thread for termination (callers must then join this thread to be
-  // guaranteed of termination).
-  void MarkForTermination() { terminate_thread_.Signal(); }
-
- private:
-  PlatformThreadId thread_id_ = kInvalidThreadId;
-
-  mutable WaitableEvent termination_ready_;
-  WaitableEvent terminate_thread_;
-  bool done_ = false;
-};
-
-}  // namespace
-
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_SetThreadCpuAffinityMode SetThreadCpuAffinityMode
-#else
-// The test only considers Android device hardware models at the moment. Some
-// CrOS devices on the waterfall have asymmetric CPUs that aren't covered. The
-// linux-trusty-rel bot also fails to sched_setaffinity().
-#define MAYBE_SetThreadCpuAffinityMode DISABLED_SetThreadCpuAffinityMode
-#endif
-TEST(CpuAffinityTest, MAYBE_SetThreadCpuAffinityMode) {
-  // This test currently only supports Nexus 5x and Pixel devices as big.LITTLE
-  // devices. For other devices, we assume that the cores are symmetric. This is
-  // currently the case for the devices on our waterfalls.
-  std::string device_model = SysInfo::HardwareModelName();
-  int expected_total_cores = SysInfo::SysInfo::NumberOfProcessors();
-  int expected_little_cores = expected_total_cores;
-  if (device_model == "Nexus 5X" || device_model == "Pixel 2" ||
-      device_model == "Pixel 2 XL" || device_model == "Pixel 3" ||
-      device_model == "Pixel 3 XL" || device_model == "Pixel 4" ||
-      device_model == "Pixel 4 XL") {
-    expected_little_cores = 4;
-    EXPECT_LT(expected_little_cores, expected_total_cores);
-  } else if (device_model == "Pixel" || device_model == "Pixel XL") {
-    expected_little_cores = 2;
-    EXPECT_LT(expected_little_cores, expected_total_cores);
-  } else if (device_model == "Pixel 3a" || device_model == "Pixel 3a XL") {
-    expected_little_cores = 6;
-    EXPECT_LT(expected_little_cores, expected_total_cores);
-  } else if (device_model == "Nexus 5" || device_model == "Nexus 7") {
-    // On our Nexus 5 and Nexus 7 bots, something else in the system seems to
-    // set affinity for the test process, making these tests flaky
-    // (crbug.com/1113964).
-    return;
-  }
-
-  TestThread thread;
-  PlatformThreadHandle handle;
-  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-  thread.WaitForTerminationReady();
-  ASSERT_TRUE(thread.IsRunning());
-
-  PlatformThreadId thread_id = thread.thread_id();
-  cpu_set_t set;
-
-  EXPECT_TRUE(
-      SetThreadCpuAffinityMode(thread_id, CpuAffinityMode::kLittleCoresOnly));
-  EXPECT_EQ(sched_getaffinity(thread_id, sizeof(set), &set), 0);
-
-  EXPECT_EQ(CPU_COUNT(&set), expected_little_cores);
-
-  EXPECT_TRUE(SetThreadCpuAffinityMode(thread_id, CpuAffinityMode::kDefault));
-  EXPECT_EQ(sched_getaffinity(thread_id, sizeof(set), &set), 0);
-
-  EXPECT_EQ(CPU_COUNT(&set), expected_total_cores);
-
-  thread.MarkForTermination();
-  PlatformThread::Join(handle);
-  ASSERT_FALSE(thread.IsRunning());
-}
-
-}  // namespace base
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 6fd132f..ad16a8a 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -464,6 +464,10 @@
         'com.google.common.flogger.backend.google.GooglePlatform',
         'com.google.common.flogger.backend.system.DefaultPlatform',
 
+        # trichrome_webview_google_bundle contains this missing reference.
+        # TODO(crbug.com/1142530): Fix this missing reference properly.
+        'org.chromium.build.NativeLibraries',
+
         # TODO(agrieve): Exclude these only when use_jacoco_coverage=true.
         'java.lang.instrument.ClassFileTransformer',
         'java.lang.instrument.IllegalClassFormatException',
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 6c119948..1a9b3736 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2133,7 +2133,6 @@
   #     uncompressed in the APK. Must be unset or true if load_library_from_apk
   #     is set to true.
   #   uncompress_dex: Store final .dex files uncompressed in the apk.
-  #   omit_dex: If true, do not build or include classes.dex.
   #   strip_resource_names: True if resource names should be stripped from the
   #     resources.arsc file in the apk or module.
   #   strip_unused_resources: True if unused resources should be stripped from
@@ -2216,7 +2215,6 @@
           defined(invoker.is_base_module) && invoker.is_base_module
     }
 
-    _omit_dex = defined(invoker.omit_dex) && invoker.omit_dex
     _enable_multidex =
         !defined(invoker.enable_multidex) || invoker.enable_multidex
 
@@ -2360,13 +2358,12 @@
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
     assert(_rebased_build_config != "")  # Mark as used.
 
-    _generate_buildconfig_java = !defined(invoker.apk_under_test) && !_omit_dex
+    _generate_buildconfig_java = !defined(invoker.apk_under_test)
     if (defined(invoker.generate_buildconfig_java)) {
       _generate_buildconfig_java = invoker.generate_buildconfig_java
     }
 
-    _generate_productconfig_java =
-        defined(invoker.product_config_java_packages) && !_omit_dex
+    _generate_productconfig_java = defined(invoker.product_config_java_packages)
 
     # JNI generation usually goes hand-in-hand with buildconfig generation.
     _generate_final_jni = _generate_buildconfig_java
@@ -2430,7 +2427,7 @@
       _incremental_apk_path = "${_final_apk_path_no_ext}_incremental.apk"
     }
 
-    if (!_incremental_apk && !_omit_dex) {
+    if (!_incremental_apk) {
       # Bundle modules don't build the dex here, but need to write this path
       # to their .build_config.json file.
       if (_proguard_enabled) {
@@ -2687,9 +2684,8 @@
     } else {
       _generate_native_libraries_java =
           (!_is_bundle_module || _is_base_module) &&
-          (_native_libs_deps != [] || _secondary_abi_native_libs_deps != [] ||
-           defined(invoker.static_library_provider)) &&
-          !_uses_static_library_synchronized_proguard && !_omit_dex
+          (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) &&
+          !_uses_static_library_synchronized_proguard
     }
     if (_generate_native_libraries_java) {
       write_native_libraries_java("${_template_name}__native_libraries") {
@@ -2698,17 +2694,7 @@
         # Do not add a dep on the generated_file target in order to avoid having
         # to build the native libraries before this target. The dependency is
         # instead captured via a depfile.
-        if (_uses_static_library) {
-          _prefix = get_label_info(invoker.static_library_provider,
-                                   "target_gen_dir") + "/" +
-                    get_label_info(invoker.static_library_provider, "name")
-          if (defined(invoker.static_library_provider_use_secondary_abi) &&
-              invoker.static_library_provider_use_secondary_abi) {
-            native_libraries_list_file = "${_prefix}.secondary_abi_native_libs"
-          } else {
-            native_libraries_list_file = "${_prefix}.native_libs"
-          }
-        } else if (_native_libs_deps != []) {
+        if (_native_libs_deps != []) {
           native_libraries_list_file = _shared_library_list_file
         } else {
           native_libraries_list_file = _secondary_abi_shared_library_list_file
@@ -2804,15 +2790,14 @@
                  ])
     }
 
+    _java_target = "${_template_name}__java"
+
     if (_is_bundle_module) {
       _add_view_trace_events =
           defined(invoker.add_view_trace_events) &&
           invoker.add_view_trace_events && enable_trace_event_bytecode_rewriting
     }
 
-    # We cannot skip this target when omit_dex = true because it writes the
-    # build_config.json.
-    _java_target = "${_template_name}__java"
     java_library_impl(_java_target) {
       forward_variables_from(invoker,
                              [
@@ -2944,7 +2929,7 @@
 
     if (_uses_static_library_synchronized_proguard) {
       _final_dex_target_dep = "${invoker.static_library_provider}__dexsplitter"
-    } else if ((_is_bundle_module && _proguard_enabled) || _omit_dex) {
+    } else if (_is_bundle_module && _proguard_enabled) {
       _final_deps += [ ":$_java_target" ]
     } else if (_incremental_apk) {
       if (defined(invoker.enable_proguard_checks)) {
@@ -3220,7 +3205,7 @@
         deps = _deps + [ ":$_build_config_target" ]
 
         if ((!_proguard_enabled || _incremental_apk) &&
-            enable_jdk_library_desugaring && !_omit_dex) {
+            enable_jdk_library_desugaring) {
           _all_jdk_libs = "//build/android:all_jdk_libs"
           deps += [ _all_jdk_libs ]
           jdk_libs_dex = get_label_info(_all_jdk_libs, "target_out_dir") +
@@ -3500,7 +3485,6 @@
                                "expected_libs_and_assets_base",
                                "generate_buildconfig_java",
                                "generate_final_jni",
-                               "generate_native_libraries_java",
                                "include_size_info",
                                "input_jars_paths",
                                "use_modern_linker",
@@ -3525,7 +3509,6 @@
                                "native_lib_placeholders",
                                "never_incremental",
                                "no_xml_namespaces",
-                               "omit_dex",
                                "png_to_webp",
                                "post_process_package_resources_script",
                                "processor_args_javac",
@@ -3550,7 +3533,6 @@
                                "srcjar_deps",
                                "static_library_dependent_targets",
                                "static_library_provider",
-                               "static_library_provider_use_secondary_abi",
                                "static_library_synchronized_proguard",
                                "target_sdk_version",
                                "testonly",
@@ -3650,7 +3632,6 @@
                                "load_library_from_apk",
                                "loadable_modules",
                                "product_config_java_packages",
-                               "main_component_library",
                                "manifest_package",
                                "max_sdk_version",
                                "min_sdk_version",
@@ -3679,7 +3660,6 @@
                                "short_resource_paths",
                                "srcjar_deps",
                                "static_library_provider",
-                               "static_library_provider_use_secondary_abi",
                                "static_library_synchronized_proguard",
                                "strip_resource_names",
                                "strip_unused_resources",
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index fc7f171..10d59a2 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-8.20220524.1.1
+8.20220524.3.1
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 3f57dbc..cfc0d60 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -179,6 +179,7 @@
   scoped_refptr<ElementAnimations> element_animations =
       GetElementAnimationsForElementId(element_id);
   if (element_animations) {
+    DCHECK(!element_animations->HasTickingKeyframeEffect());
     element_animations->RemoveKeyframeEffects();
   }
 }
@@ -187,6 +188,26 @@
                                                 Animation* animation) {
   DCHECK(element_id);
   DCHECK(animation);
+#if DCHECK_IS_ON()
+  for (const auto& keyframe_model :
+       animation->keyframe_effect()->keyframe_models()) {
+    KeyframeModel* cc_keyframe_model =
+        KeyframeModel::ToCcKeyframeModel(keyframe_model.get());
+    ElementId model_element_id = cc_keyframe_model->element_id()
+                                     ? cc_keyframe_model->element_id()
+                                     : element_id;
+    DCHECK(cc_keyframe_model->affects_active_elements() ||
+           cc_keyframe_model->affects_pending_elements());
+    DCHECK(!cc_keyframe_model->affects_active_elements() ||
+           mutator_host_client()->IsElementInPropertyTrees(
+               model_element_id, ElementListType::ACTIVE));
+    // Test thread_instance_ because LayerTreeHost has no pending tree.
+    DCHECK(thread_instance_ == ThreadInstance::MAIN ||
+           !cc_keyframe_model->affects_pending_elements() ||
+           mutator_host_client()->IsElementInPropertyTrees(
+               model_element_id, ElementListType::PENDING));
+  }
+#endif
 
   scoped_refptr<ElementAnimations> element_animations =
       GetElementAnimationsForElementId(element_id);
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 372a57aa..cf9021d 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1641,6 +1641,10 @@
   // Layer should now be registered by element id.
   EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
 
+  // We're expected to remove the animations before calling
+  // SetLayerTreeHost(nullptr).
+  animation_host_->RemoveAnimationTimeline(timeline);
+
   test_layer->SetLayerTreeHost(nullptr);
   // Layer should have been un-registered.
   EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 2c9748c5..ec26ebb2 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -1129,6 +1129,7 @@
       base::BindOnce(&LayerTreeTest::DoBeginTest, base::Unretained(this)));
 
   base::RunLoop().Run();
+  CleanupBeforeDestroy();
   DestroyLayerTreeHost();
 
   timeout_.Cancel();
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index f95399a..5d62ebd 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -149,6 +149,7 @@
     initial_root_bounds_ = bounds;
   }
 
+  virtual void CleanupBeforeDestroy() {}
   virtual void AfterTest() {}
   virtual void WillBeginTest();
   virtual void BeginTest() = 0;
diff --git a/cc/trees/draw_properties_unittest.cc b/cc/trees/draw_properties_unittest.cc
index ef08ec2..6534341 100644
--- a/cc/trees/draw_properties_unittest.cc
+++ b/cc/trees/draw_properties_unittest.cc
@@ -6650,6 +6650,7 @@
   std::unique_ptr<KeyframeModel> transform_animation(KeyframeModel::Create(
       std::move(curve), 3, 3,
       KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+  transform_animation->set_affects_pending_elements(false);
   scoped_refptr<Animation> animation(Animation::Create(1));
   timeline_impl()->AttachAnimation(animation);
   animation->AddKeyframeModel(std::move(transform_animation));
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 72b6505..08710fd 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1712,6 +1712,9 @@
 void LayerTreeHost::SetElementFilterMutated(ElementId element_id,
                                             ElementListType list_type,
                                             const FilterOperations& filters) {
+  if (list_type != ElementListType::ACTIVE)
+    return;
+
   if (IsUsingLayerLists()) {
     // In BlinkGenPropertyTrees/CompositeAfterPaint we always have property
     // tree nodes and can set the filter directly on the effect node.
@@ -1729,6 +1732,9 @@
     ElementId element_id,
     ElementListType list_type,
     const FilterOperations& backdrop_filters) {
+  if (list_type != ElementListType::ACTIVE)
+    return;
+
   if (IsUsingLayerLists()) {
     // In BlinkGenPropertyTrees/CompositeAfterPaint we always have property
     // tree nodes and can set the backdrop_filter directly on the effect node.
@@ -1748,6 +1754,9 @@
   DCHECK_GE(opacity, 0.f);
   DCHECK_LE(opacity, 1.f);
 
+  if (list_type != ElementListType::ACTIVE)
+    return;
+
   if (IsUsingLayerLists()) {
     property_trees()->effect_tree_mutable().OnOpacityAnimated(element_id,
                                                               opacity);
@@ -1775,6 +1784,9 @@
     ElementId element_id,
     ElementListType list_type,
     const gfx::Transform& transform) {
+  if (list_type != ElementListType::ACTIVE)
+    return;
+
   if (IsUsingLayerLists()) {
     property_trees()->transform_tree_mutable().OnTransformAnimated(element_id,
                                                                    transform);
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 50ff239..8dd6266c 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -60,6 +60,14 @@
     timeline_->AttachAnimation(animation_child_.get());
   }
 
+  void DetachAnimationsFromTimeline() {
+    if (animation_)
+      timeline_->DetachAnimation(animation_.get());
+    if (animation_child_)
+      timeline_->DetachAnimation(animation_child_.get());
+    animation_host()->RemoveAnimationTimeline(timeline_.get());
+  }
+
   void GetImplTimelineAndAnimationByID(const LayerTreeHostImpl& host_impl) {
     AnimationHost* animation_host_impl = GetImplAnimationHost(&host_impl);
     timeline_impl_ = animation_host_impl->GetTimelineById(timeline_id_);
@@ -71,6 +79,14 @@
     EXPECT_TRUE(animation_child_impl_);
   }
 
+  void CleanupBeforeDestroy() override {
+    // This needs to happen on the main thread (so can't happen in
+    // EndTest()), and needs to happen before DestroyLayerTreeHost()
+    // (which will trigger assertions if we don't do this), so it can't
+    // happen in AfterTest().
+    DetachAnimationsFromTimeline();
+  }
+
   AnimationHost* GetImplAnimationHost(
       const LayerTreeHostImpl* host_impl) const {
     return static_cast<AnimationHost*>(host_impl->mutator_host());
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index bd7131e..cf09cae3 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -567,6 +567,7 @@
     "//components/security_state/content/android:java",
     "//components/security_state/core:security_state_enums_java",
     "//components/segmentation_platform/public:public_java",
+    "//components/send_tab_to_self:send_tab_to_self_java",
     "//components/signin/core/browser:signin_enums_java",
     "//components/signin/public/android:java",
     "//components/site_engagement/content/android:java",
@@ -1622,6 +1623,7 @@
     "//components/security_interstitials/content/android:java",
     "//components/security_state/content/android:java",
     "//components/security_state/core:security_state_enums_java",
+    "//components/send_tab_to_self:send_tab_to_self_java",
     "//components/signin/core/browser:signin_enums_java",
     "//components/signin/public/android:java",
     "//components/signin/public/android:javatests",
@@ -2924,6 +2926,12 @@
   }
 }
 
+# TODO(agrieve): Remove this once we switch to using bundle targets to
+# generate APK stubs.
+android_resources("trichrome_dummy_resources") {
+  sources = [ "trichrome/res_dummy/values/strings.xml" ]
+}
+
 chrome_public_unit_test_apk_manifest =
     "$root_gen_dir/chrome_public_unit_test_apk_manifest/AndroidManifest.xml"
 chrome_public_test_apk_manifest =
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 87220dc..6fb71709 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -235,19 +235,6 @@
       use_chromium_linker = chromium_linker_supported
     }
 
-    if (_is_trichrome) {
-      static_library_provider_use_secondary_abi = _is_secondary_abi_primary
-
-      # http://crbug.com/1042107.
-      if (is_component_build) {
-        if (android_64bit_target_cpu && _is_64_bit_browser) {
-          main_component_library = "libmonochrome_64.cr.so"
-        } else {
-          main_component_library = "libmonochrome.cr.so"
-        }
-      }
-    }
-
     if (!_is_monochrome && !_is_trichrome) {
       deps += [
         "//chrome/android:chrome_public_v8_assets",
diff --git a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
index cb6d641c..fd2f714 100644
--- a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
@@ -10,7 +10,6 @@
   <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31"/>
   <application
       android:extractNativeLibs="false"
-      android:hasCode="false"
       android:icon="@drawable/icon_webview"
       android:label="Trichrome Library"
       android:multiArch="true"
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 070efc3..97e9ddd 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -18,7 +18,6 @@
 
     <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
     <application
-        android:hasCode="false"
         android:label="{{ application_label|default('Trichrome Library') }}"
         android:icon="@drawable/icon_webview"
         android:multiArch="true"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
index 37a27292..9af423e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -74,7 +74,7 @@
     private static final float EXTRA_HEIGHT_RATIO = 0.1f;
     private static final int SCROLL_DURATION_MS = 200;
     private static final int NAVBAR_FADE_DURATION_MS = 16;
-    private static final int SPINNER_FADE_DURATION_MS = 200;
+    private static final int SPINNER_FADE_DURATION_MS = 400;
 
     @IntDef({HeightStatus.TOP, HeightStatus.INITIAL_HEIGHT, HeightStatus.TRANSITION})
     @Retention(RetentionPolicy.SOURCE)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/SuggestionsTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/SuggestionsTileView.java
index 533b86e..8851486 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/SuggestionsTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/SuggestionsTileView.java
@@ -55,7 +55,6 @@
     public void renderIcon(Tile tile) {
         setIconDrawable(tile.getIcon());
         setIconViewLayoutParams(tile);
-        setIconTint(tile.getIconTint());
     }
 
     public void renderOfflineBadge(Tile tile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
index 7cb979bb..0f50ee54 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.suggestions.tile;
 
-import android.content.res.ColorStateList;
 import android.graphics.drawable.Drawable;
 
 import androidx.annotation.Nullable;
@@ -32,9 +31,6 @@
     private Drawable mIcon;
 
     @Nullable
-    private ColorStateList mIconTint;
-
-    @Nullable
     private Long mOfflinePageOfflineId;
 
     /**
@@ -156,17 +152,6 @@
         mIcon = icon;
     }
 
-    /**
-     * Updates the icon tint color.
-     */
-    public void setIconTint(@Nullable ColorStateList iconTint) {
-        mIconTint = iconTint;
-    }
-
-    public ColorStateList getIconTint() {
-        return mIconTint;
-    }
-
     @TileSectionType
     public int getSectionType() {
         return mSiteData.sectionType;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
index d3e4fbe..88901d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.suggestions.tile;
 
+import android.graphics.Bitmap;
 import android.util.SparseArray;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -28,6 +29,8 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsOfflineModelObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSites;
+import org.chromium.components.favicon.IconType;
+import org.chromium.components.favicon.LargeIconBridge;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 import org.chromium.url.GURL;
 
@@ -117,9 +120,9 @@
 
         /**
          * Returns a callback to be invoked when the icon for the provided tile is loaded. It will
-         * be responsible for triggering the visual refresh.
+         * be responsible for updating the tile data and triggering the visual refresh.
          */
-        Runnable createIconLoadCallback(Tile tile);
+        LargeIconBridge.LargeIconCallback createIconLoadCallback(Tile tile);
     }
 
     /**
@@ -219,16 +222,13 @@
         }
 
         @Override
-        public Runnable createIconLoadCallback(Tile tile) {
+        public LargeIconBridge.LargeIconCallback createIconLoadCallback(Tile tile) {
             // TODO(dgn): We could save on fetches by avoiding a new one when there is one pending
             // for the same URL, and applying the result to all matched URLs.
             boolean trackLoad =
                     isLoadTracked() && tile.getSectionType() == TileSectionType.PERSONALIZED;
             if (trackLoad) addTask(TileTask.FETCH_ICON);
-            return () -> {
-                mObserver.onTileIconChanged(tile);
-                if (trackLoad) removeTask(TileTask.FETCH_ICON);
-            };
+            return new LargeIconCallbackImpl(tile.getData(), trackLoad);
         }
     };
 
@@ -291,7 +291,8 @@
     @Override
     public void onIconMadeAvailable(GURL siteUrl) {
         for (Tile tile : findTilesForUrl(siteUrl)) {
-            mTileRenderer.updateIcon(tile, () -> mObserver.onTileIconChanged(tile));
+            mTileRenderer.updateIcon(tile.getData(),
+                    new LargeIconCallbackImpl(tile.getData(), /* trackLoadTask = */ false));
         }
     }
 
@@ -501,6 +502,37 @@
         mOfflineModelObserver.onDestroy();
     }
 
+    // TODO(dgn): I would like to move that to TileRenderer, but setting the data on the tile,
+    // notifying the observer and updating the tasks make it awkward.
+    private class LargeIconCallbackImpl implements LargeIconBridge.LargeIconCallback {
+        private final SiteSuggestion mSiteData;
+        private final boolean mTrackLoadTask;
+
+        private LargeIconCallbackImpl(SiteSuggestion suggestion, boolean trackLoadTask) {
+            mSiteData = suggestion;
+            mTrackLoadTask = trackLoadTask;
+        }
+
+        @Override
+        public void onLargeIconAvailable(@Nullable Bitmap icon, int fallbackColor,
+                boolean isFallbackColorDefault, @IconType int iconType) {
+            Tile tile = findTile(mSiteData);
+            if (tile != null) { // Do nothing if the tile was removed.
+                tile.setIconType(iconType);
+                if (icon == null) {
+                    mTileRenderer.setTileIconFromColor(tile, fallbackColor, isFallbackColorDefault);
+                } else {
+                    mTileRenderer.setTileIconFromBitmap(tile, icon);
+                }
+
+                mObserver.onTileIconChanged(tile);
+            }
+
+            // This call needs to be made after the tiles are completely initialised, for UMA.
+            if (mTrackLoadTask) removeTask(TileTask.FETCH_ICON);
+        }
+    }
+
     private class TileInteractionDelegateImpl
             implements TileInteractionDelegate, ContextMenuManager.Delegate {
         private final SiteSuggestion mSuggestion;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
index 5ac5ad7..7a7b9dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileRenderer.java
@@ -12,37 +12,28 @@
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 
-import androidx.annotation.DrawableRes;
 import androidx.annotation.LayoutRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
-import androidx.core.content.res.ResourcesCompat;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
 
 import org.chromium.base.TraceEvent;
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.base.task.PostTask;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge;
 import org.chromium.chrome.browser.explore_sites.ExploreSitesIPH;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.suggestions.ImageFetcher;
 import org.chromium.chrome.browser.suggestions.SiteSuggestion;
 import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle;
-import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.RoundedIconGenerator;
 import org.chromium.components.favicon.IconType;
 import org.chromium.components.favicon.LargeIconBridge;
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.Tracker;
-import org.chromium.components.search_engines.TemplateUrlService;
-import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.base.ViewUtils;
 
-import java.lang.ref.WeakReference;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -54,7 +45,7 @@
 public class TileRenderer {
     private static final String TAG = "TileRenderer";
 
-    private final Context mContext;
+    private final Resources mResources;
     private final RoundedIconGenerator mIconGenerator;
     private final Resources.Theme mTheme;
     private ImageFetcher mImageFetcher;
@@ -72,45 +63,17 @@
     @LayoutRes
     private final int mTopSitesLayout;
 
-    private class LargeIconCallbackImpl implements LargeIconBridge.LargeIconCallback {
-        private final WeakReference<Tile> mTile;
-        private final Runnable mLoadCompleteCallback;
-
-        private LargeIconCallbackImpl(Tile tile, Runnable loadCompleteCallback) {
-            mTile = new WeakReference<>(tile);
-            mLoadCompleteCallback = loadCompleteCallback;
-        }
-
-        @Override
-        public void onLargeIconAvailable(@Nullable Bitmap icon, int fallbackColor,
-                boolean isFallbackColorDefault, @IconType int iconType) {
-            Tile tile = mTile.get();
-            if (tile != null) { // Do nothing if the tile was removed.
-                tile.setIconType(iconType);
-                if (icon == null) {
-                    setTileIconFromColor(tile, fallbackColor, isFallbackColorDefault);
-                } else {
-                    setTileIconFromBitmap(tile, icon);
-                }
-                if (mLoadCompleteCallback != null) mLoadCompleteCallback.run();
-            }
-
-            mTile.clear();
-        }
-    }
-
     public TileRenderer(
             Context context, @TileStyle int style, int titleLines, ImageFetcher imageFetcher) {
         mImageFetcher = imageFetcher;
         mStyle = style;
         mTitleLinesCount = titleLines;
 
-        mContext = context;
-        Resources res = context.getResources();
+        mResources = context.getResources();
         mTheme = context.getTheme();
-        mDesiredIconSize = res.getDimensionPixelSize(R.dimen.tile_view_icon_size);
-        mIconCornerRadius = res.getDimension(R.dimen.tile_view_icon_corner_radius);
-        int minIconSize = res.getDimensionPixelSize(R.dimen.tile_view_icon_min_size);
+        mDesiredIconSize = mResources.getDimensionPixelSize(R.dimen.tile_view_icon_size);
+        mIconCornerRadius = mResources.getDimension(R.dimen.tile_view_icon_corner_radius);
+        int minIconSize = mResources.getDimensionPixelSize(R.dimen.tile_view_icon_min_size);
 
         // On ldpi devices, mDesiredIconSize could be even smaller than the global limit.
         mMinIconSize = Math.min(mDesiredIconSize, minIconSize);
@@ -119,7 +82,7 @@
         mTopSitesLayout = getTopSitesLayout();
 
         int iconColor = context.getColor(R.color.default_favicon_background_color);
-        int iconTextSize = res.getDimensionPixelSize(R.dimen.tile_view_icon_text_size);
+        int iconTextSize = mResources.getDimensionPixelSize(R.dimen.tile_view_icon_text_size);
         mIconGenerator = new RoundedIconGenerator(
                 mDesiredIconSize, mDesiredIconSize, mDesiredIconSize / 2, iconColor, iconTextSize);
     }
@@ -187,14 +150,14 @@
             tileView = (TopSitesTileView) LayoutInflater.from(parentView.getContext())
                                .inflate(mTopSitesLayout, parentView, false);
 
-            tile.setIcon(VectorDrawableCompat.create(
-                    mContext.getResources(), R.drawable.ic_apps_blue_24dp, mTheme));
+            tile.setIcon(
+                    VectorDrawableCompat.create(mResources, R.drawable.ic_apps_blue_24dp, mTheme));
             tile.setType(TileVisualType.ICON_DEFAULT);
 
             if (LibraryLoader.getInstance().isInitialized() && setupDelegate != null) {
                 // One task to load actual icon.
                 LargeIconBridge.LargeIconCallback bridgeCallback =
-                        new LargeIconCallbackImpl(tile, setupDelegate.createIconLoadCallback(tile));
+                        setupDelegate.createIconLoadCallback(tile);
                 ExploreSitesBridge.getSummaryImage(Profile.getLastUsedRegularProfile(),
                         mDesiredIconSize,
                         (Bitmap img)
@@ -215,7 +178,7 @@
         // Note: It is important that the callbacks below don't keep a reference to the tile or
         // modify them as there is no guarantee that the same tile would be used to update the view.
         if (mImageFetcher != null && tile.getSource() != TileSource.EXPLORE) {
-            updateIcon(tile, setupDelegate.createIconLoadCallback(tile));
+            fetchIcon(tile.getData(), setupDelegate.createIconLoadCallback(tile));
         }
 
         TileGroup.TileInteractionDelegate delegate = setupDelegate.createInteractionDelegate(tile);
@@ -237,21 +200,15 @@
         return tileView;
     }
 
-    public void updateIcon(final Tile tile, final Runnable iconCallback) {
-        TemplateUrlService searchService = TemplateUrlServiceFactory.get();
-        if (searchService != null
-                && searchService.isSearchResultsPageFromDefaultSearchProvider(tile.getData().url)) {
-            // We already have an icon, and could trigger the update instantly.
-            // Problem is, the TileView is likely not attached yet and the update would not be
-            // properly reflected. Yield.
-            PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
-                setTileIconFromRes(tile, R.drawable.ic_suggestion_magnifier);
-                iconCallback.run();
-            });
-        } else {
-            mImageFetcher.makeLargeIconRequest(tile.getData().url, mMinIconSize,
-                    new LargeIconCallbackImpl(tile, iconCallback));
-        }
+    private void fetchIcon(
+            final SiteSuggestion siteData, final LargeIconBridge.LargeIconCallback iconCallback) {
+            mImageFetcher.makeLargeIconRequest(siteData.url, mMinIconSize, iconCallback);
+            return;
+    }
+
+    public void updateIcon(
+            SiteSuggestion siteData, LargeIconBridge.LargeIconCallback iconCallback) {
+        mImageFetcher.makeLargeIconRequest(siteData.url, mMinIconSize, iconCallback);
     }
 
     public void setTileIconFromBitmap(Tile tile, Bitmap icon) {
@@ -260,21 +217,14 @@
             radius = mDesiredIconSize / 2;
         }
         RoundedBitmapDrawable roundedIcon =
-                ViewUtils.createRoundedBitmapDrawable(mContext.getResources(), icon, radius);
+                ViewUtils.createRoundedBitmapDrawable(mResources, icon, radius);
         roundedIcon.setAntiAlias(true);
         roundedIcon.setFilterBitmap(true);
 
         tile.setIcon(roundedIcon);
-        tile.setIconTint(null);
         tile.setType(TileVisualType.ICON_REAL);
     }
 
-    public void setTileIconFromRes(Tile tile, @DrawableRes int res) {
-        tile.setIcon(ResourcesCompat.getDrawable(mContext.getResources(), res, null));
-        tile.setIconTint(ChromeColors.getSecondaryIconTint(mContext, /* isIncognito= */ false));
-        tile.setType(TileVisualType.ICON_DEFAULT);
-    }
-
     public void setTileIconFromColor(Tile tile, int fallbackColor, boolean isFallbackColorDefault) {
         // Explore should not have generated icons.
         if (tile.getSource() == TileSource.EXPLORE) {
@@ -282,8 +232,7 @@
         }
         mIconGenerator.setBackgroundColor(fallbackColor);
         Bitmap icon = mIconGenerator.generateIconForUrl(tile.getUrl());
-        tile.setIcon(new BitmapDrawable(mContext.getResources(), icon));
-        tile.setIconTint(null);
+        tile.setIcon(new BitmapDrawable(mResources, icon));
         tile.setType(
                 isFallbackColorDefault ? TileVisualType.ICON_DEFAULT : TileVisualType.ICON_COLOR);
     }
diff --git a/chrome/android/proguard/trichrome.flags b/chrome/android/proguard/trichrome.flags
new file mode 100644
index 0000000..68fb39a
--- /dev/null
+++ b/chrome/android/proguard/trichrome.flags
@@ -0,0 +1,8 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(agrieve): Once this -keep is removed, add a @CheckDiscard to LibraryLoaderConfig.java.
+# Currently the Trichrome library just contains NativeLibraries, which we keep.
+# https://crbug.com/901465
+-keep class org.chromium.build.NativeLibraries { *; }
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni
index 1e2eec7..01b7f0b 100644
--- a/chrome/android/trichrome.gni
+++ b/chrome/android/trichrome.gni
@@ -114,7 +114,7 @@
       product_version_resources_dep =
           "//chrome/android:product_version_resources"
     } else {
-      omit_dex = true
+      generate_buildconfig_java = false
     }
 
     # TODO(torne): using icon_resources just to get a temporary icon
@@ -194,6 +194,37 @@
         }
       }
     }
+
+    # http://crbug.com/1042107.
+    if (is_component_build) {
+      if (android_64bit_target_cpu && invoker.is_64_bit_browser) {
+        main_component_library = "libmonochrome_64.cr.so"
+      } else {
+        main_component_library = "libmonochrome.cr.so"
+      }
+    }
+
+    if (!is_java_debug) {
+      proguard_enabled = true
+      proguard_configs = [
+        "//base/android/proguard/chromium_apk.flags",
+        "//base/android/proguard/chromium_code.flags",
+        "//chrome/android/proguard/trichrome.flags",
+      ]
+      if (trichrome_synchronized_proguard) {
+        proguard_configs += [
+          "//chrome/android/proguard/static_library_dex_reference_workarounds.flags",
+          "//base/android/proguard/enable_obfuscation.flags",
+        ]
+      } else {
+        # Disabling all obfuscation for the Trichrome library as a temporary
+        # workaround for crbug.com/1012842. There were naming conflicts between
+        # Library and Chrome, since each Proguard run doesn't know about the
+        # other, and thus handed out the first names (a, b, c) to both.
+        proguard_enable_obfuscation = false
+      }
+    }
+    deps += [ "//chrome/android:trichrome_dummy_resources" ]
   }
 }
 
diff --git a/chrome/android/trichrome/res_dummy/values/strings.xml b/chrome/android/trichrome/res_dummy/values/strings.xml
new file mode 100644
index 0000000..a0d71c24
--- /dev/null
+++ b/chrome/android/trichrome/res_dummy/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!-- DO NOT ADD MORE RESOURCES HERE -->
+<resources>
+    <string name="dummy"></string>
+</resources>
\ No newline at end of file
diff --git a/chrome/android/trichrome/static_library_shared_java_code.md b/chrome/android/trichrome/static_library_shared_java_code.md
new file mode 100644
index 0000000..a288902
--- /dev/null
+++ b/chrome/android/trichrome/static_library_shared_java_code.md
@@ -0,0 +1,100 @@
+# Static Library Java code
+
+[TOC]
+
+## Overview
+
+This document describes how static library targets can be used to share common
+Java code between multiple APKs. More detail can be found at
+[go/proguarding-trichrome](goto.google.com/proguarding-trichrome).
+
+## TrichromeLibrary
+
+Currently (Jan 2020) trichrome library is the only target to make use of static
+shared library APKs and is used to share common code used by both Chrome and
+Webview.
+
+## Status
+
+Java code sharing is mostly implemented at this point but there is one remaining
+blocker related to how
+[native method resolution works in Webview](crbug.com/1025009).
+
+## How it works
+
+### Build variables
+
+For `android_apk_or_module` base templates:
+
+`static_library_provider`: Specifies that this target depends on a static shared
+library APK. When synchronized proguard is turned on, the
+`static_library_provider` becomes the target that provides the final dex file.
+
+`static_library_dependent_targets`: If set, generates final dex files for
+itself and for all targets in the `static_library_dependent_targets` list.
+
+`static_library_synchronized_proguard`: Turns on synchronized proguard for
+targets that also set `static_library_provider`.
+
+### .build_config
+
+`write_build_config.py` is responsible for figuring out where code and related
+artifacts for the `static_library_provider` and
+`static_library_dependent_targets` belongs. The main difference from regular
+`.build_configs` is the mapping recording which input jars belong to each final
+dex file. Ex:
+
+```
+"deps_info": {
+  ...
+  "static_library_dependent_classpath_configs": {
+      "gen/android_webview/trichrome_webview_apk.build_config.json": [
+        "obj/android_webview/trichrome_webview_apk/trichrome_webview_apk.jar",
+        ...
+      ],
+      "gen/chrome/android/trichrome_chrome_bundle.build_config.json": [
+        "lib.java/chrome/android/app_hooks_java.jar",
+        ...
+      "gen/chrome/android/trichrome_library_apk.build_config.json": [
+        "lib.java/base/base_java.jar",
+        ...
+      ]
+      ...
+  }
+}
+```
+
+### Synchronized ProGuard
+
+TrichromeChromeBundle (base module) and TrichromeWebview do not have a final
+`dex` or `proguard` step. Instead the library APK creates a "fat" dex from the
+`.build_config.json:deps_info:java_runtime_classpath`.
+
+Then, the mapping of `.build_config.json` -> owned input jars stored in the
+`.build_config.json` is used by `dexsplitter` to generate final .dex files for
+TrichromeLibrary, TrichromeChrome, and TrichromeWebview.
+
+### Resources
+
+For Java code to be shared between Chrome and Webview in [Trichrome][trichrome],
+we ensure that Chrome and Webview use the same resource IDs. This requires a
+few adjustments to how resources are created.
+
+1. Webview's resources are compiled first without any changes.
+2. Chrome's resources are compiled second, but use the same resource IDs as
+   Webview when possible.
+3. When synchronized proguarding is turned on, the `R.java` files generated in
+   the previous step are discarded. The shared static library APK target
+   (trichrome library) takes the output `R.txt` files from the previous steps
+   and includes those resources in its own `R.java` generation.
+
+[trichrome]: /chrome/android/trichrome/static_library_shared_java_code.md
+
+### Usage
+
+* Building trichrome_chrome_bundle or trichrome_webview_apk (and various arch
+  variants) will ensure the correct library target is also built.
+* Using the generated wrapper script from the main APK is sufficient (no need
+  to explicitly install the library).
+  * `bin/trichrome_chrome_bundle run` will ensure TrichromeChromeBundle and
+    TrichromeLibrary are installed before launching Chrome.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 87a01366..7c93785 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1298,13 +1298,14 @@
     No thanks
   </message>
 
-  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE" desc="The title of the dialog that recommend apps to user">
+  <!-- TODO(crbug.com/1261902): Clean-up old strings once feature is launched. -->
+  <message name="IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_TITLE" desc="The title of the dialog that recommend apps to user">
     Find apps for work and play
   </message>
-  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION" desc="The description of the 'Recommend Apps' section">
+  <message name="IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_DESCRIPTION" desc="The description of the 'Recommend Apps' section">
     Get creative, be productive, and stay entertained with apps on the Google Play Store
   </message>
-  <message name="IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL" desc="The label on the button that selects all recommended apps">
+  <message name="IDS_LOGIN_RECOMMEND_APPS_OLD_SELECT_ALL" desc="The label on the button that selects all recommended apps">
     Select all
   </message>
   <message name="IDS_LOGIN_RECOMMEND_APPS_DO_IT_LATER" desc="The label on the button that skips installing any recomended apps">
@@ -1313,9 +1314,35 @@
   <message name="IDS_LOGIN_RECOMMEND_APPS_DONE" desc="The label on the button that installs the user selected apps">
     Done
   </message>
+
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE" desc="The title of the dialog that recommend apps to user">
+    Install apps for your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> from the Google Play Store
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION" desc="The description of the 'Recommend Apps' section">
+    Find the apps you need, from productivity to entertainment, on the Google Play Store. You can install apps anytime.
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL" desc="The label on the button that selects all recommended apps">
+    Select and install popular apps
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_IN_APP_PURCHASES" desc="Part of an app description message.">
+    In-app purchases
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_WAS_INSTALLED" desc="Part of an app description message.">
+    Installed on your other devices
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_CONTAINS_ADS" desc="Part of an app description message.">
+    Contains ads
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_SKIP" desc="The label on the button that skips installing any recomended apps">
+    Skip
+  </message>
+  <message name="IDS_LOGIN_RECOMMEND_APPS_INSTALL" desc="The label on the button that installs the user selected apps">
+    Install
+  </message>
   <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_LOADING" desc="Message shown while the recommended app list is being downloaded.">
     Please wait...
   </message>
+
   <message name="IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE" desc="The title of the dialog that tells the user the selected Android Apps are downloading.">
     Apps downloading
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_INSTALL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_INSTALL.png.sha1
new file mode 100644
index 0000000..93133f24
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_INSTALL.png.sha1
@@ -0,0 +1 @@
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..0cc2a51
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+36fe7f57d35c6338aedd6333120aa6e975d6be9a
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_TITLE.png.sha1
new file mode 100644
index 0000000..0cc2a51
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_TITLE.png.sha1
@@ -0,0 +1 @@
+36fe7f57d35c6338aedd6333120aa6e975d6be9a
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SELECT_ALL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SELECT_ALL.png.sha1
new file mode 100644
index 0000000..0cc2a51
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_OLD_SELECT_ALL.png.sha1
@@ -0,0 +1 @@
+36fe7f57d35c6338aedd6333120aa6e975d6be9a
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_CONTAINS_ADS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_CONTAINS_ADS.png.sha1
new file mode 100644
index 0000000..93133f24
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_CONTAINS_ADS.png.sha1
@@ -0,0 +1 @@
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION.png.sha1
index 1c1fd44..93133f24 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION.png.sha1
@@ -1 +1 @@
-36fe7f57d35c6338aedd6333120aa6e975d6be9a
\ No newline at end of file
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_IN_APP_PURCHASES.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_IN_APP_PURCHASES.png.sha1
new file mode 100644
index 0000000..93133f24
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_IN_APP_PURCHASES.png.sha1
@@ -0,0 +1 @@
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE.png.sha1
index 1c1fd44..93133f24 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE.png.sha1
@@ -1 +1 @@
-36fe7f57d35c6338aedd6333120aa6e975d6be9a
\ No newline at end of file
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_WAS_INSTALLED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_WAS_INSTALLED.png.sha1
new file mode 100644
index 0000000..93133f24
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SCREEN_WAS_INSTALLED.png.sha1
@@ -0,0 +1 @@
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL.png.sha1
index 1c1fd44..93133f24 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL.png.sha1
@@ -1 +1 @@
-36fe7f57d35c6338aedd6333120aa6e975d6be9a
\ No newline at end of file
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SKIP.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SKIP.png.sha1
new file mode 100644
index 0000000..93133f24
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOGIN_RECOMMEND_APPS_SKIP.png.sha1
@@ -0,0 +1 @@
+11e3419ffb8ed98e0caeeadf24e84c884e97b85d
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3351342..f1183085 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2565,6 +2565,10 @@
                desc="Label for the Delete button on the blocked download bubble subpage.">
         Delete
       </message>
+      <message name="IDS_DOWNLOAD_BUBBLE_RESUME"
+               desc="Label for the button prompting to resume a paused download">
+        Resume
+      </message>
       <message name="IDS_DOWNLOAD_BUBBLE_SCAN"
                desc="Label for the button prompting for Deep Scanning">
         Scan
@@ -4896,6 +4900,19 @@
         <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUTTON_TOOLTIP_MULTIPLE_EXTENSIONS" desc="The tooltip text of the request access button that appears on the toolbar when an extension requests access to the site">
           Requesting to read and change <ph name="ORIGIN">$1<ex>google.com</ex></ph>:
         </message>
+        <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_SINGLE_EXTENSION_TITLE" desc="The title of the request access bubble to tell the user to accept the bubble to always run the extension on the site.">
+          Always allow "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>" to run on <ph name="ORIGIN">$2<ex>google.com</ex></ph>?
+        </message>
+        <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_MULTIPLE_EXTENSIONS_TITLE" desc="The title of the request access bubble to tell the user to accept the bubble to always run the extensions on the site.">
+          Always allow these extensions to run on <ph name="ORIGIN">$1<ex>google.com</ex></ph>?
+        </message>
+        <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_OK_BUTTON_LABEL" desc="The label of the button to allow the extension(s) to run on the site.">
+          Always allow
+        </message>
+        <message name="IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_CANCEL_BUTTON_LABEL" desc="The label of the button to don't allow the extension(s) to run on the site.">
+          No thanks
+        </message>
+
         <if expr="not use_titlecase">
           <message name="IDS_EXTENSIONS_CONTEXT_MENU_CANT_ACCESS_PAGE" desc="The label in an extension's context menu indicating the extension cannot access the current page. (sentence case)">
             Can't read or change site's data
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_RESUME.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_RESUME.png.sha1
new file mode 100644
index 0000000..26c9fef9
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_RESUME.png.sha1
@@ -0,0 +1 @@
+4953b8b3de7a2d2bf4b74da36d8ecbe927f74f85
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_CANCEL_BUTTON_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_CANCEL_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..0ee9c50f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_CANCEL_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+736c2b36025d9d1c6b092c89c96c5d642286c7c8
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_MULTIPLE_EXTENSIONS_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_MULTIPLE_EXTENSIONS_TITLE.png.sha1
new file mode 100644
index 0000000..1e6bb886
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_MULTIPLE_EXTENSIONS_TITLE.png.sha1
@@ -0,0 +1 @@
+5e2995b256c98bd2bbfd964668465c864db058bb
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_OK_BUTTON_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_OK_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..0ee9c50f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_OK_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+736c2b36025d9d1c6b092c89c96c5d642286c7c8
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_SINGLE_EXTENSION_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_SINGLE_EXTENSION_TITLE.png.sha1
new file mode 100644
index 0000000..0ee9c50f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_SINGLE_EXTENSION_TITLE.png.sha1
@@ -0,0 +1 @@
+736c2b36025d9d1c6b092c89c96c5d642286c7c8
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 31f47b7..5e7b89d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5013,10 +5013,6 @@
      flag_descriptions::kOmniboxPedalsAndroidBatch1Name,
      flag_descriptions::kOmniboxPedalsAndroidBatch1Description, kOsAndroid,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxPedalsAndroidBatch1)},
-    {"omnibox-pedals-batch3-nonenglish",
-     flag_descriptions::kOmniboxPedalsBatch3NonEnglishName,
-     flag_descriptions::kOmniboxPedalsBatch3NonEnglishDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxPedalsBatch3NonEnglish)},
 #endif  // BUILDFLAG(IS_ANDROID)
 
     {"omnibox-on-focus-suggestions-contextual-web",
@@ -5071,10 +5067,6 @@
      flag_descriptions::kOmniboxShortBookmarkSuggestionsName,
      flag_descriptions::kOmniboxShortBookmarkSuggestionsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kShortBookmarkSuggestions)},
-    {"omnibox-pedals-batch3-nonenglish",
-     flag_descriptions::kOmniboxPedalsBatch3NonEnglishName,
-     flag_descriptions::kOmniboxPedalsBatch3NonEnglishDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxPedalsBatch3NonEnglish)},
     {"omnibox-drive-suggestions",
      flag_descriptions::kOmniboxDriveSuggestionsName,
      flag_descriptions::kOmniboxDriveSuggestionsDescriptions, kOsDesktop,
@@ -7363,12 +7355,6 @@
      flag_descriptions::kQuickCommandsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kQuickCommands)},
 
-    {"desktop-restructured-language-settings",
-     flag_descriptions::kDesktopRestructuredLanguageSettingsName,
-     flag_descriptions::kDesktopRestructuredLanguageSettingsDescription,
-     kOsDesktop,
-     FEATURE_VALUE_TYPE(language::kDesktopRestructuredLanguageSettings)},
-
     {"desktop-detailed-language-settings",
      flag_descriptions::kDesktopDetailedLanguageSettingsName,
      flag_descriptions::kDesktopDetailedLanguageSettingsDescription, kOsDesktop,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
index 5ddcf75..ea538ee 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_tab_helper.h
@@ -41,8 +41,7 @@
   // Call when the preferences change.
   void OnContextualSearchPrefChanged();
   // Call when an unhandled tap needs to show the UI for a tap at the given
-  // position, with the given |font_size_dips|, and |text_run_length| of the
-  // enclosing element.
+  // position.
   void OnShowUnhandledTapUIIfNeeded(int x_px, int y_px);
 
   JavaObjectWeakGlobalRef weak_java_ref_;
diff --git a/chrome/browser/android/contextualsearch/unhandled_tap_web_contents_observer.h b/chrome/browser/android/contextualsearch/unhandled_tap_web_contents_observer.h
index 3756808..474282e4a 100644
--- a/chrome/browser/android/contextualsearch/unhandled_tap_web_contents_observer.h
+++ b/chrome/browser/android/contextualsearch/unhandled_tap_web_contents_observer.h
@@ -13,8 +13,6 @@
 
 // Binds a Mojo unhandled-tap notifier message-handler to the frame host
 // observed by this observer.
-// TODO(donnd): remove this as part of removal of all Tap gesture support
-// after a migration to triggering using Longpress.
 class UnhandledTapWebContentsObserver
     : public content::WebContentsUserData<UnhandledTapWebContentsObserver> {
  public:
diff --git a/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc b/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
index 5359442..80ab628 100644
--- a/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
+++ b/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/android/send_tab_to_self/android_notification_handler.h"
@@ -14,6 +15,8 @@
 #include "chrome/browser/share/android/jni_headers/SendTabToSelfAndroidBridge_jni.h"
 #include "chrome/browser/share/android/jni_headers/TargetDeviceInfo_jni.h"
 #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
+#include "chrome/browser/sync/sync_service_factory.h"
+#include "components/send_tab_to_self/entry_point_display_reason.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/send_tab_to_self/target_device_info.h"
@@ -124,4 +127,34 @@
   }
 }
 
+static ScopedJavaLocalRef<jobject>
+JNI_SendTabToSelfAndroidBridge_GetEntryPointDisplayReason(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& j_profile,
+    const JavaParamRef<jstring>& j_url_to_share) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+  absl::optional<send_tab_to_self::EntryPointDisplayReason> reason =
+      send_tab_to_self::GetEntryPointDisplayReason(
+          GURL(ConvertJavaStringToUTF8(env, j_url_to_share)),
+          SyncServiceFactory::GetForProfile(profile),
+          SendTabToSelfSyncServiceFactory::GetForProfile(profile),
+          profile->GetPrefs());
+
+  if (!reason) {
+    return nullptr;
+  }
+
+  // Wrap the content in a java.lang.Integer, so it can be nullable.
+  // TODO(crbug.com/1219434): Having an empty optional/null to represent the
+  // hidden entry point doesn't seem worth it after all. Make that just another
+  // value in the enum, sparing the complexity here.
+  ScopedJavaLocalRef<jclass> integer_class =
+      base::android::GetClass(env, "java/lang/Integer");
+  jmethodID constructor =
+      base::android::MethodID::Get<base::android::MethodID::TYPE_INSTANCE>(
+          env, integer_class.obj(), "<init>", "(I)V");
+  return ScopedJavaLocalRef<jobject>(
+      env, env->NewObject(integer_class.obj(), constructor, *reason));
+}
+
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
index 7f052baa..23daa0fc 100644
--- a/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
+++ b/chrome/browser/ash/app_restore/full_restore_app_launch_handler_browsertest.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
@@ -60,6 +61,7 @@
 #include "components/exo/surface.h"
 #include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper_chromeos.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/features.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
@@ -90,6 +92,10 @@
 
 constexpr char kTestAppPackage[] = "test.arc.app.package";
 
+// Name of the preference that the SessionID of the Browser is saved to. This
+// is used to transfer the SessionID from PRE_ test to actual test.
+constexpr char kRestoreIdPrefName[] = "browser_restore_id";
+
 // Test values for a test WindowInfo object.
 constexpr int kActivationIndex = 2;
 constexpr int kDeskId = 2;
@@ -892,6 +898,10 @@
   // Create a browser and create a tab for it. Its bounds should not equal
   // |kCurrentBounds|.
   Browser* browser = Browser::Create(Browser::CreateParams(profile(), true));
+  PrefService* local_state = g_browser_process->local_state();
+  static_cast<PrefRegistrySimple*>(local_state->DeprecatedGetPrefRegistry())
+      ->RegisterIntegerPref(kRestoreIdPrefName, 0);
+  local_state->SetInteger(kRestoreIdPrefName, browser->session_id().id());
   AddBlankTabAndShow(browser);
   aura::Window* window = browser->window()->GetNativeWindow();
   ASSERT_NE(kCurrentBounds, window->bounds());
@@ -911,19 +921,27 @@
 // logging out and back in.
 IN_PROC_BROWSER_TEST_F(FullRestoreAppLaunchHandlerBrowserTest,
                        FullRestoreOverridesSessionRestoreTest) {
-  constexpr int kRestoreId = 1;
+  PrefService* local_state = g_browser_process->local_state();
+  static_cast<PrefRegistrySimple*>(local_state->DeprecatedGetPrefRegistry())
+      ->RegisterIntegerPref(kRestoreIdPrefName, 0);
+  const SessionID::id_type previous_browser_id =
+      static_cast<SessionID::id_type>(
+          local_state->GetInteger(kRestoreIdPrefName));
+  ASSERT_NE(0, previous_browser_id);
+
   auto* browser_list = BrowserList::GetInstance();
-  size_t count = browser_list->size();
-  ASSERT_EQ(0u, count);
+  // Initially there should not be any browsers.
+  ASSERT_TRUE(browser_list->empty());
 
   // Create Full Restore launch data before launching any browser, simulating
   // Full Restore data being saved prior to restart.
   ::full_restore::SaveAppLaunchInfo(
-      profile()->GetPath(), std::make_unique<::app_restore::AppLaunchInfo>(
-                                app_constants::kChromeAppId, kRestoreId));
+      profile()->GetPath(),
+      std::make_unique<::app_restore::AppLaunchInfo>(
+          app_constants::kChromeAppId, previous_browser_id));
   CreateAndSaveWindowInfo(
       kDeskId, kCurrentBounds, chromeos::WindowStateType::kNormal,
-      ui::SHOW_STATE_DEFAULT, kRestoreId, /*snap_percentage=*/0);
+      ui::SHOW_STATE_DEFAULT, previous_browser_id, /*snap_percentage=*/0);
   WaitForAppLaunchInfoSaved();
 
   // Launch the browser.
@@ -932,7 +950,6 @@
   app_launch_handler->LaunchBrowserWhenReady(/*first_run_full_restore=*/false);
   SetShouldRestore(app_launch_handler.get());
 
-  ASSERT_EQ(count + 1u, browser_list->size());
   ASSERT_EQ(1u, browser_list->size());
 
   // The restored browser's bounds should be the bounds saved by Full Restore,
diff --git a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
index 00ccf43..edb488c 100644
--- a/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
+++ b/chrome/browser/ash/arc/input_overlay/display_overlay_controller.cc
@@ -148,8 +148,10 @@
 }
 
 void DisplayOverlayController::AddMenuEntryView(views::Widget* overlay_widget) {
-  if (menu_entry_)
+  if (menu_entry_) {
+    menu_entry_->SetVisible(true);
     return;
+  }
   DCHECK(overlay_widget);
   auto game_icon = gfx::CreateVectorIcon(
       vector_icons::kVideogameAssetOutlineIcon, SK_ColorBLACK);
@@ -194,6 +196,8 @@
 
   input_menu_view_ = parent_view->AddChildView(
       InputMenuView::BuildMenuView(this, menu_entry_));
+  // Hide the menu entry when the menu is displayed.
+  menu_entry_->SetVisible(false);
 }
 
 void DisplayOverlayController::RemoveInputMenuView() {
diff --git a/chrome/browser/ash/arc/input_overlay/ui/error_view.cc b/chrome/browser/ash/arc/input_overlay/ui/error_view.cc
index 696bd1d..92c363db 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/error_view.cc
+++ b/chrome/browser/ash/arc/input_overlay/ui/error_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ash/arc/input_overlay/ui/error_view.h"
 
+#include "ash/ambient/util/ambient_util.h"
 #include "chrome/browser/ash/arc/input_overlay/display_overlay_controller.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/background.h"
@@ -35,6 +36,8 @@
                             gfx::Font::Weight::MEDIUM));
   SetAutoColorReadabilityEnabled(false);
   SetEnabledColor(kTextColor);
+  // Default shadow elevation value is 2 which is expected.
+  SetShadows(ash::ambient::util::GetTextShadowValues(GetColorProvider()));
 
   auto preferred_size = GetPreferredSize();
   auto content_bounds = view->parent()->bounds();
diff --git a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc
index 0258b6b..a1b04cf 100644
--- a/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc
+++ b/chrome/browser/ash/arc/input_overlay/ui/input_mapping_view.cc
@@ -10,7 +10,7 @@
 namespace input_overlay {
 namespace {
 // UI specs.
-constexpr SkColor kEditModeBgColor = SkColorSetA(SK_ColorGRAY, 0x99);
+constexpr SkColor kEditModeBgColor = SkColorSetA(SK_ColorBLACK, 0x99);
 }  // namespace
 
 InputMappingView::InputMappingView(
diff --git a/chrome/browser/ash/login/screens/recommend_apps_screen.cc b/chrome/browser/ash/login/screens/recommend_apps_screen.cc
index 6fc82a3..2bee80fa 100644
--- a/chrome/browser/ash/login/screens/recommend_apps_screen.cc
+++ b/chrome/browser/ash/login/screens/recommend_apps_screen.cc
@@ -4,10 +4,15 @@
 
 #include "chrome/browser/ash/login/screens/recommend_apps_screen.h"
 
+#include "ash/constants/ash_features.h"
+#include "chrome/browser/apps/app_discovery_service/app_discovery_service_factory.h"
+#include "chrome/browser/apps/app_discovery_service/play_extras.h"
 #include "chrome/browser/ash/login/screens/recommend_apps/recommend_apps_fetcher.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
+#include "chrome/common/chrome_features.h"
 #include "components/user_manager/user_manager.h"
 
 namespace ash {
@@ -80,8 +85,19 @@
   if (view_)
     view_->Show();
 
-  recommend_apps_fetcher_ = RecommendAppsFetcher::Create(this);
-  recommend_apps_fetcher_->Start();
+  if (features::IsOobeNewRecommendAppsEnabled() &&
+      base::FeatureList::IsEnabled(::features::kAppDiscoveryForOobe)) {
+    Profile* profile = ProfileManager::GetActiveUserProfile();
+    app_discovery_service_ =
+        apps::AppDiscoveryServiceFactory::GetForProfile(profile);
+    app_discovery_service_->GetApps(
+        apps::ResultType::kRecommendedArcApps,
+        base::BindOnce(&RecommendAppsScreen::OnRecommendationsDownloaded,
+                       weak_factory_.GetWeakPtr()));
+  } else {
+    recommend_apps_fetcher_ = RecommendAppsFetcher::Create(this);
+    recommend_apps_fetcher_->Start();
+  }
 }
 
 void RecommendAppsScreen::HideImpl() {
@@ -93,6 +109,51 @@
     view_->OnLoadSuccess(std::move(app_list));
 }
 
+void RecommendAppsScreen::OnRecommendationsDownloaded(
+    const std::vector<apps::Result>& results,
+    apps::DiscoveryError error) {
+  switch (error) {
+    case apps::DiscoveryError::kSuccess:
+      UnpackResultAndShow(results);
+      break;
+    case apps::DiscoveryError::kErrorRequestFailed:
+      OnLoadError();
+      break;
+    case apps::DiscoveryError::kErrorMalformedData:
+      OnParseResponseError();
+      break;
+  }
+}
+
+void RecommendAppsScreen::UnpackResultAndShow(
+    const std::vector<apps::Result>& results) {
+  if (!view_)
+    return;
+  base::Value::List app_list;
+  for (const auto& app_result : results) {
+    base::Value::Dict app_info;
+    app_info.Set("title", base::Value(app_result.GetAppTitle()));
+    auto* play_extras = app_result.GetSourceExtras()->AsPlayExtras();
+    app_info.Set("icon_url", base::Value(play_extras->GetIconUrl().spec()));
+    app_info.Set("category", base::Value(play_extras->GetCategory()));
+    app_info.Set("description", base::Value(play_extras->GetDescription()));
+    app_info.Set("content_rating",
+                 base::Value(play_extras->GetContentRating()));
+    app_info.Set("content_rating_icon",
+                 base::Value(play_extras->GetContentRatingIconUrl().spec()));
+    app_info.Set("in_app_purchases",
+                 base::Value(play_extras->GetHasInAppPurchases()));
+    app_info.Set("was_installed",
+                 base::Value(play_extras->GetWasPreviouslyInstalled()));
+    app_info.Set("contains_ads", base::Value(play_extras->GetContainsAds()));
+    app_info.Set("package_name", base::Value(play_extras->GetPackageName()));
+    app_info.Set("optimized_for_chrome",
+                 base::Value(play_extras->GetOptimizedForChrome()));
+    app_list.Append(std::move(app_info));
+  }
+  view_->OnLoadSuccess(base::Value(std::move(app_list)));
+}
+
 void RecommendAppsScreen::OnLoadError() {
   if (is_hidden())
     return;
diff --git a/chrome/browser/ash/login/screens/recommend_apps_screen.h b/chrome/browser/ash/login/screens/recommend_apps_screen.h
index 13f67549..48906b9 100644
--- a/chrome/browser/ash/login/screens/recommend_apps_screen.h
+++ b/chrome/browser/ash/login/screens/recommend_apps_screen.h
@@ -9,6 +9,8 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/apps/app_discovery_service/app_discovery_service.h"
 #include "chrome/browser/ash/login/screens/base_screen.h"
 #include "chrome/browser/ash/login/screens/recommend_apps/recommend_apps_fetcher_delegate.h"
 // TODO(https://crbug.com/1164001): move to forward declaration.
@@ -73,13 +75,20 @@
   void ShowImpl() override;
   void HideImpl() override;
 
+  void OnRecommendationsDownloaded(const std::vector<apps::Result>& result,
+                                   apps::DiscoveryError error);
+  void UnpackResultAndShow(const std::vector<apps::Result>& result);
+
   RecommendAppsScreenView* view_;
   ScreenExitCallback exit_callback_;
 
   std::unique_ptr<RecommendAppsFetcher> recommend_apps_fetcher_;
+  base::raw_ptr<apps::AppDiscoveryService> app_discovery_service_ = nullptr;
 
   // Skip the screen for testing if set to true.
   bool skip_for_testing_ = false;
+
+  base::WeakPtrFactory<RecommendAppsScreen> weak_factory_{this};
 };
 
 }  // namespace ash
diff --git a/chrome/browser/download/bubble/download_bubble_controller.cc b/chrome/browser/download/bubble/download_bubble_controller.cc
index 1c58fb8..05112a9 100644
--- a/chrome/browser/download/bubble/download_bubble_controller.cc
+++ b/chrome/browser/download/bubble/download_bubble_controller.cc
@@ -380,6 +380,7 @@
       [[fallthrough]];
     case DownloadCommands::DEEP_SCAN:
     case DownloadCommands::BYPASS_DEEP_SCANNING:
+    case DownloadCommands::RESUME:
       commands.ExecuteCommand(command);
       break;
     default:
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc
index 74c3fa0..028877a 100644
--- a/chrome/browser/download/download_ui_model.cc
+++ b/chrome/browser/download/download_ui_model.cc
@@ -778,8 +778,8 @@
                        ui::kColorAlertHighSeverity);
 }
 
-DownloadUIModel::BubbleUIInfo DownloadUIModel::GetBubbleUIInfoForWarning()
-    const {
+DownloadUIModel::BubbleUIInfo
+DownloadUIModel::GetBubbleUIInfoForInProgressOrComplete() const {
   switch (GetMixedContentStatus()) {
     case download::DownloadItem::MixedContentStatus::BLOCK:
     case download::DownloadItem::MixedContentStatus::WARN:
@@ -996,7 +996,9 @@
   bool has_progress_bar = GetState() == DownloadItem::IN_PROGRESS;
   BubbleUIInfo bubble_ui_info = DownloadUIModel::BubbleUIInfo(has_progress_bar);
   if (has_progress_bar) {
-    bubble_ui_info.AddPrimaryButton(DownloadCommands::Command::CANCEL);
+    bubble_ui_info.AddPrimaryButton(IsPaused()
+                                        ? DownloadCommands::Command::RESUME
+                                        : DownloadCommands::Command::CANCEL);
   }
   return bubble_ui_info;
 }
@@ -1005,7 +1007,7 @@
   switch (GetState()) {
     case DownloadItem::IN_PROGRESS:
     case DownloadItem::COMPLETE:
-      return GetBubbleUIInfoForWarning();
+      return GetBubbleUIInfoForInProgressOrComplete();
     case DownloadItem::INTERRUPTED: {
       const FailState fail_state = GetLastFailState();
       if (fail_state != FailState::USER_CANCELED) {
diff --git a/chrome/browser/download/download_ui_model.h b/chrome/browser/download/download_ui_model.h
index 9108724..37ffc40 100644
--- a/chrome/browser/download/download_ui_model.h
+++ b/chrome/browser/download/download_ui_model.h
@@ -448,7 +448,7 @@
   BubbleUIInfo GetBubbleUIInfo() const;
   BubbleUIInfo GetBubbleUIInfoForInterrupted(
       offline_items_collection::FailState fail_state) const;
-  BubbleUIInfo GetBubbleUIInfoForWarning() const;
+  BubbleUIInfo GetBubbleUIInfoForInProgressOrComplete() const;
 #endif
 
 #if BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
index 0d18c16..0ab269b 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
@@ -500,7 +500,7 @@
 
 void CertificateProviderRequestPinFunction::OnInputReceived(
     const std::string& value) {
-  std::unique_ptr<base::ListValue> create_results(new base::ListValue());
+  std::vector<base::Value> create_results;
   chromeos::CertificateProviderService* const service =
       chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
           browser_context());
@@ -510,7 +510,8 @@
     LOG(WARNING) << "PIN request succeeded";
     api::certificate_provider::PinResponseDetails details;
     details.user_input = std::make_unique<std::string>(value);
-    create_results->Append(base::Value::FromUniquePtrValue(details.ToValue()));
+    create_results.emplace_back(
+        base::Value::FromUniquePtrValue(details.ToValue()));
   } else {
     // TODO(crbug.com/1046860): Remove logging after stabilizing the feature.
     LOG(WARNING) << "PIN request canceled";
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
index 60cdfc7..4b40d6e 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
@@ -250,8 +250,8 @@
     client_certs.Append(base::Value(std::move(cert)));
   }
 
-  auto results = std::make_unique<base::ListValue>();
-  results->Append(base::Value(std::move(client_certs)));
+  std::vector<base::Value> results;
+  results.emplace_back(std::move(client_certs));
   Respond(ArgumentList(std::move(results)));
 }
 
diff --git a/chrome/browser/extensions/content_script_tracker_browsertest.cc b/chrome/browser/extensions/content_script_tracker_browsertest.cc
index f8e60661..bc51f13 100644
--- a/chrome/browser/extensions/content_script_tracker_browsertest.cc
+++ b/chrome/browser/extensions/content_script_tracker_browsertest.cc
@@ -1278,7 +1278,9 @@
   }
 
   // Verify that ContentScriptTracker detected the content script injection
-  // from `app` (but not from `unrelated_extension`).
+  // from `app` in the bar.com guest process (but not from
+  // `unrelated_extension`).
+  guest_process = guest_contents->GetMainFrame()->GetProcess();
   EXPECT_TRUE(ContentScriptTracker::DidProcessRunContentScriptFromExtension(
       *guest_process, app->id()));
   EXPECT_FALSE(ContentScriptTracker::DidProcessRunContentScriptFromExtension(
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index a1c9e670..e1f6a40 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -426,7 +426,7 @@
   // creation, the renderer-side Frame object would not have been created yet.
   // We should wait for RenderFrameCreated() to happen, to avoid sending this
   // message twice.
-  if (render_frame_host->IsRenderFrameCreated()) {
+  if (render_frame_host->IsRenderFrameLive()) {
     SessionID id = sessions::SessionTabHelper::IdForTab(web_contents());
     CHECK(id.is_valid());
     ExtensionWebContentsObserver::GetForWebContents(web_contents())
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index b72354a..4a978a4 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -94,6 +94,7 @@
 constexpr char kArcStatusKey[] = "CHROMEOS_ARC_STATUS";
 constexpr char kMonitorInfoKey[] = "monitor_info";
 constexpr char kAccountTypeKey[] = "account_type";
+constexpr char kLacrosStatus[] = "lacros_status";
 constexpr char kDemoModeConfigKey[] = "demo_mode_config";
 constexpr char kOnboardingTime[] = "ONBOARDING_TIME";
 #else
@@ -357,6 +358,9 @@
     PopulateArcPolicyStatus(response.get());
   }
   response->emplace(kAccountTypeKey, GetPrimaryAccountTypeString());
+  response->emplace(kLacrosStatus, crosapi::browser_util::IsLacrosEnabled()
+                                       ? "enabled"
+                                       : "disabled");
   response->emplace(kDemoModeConfigKey, ash::DemoSession::DemoConfigToString(
                                             ash::DemoSession::GetDemoConfig()));
   PopulateLocalStateSettings(response.get());
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 3532cc4..10207d4 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1168,11 +1168,6 @@
     "expiry_milestone": 106
   },
   {
-    "name": "desktop-restructured-language-settings",
-    "owners": [ "chrome-language@google.com" ],
-    "expiry_milestone": 101
-  },
-  {
     "name": "destroy-profile-on-browser-close",
     "owners": [ "nicolaso" ],
     "expiry_milestone": 100
@@ -4553,16 +4548,6 @@
     "expiry_milestone": 105
   },
   {
-    "name": "omnibox-pedals-batch3",
-    "owners": [ "orinj", "chrome-omnibox-team@google.com" ],
-    "expiry_milestone": 107
-  },
-  {
-    "name": "omnibox-pedals-batch3-nonenglish",
-    "owners": [ "orinj", "chrome-omnibox-team@google.com" ],
-    "expiry_milestone": 107
-  },
-  {
     "name": "omnibox-retain-suggestions-with-headers",
     "owners": [ "ender@google.com", "mahmadi@google.com", "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 112
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 1641023..6321bbc 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1844,12 +1844,6 @@
     "current URL. Will only work if user is signed-in and syncing, or is "
     "otherwise eligible to send the current page URL to the suggest server.";
 
-const char kOmniboxPedalsBatch3NonEnglishName[] =
-    "Omnibox Pedals batch 3 for non-English locales";
-const char kOmniboxPedalsBatch3NonEnglishDescription[] =
-    "Enable the third batch of Omnibox Pedals (Find your phone, etc.) for "
-    "locales other than 'en' and 'en-GB'.";
-
 const char kOmniboxSpareRendererName[] =
     "Start spare renderer on omnibox focus";
 const char kOmniboxSpareRendererDescription[] =
@@ -5764,11 +5758,6 @@
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_FUCHSIA)
 
-const char kDesktopRestructuredLanguageSettingsName[] =
-    "Restructured Language Settings (Desktop)";
-const char kDesktopRestructuredLanguageSettingsDescription[] =
-    "Enable the new restructured language settings page";
-
 const char kDesktopDetailedLanguageSettingsName[] =
     "Detailed Language Settings (Desktop)";
 const char kDesktopDetailedLanguageSettingsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3bbbb97de..b8d546c6f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1027,9 +1027,6 @@
 extern const char kOmniboxOnFocusSuggestionsContextualWebName[];
 extern const char kOmniboxOnFocusSuggestionsContextualWebDescription[];
 
-extern const char kOmniboxPedalsBatch3NonEnglishName[];
-extern const char kOmniboxPedalsBatch3NonEnglishDescription[];
-
 extern const char kOmniboxShortBookmarkSuggestionsName[];
 extern const char kOmniboxShortBookmarkSuggestionsDescription[];
 
@@ -3311,9 +3308,6 @@
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_FUCHSIA)
 
-extern const char kDesktopRestructuredLanguageSettingsName[];
-extern const char kDesktopRestructuredLanguageSettingsDescription[];
-
 extern const char kDesktopDetailedLanguageSettingsName[];
 extern const char kDesktopDetailedLanguageSettingsDescription[];
 
diff --git a/chrome/browser/history_clusters/OWNERS b/chrome/browser/history_clusters/OWNERS
index c6981c7..19e302b 100644
--- a/chrome/browser/history_clusters/OWNERS
+++ b/chrome/browser/history_clusters/OWNERS
@@ -1,5 +1,8 @@
 file://components/history_clusters/OWNERS
 
+# The top-level directly includes a lot of Android specific code.
+pnoland@chromium.org
+
 # This is for the common case of adding or renaming files. If you're doing
 # structural changes, use usual OWNERS rules.
 per-file BUILD.gn=*
diff --git a/chrome/browser/image_decoder/image_decoder.cc b/chrome/browser/image_decoder/image_decoder.cc
index 026f661..2d71a77f 100644
--- a/chrome/browser/image_decoder/image_decoder.cc
+++ b/chrome/browser/image_decoder/image_decoder.cc
@@ -10,8 +10,6 @@
 #include "base/callback.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
 #include "ipc/ipc_channel.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 #include "services/data_decoder/public/cpp/decode_image.h"
@@ -35,38 +33,24 @@
     std::move(fail_callback).Run(request_id);
 }
 
-void RunDecodeCallbackOnTaskRunner(
-    data_decoder::DecodeImageCallback callback,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    const SkBitmap& image) {
-  task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), image));
-}
-
 template <typename ImageDataType>
 void DecodeImage(ImageDataType image_data,
                  data_decoder::mojom::ImageCodec codec,
                  bool shrink_to_fit,
                  const gfx::Size& desired_image_frame_size,
                  data_decoder::DecodeImageCallback callback,
-                 scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
                  data_decoder::DataDecoder* data_decoder) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
   base::span<const uint8_t> image_data_span(
       base::as_bytes(base::make_span(image_data)));
 
   if (data_decoder) {
-    data_decoder::DecodeImage(
-        data_decoder, image_data_span, codec, shrink_to_fit,
-        kMaxImageSizeInBytes, desired_image_frame_size,
-        base::BindOnce(&RunDecodeCallbackOnTaskRunner, std::move(callback),
-                       std::move(callback_task_runner)));
+    data_decoder::DecodeImage(data_decoder, image_data_span, codec,
+                              shrink_to_fit, kMaxImageSizeInBytes,
+                              desired_image_frame_size, std::move(callback));
   } else {
     data_decoder::DecodeImageIsolated(
         image_data_span, codec, shrink_to_fit, kMaxImageSizeInBytes,
-        desired_image_frame_size,
-        base::BindOnce(&RunDecodeCallbackOnTaskRunner, std::move(callback),
-                       std::move(callback_task_runner)));
+        desired_image_frame_size, std::move(callback));
   }
 }
 
@@ -168,17 +152,9 @@
                                     base::Unretained(this)),
                      request_id);
 
-  // NOTE: There exist ImageDecoder consumers which implicitly rely on this
-  // operation happening on a thread which always has a ThreadTaskRunnerHandle.
-  // We arbitrarily use the IO thread here to match details of the legacy
-  // implementation.
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(&DecodeImage<ImageDataType>, std::move(image_data), codec,
-                     shrink_to_fit, desired_image_frame_size,
-                     std::move(callback),
-                     base::WrapRefCounted(image_request->task_runner()),
-                     image_request->data_decoder()));
+  DecodeImage<ImageDataType>(std::move(image_data), codec, shrink_to_fit,
+                             desired_image_frame_size, std::move(callback),
+                             image_request->data_decoder());
 }
 
 template void ImageDecoder::StartWithOptionsImpl(ImageRequest*,
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc
index 5543e6f..fa19b4fe 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -72,14 +72,6 @@
   pref->SetInteger(path, value + 1);
 }
 
-// Called on a background thread to load hardware class information.
-std::string GetFullHardwareClassOnBackgroundThread() {
-  std::string full_hardware_class;
-  chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
-      "hardware_class", &full_hardware_class);
-  return full_hardware_class;
-}
-
 // Called on a background thread to load cellular device variant
 // using ConfigFS.
 std::string GetCellularDeviceVariantOnBackgroundThread() {
@@ -113,7 +105,7 @@
     profile_provider_ = std::make_unique<metrics::ProfileProvider>();
 }
 
-ChromeOSMetricsProvider::~ChromeOSMetricsProvider() {}
+ChromeOSMetricsProvider::~ChromeOSMetricsProvider() = default;
 
 // static
 void ChromeOSMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
@@ -183,16 +175,10 @@
 
 void ChromeOSMetricsProvider::InitTaskGetFullHardwareClass(
     base::OnceClosure callback) {
-  // Run the (potentially expensive) task in the background to avoid blocking
-  // the UI thread.
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE,
-      {base::MayBlock(), base::WithBaseSyncPrimitives(),
-       base::TaskPriority::BEST_EFFORT,
-       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::BindOnce(&GetFullHardwareClassOnBackgroundThread),
-      base::BindOnce(&ChromeOSMetricsProvider::SetFullHardwareClass,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  chromeos::system::StatisticsProvider::GetInstance()
+      ->ScheduleOnMachineStatisticsLoaded(
+          base::BindOnce(&ChromeOSMetricsProvider::OnMachineStatisticsLoaded,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
 void ChromeOSMetricsProvider::InitTaskGetArcFeatures(
@@ -384,10 +370,10 @@
   }
 }
 
-void ChromeOSMetricsProvider::SetFullHardwareClass(
-    base::OnceClosure callback,
-    std::string full_hardware_class) {
-  full_hardware_class_ = full_hardware_class;
+void ChromeOSMetricsProvider::OnMachineStatisticsLoaded(
+    base::OnceClosure callback) {
+  chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
+      "hardware_class", &full_hardware_class_);
 
   // Structured metrics needs to know when full hardware class is available
   // since events should have full hardware class populated. Notify structured
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.h b/chrome/browser/metrics/chromeos_metrics_provider.h
index 7367fe9..4524a91d 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider.h
+++ b/chrome/browser/metrics/chromeos_metrics_provider.h
@@ -84,9 +84,9 @@
   void UpdateMultiProfileUserCount(
       metrics::SystemProfileProto* system_profile_proto);
 
-  // Sets the full hardware class, then calls the callback.
-  void SetFullHardwareClass(base::OnceClosure callback,
-                            std::string full_hardware_class);
+  // Invoked when StatisticsProvider finishes loading to read the full hardware
+  // class from StatisticsProvider and calls the callback.
+  void OnMachineStatisticsLoaded(base::OnceClosure callback);
 
   // Sets the cellular device variant, then calls the callback.
   void SetCellularDeviceVariant(base::OnceClosure callback,
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 5f0264a..53abbfe 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -1607,8 +1607,7 @@
 // Printing preview a web page with an iframe from an isolated origin.
 // This test passes whenever the print preview is rendered. This should not be
 // a timed out test which indicates the print preview hung or crash.
-IN_PROC_BROWSER_TEST_F(IsolateOriginsPrintBrowserTest,
-                       DISABLED_PrintIsolatedSubframe) {
+IN_PROC_BROWSER_TEST_F(IsolateOriginsPrintBrowserTest, PrintIsolatedSubframe) {
   ASSERT_TRUE(embedded_test_server()->Started());
   GURL url(embedded_test_server()->GetURL(
       "/printing/content_with_same_site_iframe.html"));
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.html b/chrome/browser/resources/access_code_cast/access_code_cast.html
index dbc27d03..d45c7107 100644
--- a/chrome/browser/resources/access_code_cast/access_code_cast.html
+++ b/chrome/browser/resources/access_code_cast/access_code_cast.html
@@ -34,6 +34,10 @@
     background-color: transparent;
   }
 
+  #buttons cr-button {
+    margin-inline-start: 8px;
+  }
+
   #error-message-container {
     min-height: 16px;
   }
@@ -112,17 +116,24 @@
       </div>
     </template>
   </div>
-  <div slot="button-container">
-    <cr-button on-click="cancelButtonPressed" class="cancel-button">
-      $i18n{cancel}
-    </cr-button>
-    <cr-button id="castButton" on-click="addSinkAndCast" class="action-button"
-      disabled="[[submitDisabled]]">
-      $i18n{submit}
-    </cr-button>
-    <cr-button id="backButton" on-click="switchToCodeInput"
-      class="action-button">
-      $i18n{back}
-    </cr-button>
+  <div slot="button-container" id="buttons">
+    <template is="dom-if" if="[[!isWin]]">
+      <cr-button on-click="cancelButtonPressed">
+        $i18n{cancel}
+      </cr-button>
+    </template>
+      <cr-button id="castButton" on-click="addSinkAndCast" class="action-button"
+        disabled="[[submitDisabled]]">
+        $i18n{submit}
+      </cr-button>
+      <cr-button id="backButton" on-click="switchToCodeInput"
+        class="action-button">
+        $i18n{back}
+      </cr-button>
+    <template is="dom-if" if="[[isWin]]">
+      <cr-button on-click="cancelButtonPressed">
+        $i18n{cancel}
+      </cr-button>
+    </template>
   </div>
 </cr-dialog>
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.ts b/chrome/browser/resources/access_code_cast/access_code_cast.ts
index 433f5d6..d25b44a3 100644
--- a/chrome/browser/resources/access_code_cast/access_code_cast.ts
+++ b/chrome/browser/resources/access_code_cast/access_code_cast.ts
@@ -13,6 +13,7 @@
 
 import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import {isWindows} from 'chrome://resources/js/cr.m.js';
 import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js';
@@ -84,17 +85,19 @@
   private canCast: boolean;
   private inputEnabledStartTime: number;
   private inputLabel: string;
-  private state: PageState;
-  private submitDisabled: boolean;
+  private isWin: boolean;
+  private managedFootnote: string;
   private qrScannerEnabled: boolean;
   private rememberDevices: boolean;
-  private managedFootnote: string;
+  private state: PageState;
+  private submitDisabled: boolean;
 
   constructor() {
     super();
     this.listenerIds = [];
     this.router = BrowserProxy.getInstance().callbackRouter;
     this.inputLabel = this.i18n('inputLabel');
+    this.isWin = isWindows;
 
     this.createManagedFootnote(
         loadTimeData.getInteger('rememberedDeviceDuration'));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
index de77444..85dba11 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -85,6 +85,7 @@
     JaPhoneticData.init(JaPhoneticMap.MAP);
     LiveRegions.init(this);
     LocaleOutputHelper.init();
+    LogStore.init();
     MediaAutomationHandler.init();
     PageLoadSoundHandler.init();
     PanelBackground.init();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
index 393d33d..2c92460a 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
@@ -31,6 +31,19 @@
 };
 
 ChromeVoxState = class {
+  /** @param {ChromeVoxStateObserver} observer */
+  static addObserver(observer) {
+    ChromeVoxState.observers.push(observer);
+  }
+
+  /** @param {ChromeVoxStateObserver} observer */
+  static removeObserver(observer) {
+    const index = ChromeVoxState.observers.indexOf(observer);
+    if (index > -1) {
+      ChromeVoxState.observers.splice(index, 1);
+    }
+  }
+
   /** @return {cursors.Range} */
   get currentRange() {
     return this.getCurrentRange();
@@ -124,19 +137,6 @@
 /** @type {!Array<ChromeVoxStateObserver>} */
 ChromeVoxState.observers = [];
 
-/** @param {ChromeVoxStateObserver} observer */
-ChromeVoxState.addObserver = function(observer) {
-  ChromeVoxState.observers.push(observer);
-};
-
-/** @param {ChromeVoxStateObserver} observer */
-ChromeVoxState.removeObserver = function(observer) {
-  const index = ChromeVoxState.observers.indexOf(observer);
-  if (index > -1) {
-    ChromeVoxState.observers.splice(index, 1);
-  }
-};
-
 BridgeHelper.registerHandler(
     BridgeTargets.CHROMEVOX_STATE, BridgeActions.CLEAR_CURRENT_RANGE,
     () => ChromeVoxState.instance.setCurrentRange(null));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
index 5cea8c9..9f13837e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
@@ -27,8 +27,6 @@
     consoleTts.setEnabled(
         ChromeVoxPrefs.instance.getPrefs()['enableSpeechLogging'] === 'true');
 
-    LogStore.getInstance();
-
     /**
      * Chrome's actual TTS which knows and cares about pitch, volume, etc.
      * @type {TtsBackground}
@@ -313,7 +311,8 @@
 
     ChromeVoxState.backgroundTts = background.backgroundTts_;
     BridgeHelper.registerHandler(
-        BridgeTargets.CHROMEVOX_BACKGROUND, BridgeActions.GET_CURRENT_VOICE,
+        BridgeConstants.ChromeVoxBackground.TARGET,
+        BridgeConstants.ChromeVoxBackground.Action.GET_CURRENT_VOICE,
         () => background.getCurrentVoice());
   }
 }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js
index 09a107f..6a8017c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/logging/log_store.js
@@ -134,9 +134,11 @@
     this.shouldSkipOutput_ = newValue;
   }
 
-  /**
-   * @return {LogStore}
-   */
+  static init() {
+    LogStore.getInstance();
+  }
+
+  /** @return {!LogStore} */
   static getInstance() {
     if (!LogStore.instance) {
       LogStore.instance = new LogStore();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
index 9570c62..899f28c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/background_bridge.js
@@ -57,7 +57,8 @@
    */
   async getCurrentVoice() {
     return BridgeHelper.sendMessage(
-        BridgeTargets.CHROMEVOX_BACKGROUND, BridgeActions.GET_CURRENT_VOICE);
+        BridgeConstants.ChromeVoxBackground.TARGET,
+        BridgeConstants.ChromeVoxBackground.Action.GET_CURRENT_VOICE);
   },
 };
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
index 82d4d91..a8366480 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/bridge_constants.js
@@ -13,7 +13,6 @@
 
 /** @enum {string} */
 BridgeTargets = {
-  CHROMEVOX_BACKGROUND: 'ChromeVoxBackground',
   CHROMEVOX_PREFS: 'ChromeVoxPrefs',
   CHROMEVOX_STATE: 'ChromeVoxState',
   EVENT_STREAM_LOGGER: 'EventStreamLogger',
@@ -49,6 +48,15 @@
     },
   },
 
+  ChromeVoxBackground: {
+    /** @public {BridgeTarget} */
+    TARGET: 'ChromeVoxBackground',
+    /** @enum {string} */
+    Action: {
+      GET_CURRENT_VOICE: 'getCurrentVoice',
+    },
+  },
+
   CommandHandler: {
     /** @public {BridgeTarget} */
     TARGET: 'CommandHandler',
@@ -82,7 +90,6 @@
   DESTROY_I_SEARCH: 'destroyISearch',
   FOCUS_TAB: 'focusTab',
   GET_ACTIONS_FOR_CURRENT_NODE: 'getActionsForCurrentNode',
-  GET_CURRENT_VOICE: 'getCurrentVoice',
   GET_LOGS: 'getLogs',
   GET_PREFS: 'getPrefs',
   GET_TAB_MENU_DATA: 'getTabMenuData',
@@ -105,6 +112,7 @@
  * @typedef {BridgeActions |
  *           BridgeConstants.BrailleBackground.Action |
  *           BridgeConstants.BrailleCommandHandler.Action |
+ *           BridgeConstants.ChromeVoxBackground.Action |
  *           BridgeConstants.CommandHandler.Action |
  *           BridgeConstants.EventSourceState.Action}
  */
diff --git a/chrome/browser/resources/chromeos/login/components/oobe_types.js b/chrome/browser/resources/chromeos/login/components/oobe_types.js
index dcf2fab..8251835 100644
--- a/chrome/browser/resources/chromeos/login/components/oobe_types.js
+++ b/chrome/browser/resources/chromeos/login/components/oobe_types.js
@@ -123,6 +123,25 @@
  *   package_name: string,
  * }}
  */
+OobeTypes.RecommendedAppsOldExpectedAppData;
+
+/**
+ * Data type that is expected for each app that is shown on the RecommendApps
+ * screen.
+ * @typedef {{
+ *   title: string,
+ *   icon_url: string,
+ *   category: string,
+ *   description: string,
+ *   content_rating: number,
+ *   content_rating_icon: string,
+ *   in_app_purchases: boolean,
+ *   was_installed: boolean,
+ *   contains_ads: boolean,
+ *   package_name: string,
+ *   optimized_for_chrome: boolean,
+ * }}
+ */
 OobeTypes.RecommendedAppsExpectedAppData;
 
 /**
diff --git a/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.html b/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.html
index 55fb805..ccbbebf 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.html
+++ b/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.html
@@ -2,6 +2,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
+<link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
@@ -49,9 +50,10 @@
         [[i18nDynamic(locale, 'recommendAppsScreenTitle')]]
       </h1>
       <div slot="subtitle">
-        [[i18nDynamic(locale, 'recommendAppsScreenDescription', appCount_)]]
+        [[i18nDynamic(locale, 'recommendAppsScreenDescription')]]
       </div>
-      <div id="app-list-view-container" slot="content">
+      <div id="app-list-view-container" slot="content"
+          hidden="[[isOobeNewRecommendAppsEnabled_]]">
         <div id="selectAllButton">
           <a class="oobe-local-link focus-on-show" is="action-link"
               on-click="onSelectAll_">
diff --git a/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.js b/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.js
index 977e163..7c502ad 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.js
+++ b/chrome/browser/resources/chromeos/login/screens/common/recommend_apps.js
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -13,7 +13,7 @@
  * UI mode for the dialog.
  * @enum {string}
  */
- const RecommendAppsUiState = {
+const RecommendAppsUiState = {
   LOADING: 'loading',
   LIST: 'list',
 };
@@ -23,6 +23,7 @@
  * @extends {PolymerElement}
  * @implements {LoginScreenBehaviorInterface}
  * @implements {MultiStepBehaviorInterface}
+ * @implements {OobeI18nBehaviorInterface}
  */
 const RecommendAppsElementBase = Polymer.mixinBehaviors(
   [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior, MultiStepBehavior],
@@ -59,6 +60,18 @@
         type: Number,
         value: 0,
       },
+
+      /**
+       * If new version of screen available.
+       * @private
+       */
+      isOobeNewRecommendAppsEnabled_: {
+        type: Boolean,
+        value() {
+          return loadTimeData.getBoolean('isOobeNewRecommendAppsEnabled');
+        },
+        readOnly: true,
+      },
     };
   }
 
@@ -121,6 +134,11 @@
    * It is assumed that |loadAppList| is called only once after |setWebview|.
    */
   loadAppList(appList) {
+    if (this.isOobeNewRecommendAppsEnabled_) {
+      // TODO(dkuzmin): finish UI changes of a new layout.
+      this.setUIStep(RecommendAppsUiState.LIST);
+      return;
+    }
     this.appCount_ = appList.length;
 
     const appListView = this.$.appView;
@@ -197,7 +215,10 @@
    */
   onSelectAll_() {
     const appListView = this.$.appView;
-    appListView.executeScript({code: 'selectAll();'});
+    if (!this.isOobeNewRecommendAppsEnabled_) {
+      appListView.executeScript({code: 'selectAll();'});
+      return;
+    }
   }
 
   canProceed_(appsSelected) {
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java
index 0805340f..95cd31eb 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridge.java
@@ -4,6 +4,10 @@
 
 package org.chromium.chrome.browser.share.send_tab_to_self;
 
+import androidx.annotation.Nullable;
+
+import com.google.common.base.Optional;
+
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -76,6 +80,14 @@
         SendTabToSelfAndroidBridgeJni.get().updateActiveWebContents(webContents);
     }
 
+    public static Optional</*@EntryPointDisplayReason*/ Integer> getEntryPointDisplayReason(
+            Profile profile, String url) {
+        @Nullable
+        Integer reason =
+                SendTabToSelfAndroidBridgeJni.get().getEntryPointDisplayReason(profile, url);
+        return reason == null ? Optional.absent() : Optional.of(reason.intValue());
+    }
+
     @NativeMethods
     public interface Natives {
         boolean addEntry(
@@ -88,5 +100,8 @@
         TargetDeviceInfo[] getAllTargetDeviceInfos(Profile profile);
 
         void updateActiveWebContents(WebContents webContents);
+
+        @Nullable
+        Integer getEntryPointDisplayReason(Profile profile, String url);
     }
 }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinator.java
index d8e4e65..2fe7500 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinator.java
@@ -7,6 +7,8 @@
 import android.accounts.Account;
 import android.content.Context;
 
+import com.google.common.base.Optional;
+
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -18,10 +20,8 @@
 import org.chromium.chrome.browser.ui.signin.account_picker.AccountPickerDelegate;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
-import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.base.GoogleServiceAuthError;
-import org.chromium.components.sync.ModelType;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.util.List;
@@ -37,6 +37,7 @@
     private static class TargetDeviceListWaiter
             extends EmptyBottomSheetObserver implements SyncService.SyncStateChangedListener {
         private final BottomSheetController mBottomSheetController;
+        private final String mUrl;
         private final Runnable mGotDeviceListCallback;
 
         /**
@@ -44,9 +45,10 @@
          * account picker bottom sheet was closed and there's nothing left to do (simply don't
          * show any other bottom sheet).
          */
-        public TargetDeviceListWaiter(
-                BottomSheetController bottomSheetController, Runnable gotDeviceListCallback) {
+        public TargetDeviceListWaiter(BottomSheetController bottomSheetController, String url,
+                Runnable gotDeviceListCallback) {
             mBottomSheetController = bottomSheetController;
+            mUrl = url;
             mGotDeviceListCallback = gotDeviceListCallback;
 
             SyncService.get().addSyncStateChangedListener(this);
@@ -71,10 +73,22 @@
         }
 
         private void notifyAndDestroyIfDone() {
-            if (SyncService.get().getActiveDataTypes().contains(ModelType.DEVICE_INFO)) {
-                destroy();
-                mGotDeviceListCallback.run();
+            Optional</*@EntryPointDisplayReason*/ Integer> displayReason =
+                    SendTabToSelfAndroidBridge.getEntryPointDisplayReason(
+                            Profile.getLastUsedRegularProfile(), mUrl);
+            // The model is starting up, keep waiting.
+            if (!displayReason.isPresent()) return;
+
+            switch (displayReason.get()) {
+                case EntryPointDisplayReason.OFFER_SIGN_IN:
+                    return;
+                case EntryPointDisplayReason.INFORM_NO_TARGET_DEVICE:
+                case EntryPointDisplayReason.OFFER_FEATURE:
+                    break;
             }
+
+            destroy();
+            mGotDeviceListCallback.run();
         }
     }
 
@@ -131,55 +145,45 @@
     }
 
     public void show() {
-        if (!shouldOfferSignInPromo()) {
-            showDeviceList();
+        Profile profile = Profile.getLastUsedRegularProfile();
+        Optional</*@EntryPointDisplayReason*/ Integer> displayReason =
+                SendTabToSelfAndroidBridge.getEntryPointDisplayReason(profile, mUrl);
+        if (!displayReason.isPresent()) {
+            // This must be the old behavior where the entry point is shown even in states where
+            // no promo is shown.
+            assert !ChromeFeatureList.isEnabled(ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO);
+            mController.requestShowContent(new NoTargetDeviceBottomSheetContent(mContext), true);
             return;
         }
 
-        new AccountPickerBottomSheetCoordinator(mWindowAndroid, mController,
-                new SendTabToSelfAccountPickerDelegate(this::onSignInComplete));
+        switch (displayReason.get()) {
+            case EntryPointDisplayReason.INFORM_NO_TARGET_DEVICE:
+                mController.requestShowContent(
+                        new NoTargetDeviceBottomSheetContent(mContext), true);
+                return;
+            case EntryPointDisplayReason.OFFER_FEATURE:
+                // TODO(crbug.com/1219434): Merge with INFORM_NO_TARGET_DEVICE, just let the UI
+                // differentiate between the 2 by checking the device list size.
+                List<TargetDeviceInfo> targetDevices =
+                        SendTabToSelfAndroidBridge.getAllTargetDeviceInfos(profile);
+                mController.requestShowContent(new DevicePickerBottomSheetContent(mContext, mUrl,
+                                                       mTitle, mController, targetDevices),
+                        true);
+                return;
+            case EntryPointDisplayReason.OFFER_SIGN_IN: {
+                new AccountPickerBottomSheetCoordinator(mWindowAndroid, mController,
+                        new SendTabToSelfAccountPickerDelegate(this::onSignInComplete));
+                return;
+            }
+        }
     }
 
     private void onSignInComplete() {
-        new TargetDeviceListWaiter(mController, this::onTargetDeviceListReady);
+        new TargetDeviceListWaiter(mController, mUrl, this::onTargetDeviceListReady);
     }
 
     private void onTargetDeviceListReady() {
         mController.hideContent(mController.getCurrentSheetContent(), /*animate=*/true);
-        showDeviceList();
-    }
-
-    private void showDeviceList() {
-        List<TargetDeviceInfo> targetDevices = SendTabToSelfAndroidBridge.getAllTargetDeviceInfos(
-                Profile.getLastUsedRegularProfile());
-        if (targetDevices.isEmpty()) {
-            mController.requestShowContent(
-                    new NoTargetDeviceBottomSheetContent(mContext), /*animate=*/true);
-        } else {
-            mController.requestShowContent(new DevicePickerBottomSheetContent(mContext, mUrl,
-                                                   mTitle, mController, targetDevices),
-                    /*animate=*/true);
-        }
-    }
-
-    private boolean shouldOfferSignInPromo() {
-        // There should be some account on the device that can sign in to Chrome.
-        List<Account> accounts = AccountUtils.getAccountsIfFulfilledOrEmpty(
-                AccountManagerFacadeProvider.getInstance().getAccounts());
-        if (accounts.isEmpty()) {
-            return false;
-        }
-
-        Profile profile = Profile.getLastUsedRegularProfile();
-        if (!IdentityServicesProvider.get().getSigninManager(profile).isSigninAllowed()) {
-            return false;
-        }
-
-        // There should be no account signed in to Chrome yet.
-        if (SyncService.get().getAccountInfo() != null) {
-            return false;
-        }
-
-        return ChromeFeatureList.isEnabled(ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO);
+        show();
     }
 }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
index a9d093b4d..b6b8a88 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
@@ -15,6 +15,8 @@
 
 import androidx.appcompat.content.res.AppCompatResources;
 
+import com.google.common.base.Optional;
+
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
@@ -31,6 +33,7 @@
 import org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsCoordinator;
 import org.chromium.chrome.browser.share.qrcode.QrCodeCoordinator;
 import org.chromium.chrome.browser.share.screenshot.ScreenshotCoordinator;
+import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridge;
 import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfCoordinator;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleMetricsHelper.LinkToggleMetricsDetails;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType;
@@ -122,12 +125,12 @@
         mShareStartTime = shareStartTime;
         mImageEditorModuleProvider = imageEditorModuleProvider;
         mFeatureEngagementTracker = featureEngagementTracker;
-        mOrderedFirstPartyOptions = new ArrayList<>();
-        initializeFirstPartyOptionsInOrder();
         mChromeOptionShareCallback = chromeOptionShareCallback;
         mUrl = url;
         mLinkGenerationStatusForMetrics = linkGenerationStatusForMetrics;
         mLinkToggleMetricsDetails = linkToggleMetricsDetails;
+        mOrderedFirstPartyOptions = new ArrayList<>();
+        initializeFirstPartyOptionsInOrder();
     }
 
     /**
@@ -299,7 +302,13 @@
         mOrderedFirstPartyOptions.add(createCopyImageFirstPartyOption());
         mOrderedFirstPartyOptions.add(createCopyFirstPartyOption());
         mOrderedFirstPartyOptions.add(createCopyTextFirstPartyOption());
-        mOrderedFirstPartyOptions.add(createSendTabToSelfFirstPartyOption());
+        Optional<Integer> sendTabToSelfDisplayReason =
+                SendTabToSelfAndroidBridge.getEntryPointDisplayReason(
+                        Profile.getLastUsedRegularProfile(), mUrl);
+        if (sendTabToSelfDisplayReason.isPresent()
+                || !ChromeFeatureList.isEnabled(ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO)) {
+            mOrderedFirstPartyOptions.add(createSendTabToSelfFirstPartyOption());
+        }
         if (!mIsIncognito) {
             mOrderedFirstPartyOptions.add(createQrCodeFirstPartyOption());
         }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java
index 63b5bfab..41cc63e 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java
@@ -4,11 +4,15 @@
 
 package org.chromium.chrome.browser.share.send_tab_to_self;
 
+import static org.chromium.url.JUnitTestGURLs.HTTP_URL;
+
 import android.view.View;
 
 import androidx.annotation.IdRes;
 import androidx.test.filters.LargeTest;
 
+import com.google.common.base.Optional;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -21,13 +25,12 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.sync.SyncService;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
-import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.protocol.DeviceInfoSpecifics;
 import org.chromium.components.sync.protocol.EntitySpecifics;
 import org.chromium.components.sync.protocol.FeatureSpecificFields;
@@ -53,8 +56,11 @@
     public void testShowDeviceListIfSignedIn() {
         // Sign in and wait for the device list to be downloaded.
         mSyncTestRule.setUpAccountAndSignInForTesting();
-        CriteriaHelper.pollUiThread(
-                () -> SyncService.get().getActiveDataTypes().contains(ModelType.DEVICE_INFO));
+        CriteriaHelper.pollUiThread(() -> {
+            return SendTabToSelfAndroidBridge
+                    .getEntryPointDisplayReason(Profile.getLastUsedRegularProfile(), HTTP_URL)
+                    .equals(Optional.of(EntryPointDisplayReason.OFFER_FEATURE));
+        });
 
         buildAndShowCoordinator();
 
@@ -122,8 +128,8 @@
         WindowAndroid windowAndroid = activity.getWindowAndroid();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SendTabToSelfCoordinator coordinator =
-                    new SendTabToSelfCoordinator(activity, windowAndroid, "page-to-share.com",
-                            "Page", BottomSheetControllerProvider.from(windowAndroid));
+                    new SendTabToSelfCoordinator(activity, windowAndroid, HTTP_URL, "Page",
+                            BottomSheetControllerProvider.from(windowAndroid));
             coordinator.show();
         });
     }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
index b924c20..0baa3f6 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
@@ -45,6 +45,8 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration;
+import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridge;
+import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridgeJni;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleCoordinator.LinkToggleState;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleMetricsHelper.LinkToggleMetricsDetails;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType;
@@ -90,6 +92,8 @@
     @Mock
     private UserPrefs.Natives mUserPrefsNatives;
     @Mock
+    private SendTabToSelfAndroidBridge.Natives mSendTabToSelfAndroidBridgeNatives;
+    @Mock
     private Profile mProfile;
     @Mock
     private PrefService mPrefService;
@@ -118,8 +122,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsNatives);
+        mJniMocker.mock(
+                SendTabToSelfAndroidBridgeJni.TEST_HOOKS, mSendTabToSelfAndroidBridgeNatives);
         Profile.setLastUsedProfileForTesting(mProfile);
         Mockito.when(mUserPrefsNatives.get(mProfile)).thenReturn(mPrefService);
+        Mockito.when(mSendTabToSelfAndroidBridgeNatives.getEntryPointDisplayReason(
+                             any(), anyString()))
+                .thenReturn(null);
         Mockito.when(mTabProvider.hasValue()).thenReturn(true);
         Mockito.when(mTabProvider.get()).thenReturn(mTab);
         Mockito.when(mTab.getWebContents()).thenReturn(mWebContents);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a6a926e..564cd2d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -4275,6 +4275,8 @@
       "views/extensions/extension_permissions_view.cc",
       "views/extensions/extension_permissions_view.h",
       "views/extensions/extension_uninstall_dialog_view.cc",
+      "views/extensions/extensions_dialogs_utils.cc",
+      "views/extensions/extensions_dialogs_utils.h",
       "views/extensions/extensions_menu_button.cc",
       "views/extensions/extensions_menu_button.h",
       "views/extensions/extensions_menu_item_view.cc",
@@ -4285,6 +4287,8 @@
       "views/extensions/extensions_request_access_button.h",
       "views/extensions/extensions_request_access_button_hover_card.cc",
       "views/extensions/extensions_request_access_button_hover_card.h",
+      "views/extensions/extensions_request_access_dialog_view.cc",
+      "views/extensions/extensions_request_access_dialog_view.h",
       "views/extensions/extensions_tabbed_menu_view.cc",
       "views/extensions/extensions_tabbed_menu_view.h",
       "views/extensions/extensions_toolbar_button.cc",
diff --git a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
index 64bfbef0..83de562 100644
--- a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
@@ -26,8 +26,7 @@
             std::make_unique<TestOmniboxEditController>()) {}
 
   void SetUp() override {
-    feature_list_.InitWithFeatures({omnibox::kOmniboxPedalsBatch3NonEnglish},
-                                   {});
+    feature_list_.InitWithFeatures({}, {});
     InitPedals();
   }
 
diff --git a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
index 87d1f11..88d60d0 100644
--- a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
@@ -24,7 +24,7 @@
   std::unique_ptr<base::Environment> env = base::Environment::Create();
   MockAutocompleteProviderClient client;
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures({omnibox::kOmniboxPedalsBatch3NonEnglish}, {});
+  feature_list.InitWithFeatures({}, {});
 
   // This used to have a vector of strings for specific trigger testing in each
   // language but those depended on pedal_processor, which is deprecated, so
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
index 9468597..7c01190 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -72,11 +72,14 @@
   auto mode = download::GetDesiredDownloadItemMode(model_.get());
   auto state = model_->GetState();
   bool mode_unchanged = (mode_ == mode);
-  if (mode_unchanged && (state_ == state))
+  bool is_paused = model_->IsPaused();
+  if (mode_unchanged && (state_ == state) && (is_paused_ == is_paused)) {
     return;
+  }
 
   mode_ = mode;
   state_ = state;
+  is_paused_ = is_paused;
 
   // If either of mode or state changes, we might need to change UI.
   ui_info_ = model_->GetBubbleUIInfo();
@@ -268,6 +271,9 @@
   open_now_button_ = AddMainPageButton(
       DownloadCommands::BYPASS_DEEP_SCANNING,
       l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_OPEN_NOW));
+  resume_button_ =
+      AddMainPageButton(DownloadCommands::RESUME,
+                        l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_RESUME));
 
   subpage_icon_holder_ =
       AddChildView(std::make_unique<views::FlexLayoutView>());
@@ -305,6 +311,7 @@
   // Set up initial state.
   mode_ = download::GetDesiredDownloadItemMode(model_.get());
   state_ = model_->GetState();
+  is_paused_ = model_->IsPaused();
   ui_info_ = model_->GetBubbleUIInfo();
   OnDownloadUpdated();
 }
@@ -346,6 +353,8 @@
                            DownloadCommands::DEEP_SCAN);
   open_now_button_->SetVisible(ui_info_.primary_button_command ==
                                DownloadCommands::BYPASS_DEEP_SCANNING);
+  resume_button_->SetVisible(ui_info_.primary_button_command ==
+                             DownloadCommands::RESUME);
   subpage_icon_->SetVisible(ui_info_.has_subpage);
   subpage_icon_->SetBorder(views::CreateEmptyBorder(
       gfx::Insets(ui_info_.has_subpage ? kDownloadSubpageIconMargin : 0)));
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
index 0456a15..9751360 100644
--- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
+++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.h
@@ -108,6 +108,7 @@
   raw_ptr<views::MdTextButton> keep_button_ = nullptr;
   raw_ptr<views::MdTextButton> scan_button_ = nullptr;
   raw_ptr<views::MdTextButton> open_now_button_ = nullptr;
+  raw_ptr<views::MdTextButton> resume_button_ = nullptr;
   raw_ptr<views::FlexLayoutView> main_button_holder_ = nullptr;
 
   // The progress bar for in-progress downloads.
@@ -137,6 +138,7 @@
   download::DownloadItemMode mode_;
   download::DownloadItem::DownloadState state_;
   DownloadUIModel::BubbleUIInfo ui_info_;
+  bool is_paused_;
 
   const gfx::VectorIcon* last_overriden_icon_ = nullptr;
   bool already_set_default_icon_ = false;
diff --git a/chrome/browser/ui/views/extensions/blocked_action_dialog_view.cc b/chrome/browser/ui/views/extensions/blocked_action_dialog_view.cc
index 49baf589..bda80a4 100644
--- a/chrome/browser/ui/views/extensions/blocked_action_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/blocked_action_dialog_view.cc
@@ -7,7 +7,7 @@
 #include "base/feature_list.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/ui_features.h"
-#include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
+#include "chrome/browser/ui/views/extensions/extensions_dialogs_utils.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -33,16 +33,6 @@
 
 DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kCheckboxId);
 
-// TODO(crbug.com/1325171): Use extensions::IconImage instead of getting the
-// action's image. The icon displayed should be the "product" icon and not the
-// "action" action based on the web contents.
-ui::ImageModel GetIcon(ToolbarActionViewController* action,
-                       content::WebContents* web_contents) {
-  return ui::ImageModel::FromImageSkia(
-      action->GetIcon(web_contents, InstalledExtensionMenuItemView::kIconSize)
-          .AsImageSkia());
-}
-
 }  // namespace
 
 // static
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.cc b/chrome/browser/ui/views/extensions/extension_view_views.cc
index a322690..643d7b3 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_view_views.cc
@@ -130,8 +130,8 @@
   ResizeDueToAutoResize(web_contents(), pending_preferred_size_);
 }
 
-gfx::NativeCursor ExtensionViewViews::GetCursor(const ui::MouseEvent& event) {
-  return gfx::kNullCursor;
+ui::Cursor ExtensionViewViews::GetCursor(const ui::MouseEvent& event) {
+  return ui::Cursor();
 }
 
 void ExtensionViewViews::PreferredSizeChanged() {
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.h b/chrome/browser/ui/views/extensions/extension_view_views.h
index 968c4b9..a40ba467 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.h
+++ b/chrome/browser/ui/views/extensions/extension_view_views.h
@@ -61,7 +61,7 @@
   void OnLoaded() override;
 
   // views::WebView:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void PreferredSizeChanged() override;
   void OnWebContentsAttached() override;
 
diff --git a/chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.cc
index a2fdd3b..c475408f 100644
--- a/chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.cc
@@ -11,6 +11,7 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions_toolbar_container.h"
+#include "ui/views/layout/animating_layout_manager_test_util.h"
 
 scoped_refptr<const extensions::Extension>
 ExtensionsDialogBrowserTest::InstallExtension(const std::string& name) {
@@ -19,6 +20,7 @@
   extensions::ExtensionSystem::Get(browser()->profile())
       ->extension_service()
       ->AddExtension(extension.get());
+  views::test::WaitForAnimatingLayoutManager(extensions_container());
   return extension;
 }
 
diff --git a/chrome/browser/ui/views/extensions/extensions_dialogs_utils.cc b/chrome/browser/ui/views/extensions/extensions_dialogs_utils.cc
new file mode 100644
index 0000000..7eb1dfb6
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/extensions_dialogs_utils.cc
@@ -0,0 +1,48 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/extensions/extensions_dialogs_utils.h"
+
+#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
+#include "components/url_formatter/url_formatter.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/layout/flex_layout_view.h"
+
+std::unique_ptr<views::BubbleDialogModelHost::CustomView> CreateExtensionItem(
+    const std::u16string& name,
+    const ui::ImageModel& icon) {
+  const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+  const gfx::Insets content_insets = provider->GetDialogInsetsForContentType(
+      views::DialogContentType::kText, views::DialogContentType::kText);
+
+  return std::make_unique<views::BubbleDialogModelHost::CustomView>(
+      views::Builder<views::FlexLayoutView>()
+          .SetOrientation(views::LayoutOrientation::kHorizontal)
+          .SetMainAxisAlignment(views::LayoutAlignment::kStart)
+          .SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
+          .SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
+              0, content_insets.left(), 0, content_insets.right())))
+          .AddChildren(views::Builder<views::ImageView>().SetImage(icon),
+                       views::Builder<views::Label>().SetText(name))
+          .Build(),
+      views::BubbleDialogModelHost::FieldType::kMenuItem);
+}
+
+// TODO(crbug.com/1325171): Use extensions::IconImage instead of getting the
+// action's image. The icon displayed should be the "product" icon and not the
+// "action" action based on the web contents.
+ui::ImageModel GetIcon(ToolbarActionViewController* action,
+                       content::WebContents* web_contents) {
+  return ui::ImageModel::FromImageSkia(
+      action->GetIcon(web_contents, InstalledExtensionMenuItemView::kIconSize)
+          .AsImageSkia());
+}
+
+std::u16string GetCurrentHost(content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  return url_formatter::IDNToUnicode(
+      url_formatter::StripWWW(web_contents->GetLastCommittedURL().host()));
+}
diff --git a/chrome/browser/ui/views/extensions/extensions_dialogs_utils.h b/chrome/browser/ui/views/extensions/extensions_dialogs_utils.h
new file mode 100644
index 0000000..39b394e
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/extensions_dialogs_utils.h
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_DIALOGS_UTILS_H_
+#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_DIALOGS_UTILS_H_
+
+#include "content/public/browser/web_contents.h"
+#include "ui/views/bubble/bubble_dialog_model_host.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+class ToolbarActionViewController;
+
+std::unique_ptr<views::BubbleDialogModelHost::CustomView> CreateExtensionItem(
+    const std::u16string& name,
+    const ui::ImageModel& icon);
+
+// Returns the icon corresponding to `action` for the given `web_contents`.
+ui::ImageModel GetIcon(ToolbarActionViewController* action,
+                       content::WebContents* web_contents);
+
+// Returns the host of the `web_content`. This method should only be called when
+// web contents are present.
+std::u16string GetCurrentHost(content::WebContents* web_contents);
+
+#endif  // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_DIALOGS_UTILS_H_
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button.cc b/chrome/browser/ui/views/extensions/extensions_request_access_button.cc
index c3652879..8eaf1e1 100644
--- a/chrome/browser/ui/views/extensions/extensions_request_access_button.cc
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_button.cc
@@ -9,7 +9,13 @@
 #include "base/check_op.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.h"
+#include "chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h"
+#include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
+#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
 ExtensionsRequestAccessButton::ExtensionsRequestAccessButton(Browser* browser)
@@ -40,10 +46,8 @@
       !GetWidget()->IsMouseEventsEnabled())
     return;
 
-  content::WebContents* web_contents =
-      browser_->tab_strip_model()->GetActiveWebContents();
   ExtensionsRequestAccessButtonHoverCard::ShowBubble(
-      web_contents, this, extensions_requesting_access_);
+      web_contents(), this, extensions_requesting_access_);
 }
 
 std::u16string ExtensionsRequestAccessButton::GetTooltipText(
@@ -52,9 +56,21 @@
   return std::u16string();
 }
 
-// TODO(crbug.com/1239772): Grant access to all the extensions requesting access
-// when the button is pressed.
-void ExtensionsRequestAccessButton::OnButtonPressed() {}
+void ExtensionsRequestAccessButton::OnButtonPressed() {
+  // TODO(crbug.com/1322796): Multiple classes use this. We should pull getting
+  // an anchor view and showing a BubbleDialogDelegate into a common location.
+  BrowserView* const browser_view =
+      BrowserView::GetBrowserViewForBrowser(browser_);
+  ExtensionsToolbarContainer* const container =
+      browser_view ? browser_view->toolbar_button_provider()
+                         ->GetExtensionsToolbarContainer()
+                   : nullptr;
+  DCHECK(container);
+  views::View* const anchor_view = container->GetExtensionsButton();
+
+  ShowExtensionsRequestAccessDialogView(web_contents(), anchor_view,
+                                        extensions_requesting_access_);
+}
 
 // Linux enter/leave events are sometimes flaky, so we don't want to "miss"
 // an enter event and fail to hover the button. This is effectively a no-op if
@@ -71,3 +87,7 @@
 void ExtensionsRequestAccessButton::OnMouseExited(const ui::MouseEvent& event) {
   ExtensionsRequestAccessButtonHoverCard::HideBubble();
 }
+
+content::WebContents* ExtensionsRequestAccessButton::web_contents() {
+  return browser_->tab_strip_model()->GetActiveWebContents();
+}
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button.h b/chrome/browser/ui/views/extensions/extensions_request_access_button.h
index 8e26d8c..a4d1a2c 100644
--- a/chrome/browser/ui/views/extensions/extensions_request_access_button.h
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_button.h
@@ -7,6 +7,10 @@
 
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 class ToolbarActionViewController;
 class Browser;
 
@@ -38,6 +42,8 @@
  private:
   void OnButtonPressed();
 
+  content::WebContents* web_contents();
+
   raw_ptr<Browser> browser_;
 
   std::vector<ToolbarActionViewController*> extensions_requesting_access_;
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.cc b/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.cc
index 561b254..e822041 100644
--- a/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.cc
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.cc
@@ -5,55 +5,20 @@
 #include "chrome/browser/ui/views/extensions/extensions_request_access_button_hover_card.h"
 
 #include "base/bind.h"
-#include "base/strings/strcat.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/extensions/extensions_menu_item_view.h"
-#include "chrome/browser/ui/views/extensions/extensions_request_access_button.h"
+#include "chrome/browser/ui/views/extensions/extensions_dialogs_utils.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/url_formatter/url_formatter.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/dialog_model.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/bubble/bubble_dialog_model_host.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/layout/flex_layout_view.h"
-#include "ui/views/layout/layout_provider.h"
 #include "ui/views/view.h"
 
 namespace {
 
 views::BubbleDialogModelHost* request_access_bubble = nullptr;
 
-ui::ImageModel GetIcon(ToolbarActionViewController* action,
-                       content::WebContents* web_contents) {
-  return ui::ImageModel::FromImageSkia(
-      action->GetIcon(web_contents, InstalledExtensionMenuItemView::kIconSize)
-          .AsImageSkia());
-}
-
-std::unique_ptr<views::BubbleDialogModelHost::CustomView> CreateExtensionItem(
-    const std::u16string& name,
-    const ui::ImageModel& icon) {
-  const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
-  const gfx::Insets content_insets = provider->GetDialogInsetsForContentType(
-      views::DialogContentType::kText, views::DialogContentType::kText);
-
-  return std::make_unique<views::BubbleDialogModelHost::CustomView>(
-      views::Builder<views::FlexLayoutView>()
-          .SetOrientation(views::LayoutOrientation::kHorizontal)
-          .SetMainAxisAlignment(views::LayoutAlignment::kStart)
-          .SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
-          .SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
-              0, content_insets.left(), 0, content_insets.right())))
-          .AddChildren(views::Builder<views::ImageView>().SetImage(icon),
-                       views::Builder<views::Label>().SetText(name))
-          .Build(),
-      views::BubbleDialogModelHost::FieldType::kMenuItem);
-}
-
 }  // namespace
 
 // static
@@ -64,8 +29,6 @@
   DCHECK(!request_access_bubble);
   DCHECK(web_contents);
   DCHECK(!actions.empty());
-  std::u16string url = url_formatter::IDNToUnicode(
-      url_formatter::StripWWW(web_contents->GetLastCommittedURL().host()));
 
   ui::DialogModel::Builder dialog_builder =
       ui::DialogModel::Builder(std::make_unique<ui::DialogModelDelegate>());
@@ -76,6 +39,7 @@
       .SetDialogDestroyingCallback(
           base::BindOnce(&ExtensionsRequestAccessButtonHoverCard::HideBubble));
 
+  const std::u16string url = GetCurrentHost(web_contents);
   if (actions.size() == 1) {
     dialog_builder.SetIcon(GetIcon(actions[0], web_contents))
         .AddBodyText(ui::DialogModelLabel(l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.cc b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.cc
new file mode 100644
index 0000000..27a5afb
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h"
+
+#include "base/callback_helpers.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
+#include "chrome/browser/ui/views/extensions/extensions_dialogs_utils.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/dialog_model.h"
+#include "ui/views/bubble/bubble_dialog_model_host.h"
+
+void ShowExtensionsRequestAccessDialogView(
+    content::WebContents* web_contents,
+    views::View* anchor_view,
+    std::vector<ToolbarActionViewController*> actions) {
+  DCHECK(!actions.empty());
+
+  ui::DialogModel::Builder dialog_builder =
+      ui::DialogModel::Builder(std::make_unique<ui::DialogModelDelegate>());
+  dialog_builder
+      // TODO(crbug.com/1239772): Grant access to all the extensions when dialog
+      // is accepted
+      .AddOkButton(base::DoNothing(),
+                   l10n_util::GetStringUTF16(
+                       IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_OK_BUTTON_LABEL))
+      .AddCancelButton(
+          base::DoNothing(),
+          l10n_util::GetStringUTF16(
+              IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_CANCEL_BUTTON_LABEL));
+
+  std::u16string current_site = GetCurrentHost(web_contents);
+  if (actions.size() == 1) {
+    dialog_builder.SetTitle(l10n_util::GetStringFUTF16(
+        IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_SINGLE_EXTENSION_TITLE,
+        actions[0]->GetActionName(), current_site));
+  } else {
+    dialog_builder.SetTitle(l10n_util::GetStringFUTF16(
+        IDS_EXTENSIONS_REQUEST_ACCESS_BUBBLE_MULTIPLE_EXTENSIONS_TITLE,
+        current_site));
+    for (auto* action : actions) {
+      dialog_builder.AddCustomField(CreateExtensionItem(
+          action->GetActionName(), GetIcon(action, web_contents)));
+    }
+  }
+
+  auto bubble = std::make_unique<views::BubbleDialogModelHost>(
+      dialog_builder.Build(), anchor_view, views::BubbleBorder::TOP_RIGHT);
+  views::BubbleDialogDelegate::CreateBubble(std::move(bubble))->Show();
+}
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h
new file mode 100644
index 0000000..244fcd50
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_REQUEST_ACCESS_DIALOG_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_REQUEST_ACCESS_DIALOG_VIEW_H_
+
+#include <vector>
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace views {
+class View;
+}  // namespace views
+
+class ToolbarActionViewController;
+
+void ShowExtensionsRequestAccessDialogView(
+    content::WebContents* web_contents,
+    views::View* anchor_view,
+    std::vector<ToolbarActionViewController*> extensions);
+
+#endif  // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_REQUEST_ACCESS_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view_browsertest.cc
new file mode 100644
index 0000000..bfeaf5e
--- /dev/null
+++ b/chrome/browser/ui/views/extensions/extensions_request_access_dialog_view_browsertest.cc
@@ -0,0 +1,43 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/extensions/extensions_request_access_dialog_view.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/views/extensions/extensions_dialogs_browsertest.h"
+#include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
+#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h"
+#include "content/public/test/browser_test.h"
+
+class ExtensionsRequestAccessDialogViewBrowserTest
+    : public ExtensionsDialogBrowserTest {
+ public:
+  // DialogBrowserTest:
+  void ShowUi(const std::string& name) override {
+    // Install extension so the extensions menu button is visible and can serve
+    // as the dialog's anchor point.
+    InstallExtension("Extension");
+    views::View* const anchor_view =
+        extensions_container()->GetExtensionsButton();
+    EXPECT_TRUE(anchor_view->GetVisible());
+
+    auto controller_A = std::make_unique<TestToolbarActionViewController>("A");
+    std::vector<ToolbarActionViewController*> extensions_requesting_access;
+    extensions_requesting_access.push_back(controller_A.get());
+
+    ShowExtensionsRequestAccessDialogView(
+        browser()->tab_strip_model()->GetActiveWebContents(), anchor_view,
+        extensions_requesting_access);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      features::kExtensionsMenuAccessControl};
+};
+
+IN_PROC_BROWSER_TEST_F(ExtensionsRequestAccessDialogViewBrowserTest, InvokeUi) {
+  ShowAndVerifyUi();
+}
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
index f0a874d..4e242f4 100644
--- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
+++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -136,7 +136,7 @@
     event->SetHandled();
   }
 
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override {
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override {
     auto pair = GetParentWidgetAndEvent(this, &event);
     if (pair.widget) {
       views::View* omnibox_view =
@@ -145,7 +145,7 @@
       return omnibox_view->GetCursor(*pair.event);
     }
 
-    return nullptr;
+    return ui::Cursor();
   }
 #endif  // !USE_AURA
 
diff --git a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
index d566dbf..a3ac6c0 100644
--- a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
+++ b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
@@ -13,7 +13,6 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/vector_icons.h"
 
 namespace {
@@ -63,8 +62,8 @@
 
 BackToTabLabelButton::~BackToTabLabelButton() = default;
 
-gfx::NativeCursor BackToTabLabelButton::GetCursor(const ui::MouseEvent& event) {
-  return views::GetNativeHandCursor();
+ui::Cursor BackToTabLabelButton::GetCursor(const ui::MouseEvent& event) {
+  return ui::mojom::CursorType::kHand;
 }
 
 void BackToTabLabelButton::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/overlay/back_to_tab_label_button.h b/chrome/browser/ui/views/overlay/back_to_tab_label_button.h
index b802448c..233aa5d 100644
--- a/chrome/browser/ui/views/overlay/back_to_tab_label_button.h
+++ b/chrome/browser/ui/views/overlay/back_to_tab_label_button.h
@@ -20,7 +20,7 @@
   ~BackToTabLabelButton() override;
 
   // views::View:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void OnThemeChanged() override;
 
   // Updates the position of this button within the new bounds of the window.
diff --git a/chrome/browser/ui/views/overlay/overlay_window_image_button.cc b/chrome/browser/ui/views/overlay/overlay_window_image_button.cc
index 59a4710..6d609f3e 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_image_button.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_image_button.cc
@@ -11,7 +11,6 @@
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/highlight_path_generator.h"
-#include "ui/views/native_cursor.h"
 
 OverlayWindowImageButton::OverlayWindowImageButton(PressedCallback callback)
     : ImageButton(std::move(callback)) {
@@ -24,9 +23,8 @@
   SetInstallFocusRingOnFocus(true);
 }
 
-gfx::NativeCursor OverlayWindowImageButton::GetCursor(
-    const ui::MouseEvent& event) {
-  return views::GetNativeHandCursor();
+ui::Cursor OverlayWindowImageButton::GetCursor(const ui::MouseEvent& event) {
+  return ui::mojom::CursorType::kHand;
 }
 
 void OverlayWindowImageButton::OnThemeChanged() {
diff --git a/chrome/browser/ui/views/overlay/overlay_window_image_button.h b/chrome/browser/ui/views/overlay/overlay_window_image_button.h
index cbc723f..fd4ea1f 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_image_button.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_image_button.h
@@ -21,7 +21,7 @@
   ~OverlayWindowImageButton() override = default;
 
   // views::View:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void OnThemeChanged() override;
 };
 
diff --git a/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.cc b/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.cc
index 402c77b..4779496 100644
--- a/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.cc
+++ b/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.cc
@@ -56,6 +56,14 @@
                           base::Unretained(this))));
 }
 
+void UserNoteUICoordinator::OnNoteDeleted(const base::UnguessableToken& id,
+                                          UserNoteView* user_note_view) {
+  scroll_contents_view_->RemoveChildView(user_note_view);
+  auto* service =
+      user_notes::UserNoteServiceFactory::GetForContext(browser_->profile());
+  service->OnNoteDeleted(id);
+}
+
 void UserNoteUICoordinator::OnNoteCreationDone(
     const base::UnguessableToken& id,
     const std::string& note_content) {
@@ -65,21 +73,12 @@
 }
 
 void UserNoteUICoordinator::OnNoteCreationCancelled(
-    const base::UnguessableToken& id,
-    UserNoteView* user_note_view) {
-  scroll_contents_view_->RemoveChildView(user_note_view);
+    const base::UnguessableToken& id) {
   auto* service =
       user_notes::UserNoteServiceFactory::GetForContext(browser_->profile());
   service->OnNoteCreationCancelled(id);
 }
 
-void UserNoteUICoordinator::OnNoteUpdated(const base::UnguessableToken& id,
-                                          const std::string& note_content) {
-  auto* service =
-      user_notes::UserNoteServiceFactory::GetForContext(browser_->profile());
-  service->OnNoteUpdated(id, note_content);
-}
-
 void UserNoteUICoordinator::FocusNote(const std::string& guid) {
   // TODO(cheickcisse): Implement FocusNote, which will be called by
   // UserNoteService to inform, inform the user note side panel to scroll the
diff --git a/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.h b/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.h
index cb4c473..a20c522 100644
--- a/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.h
+++ b/chrome/browser/ui/views/side_panel/user_note/user_note_ui_coordinator.h
@@ -17,7 +17,6 @@
 }
 
 class SidePanelRegistry;
-class UserNoteView;
 
 class UserNoteUICoordinator : public user_notes::UserNotesUI,
                               public TabStripModelObserver,
@@ -32,12 +31,11 @@
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kScrollViewElementIdForTesting);
 
   void CreateAndRegisterEntry(SidePanelRegistry* global_registry);
+  void OnNoteDeleted(const base::UnguessableToken& id,
+                     UserNoteView* user_note_view);
   void OnNoteCreationDone(const base::UnguessableToken& id,
                           const std::string& note_content);
-  void OnNoteCreationCancelled(const base::UnguessableToken& id,
-                               UserNoteView* user_note_view);
-  void OnNoteUpdated(const base::UnguessableToken& id,
-                     const std::string& note_content);
+  void OnNoteCreationCancelled(const base::UnguessableToken& id);
 
   // UserNoteUI overrides
   void FocusNote(const std::string& guid) override;
diff --git a/chrome/browser/ui/views/side_panel/user_note/user_note_view.cc b/chrome/browser/ui/views/side_panel/user_note/user_note_view.cc
index da8da4de..dd42159 100644
--- a/chrome/browser/ui/views/side_panel/user_note/user_note_view.cc
+++ b/chrome/browser/ui/views/side_panel/user_note/user_note_view.cc
@@ -33,13 +33,11 @@
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/layout/layout_types.h"
-#include "ui/views/view_utils.h"
 
 namespace {
 
 constexpr int kUserNoteDateViewId = 180;
 constexpr int kUserNoteMenuButtonViewId = 181;
-constexpr int kUserNoteQuoteViewId = 182;
 
 // Layout structure:
 //
@@ -127,7 +125,6 @@
   user_note_quote->SetMultiLine(true);
   user_note_quote->SetMaxLines(user_note_quote_max_lines);
   user_note_quote->SetElideBehavior(gfx::ELIDE_TAIL);
-  user_note_quote->SetID(kUserNoteQuoteViewId);
   // User note quote layout
   const views::FlexSpecification text_flex(
       views::LayoutOrientation::kVertical,
@@ -151,11 +148,10 @@
 
 // Layout structure:
 //
-// [    cancel (add or save)]  <--- button container
+// [    cancel add]  <--- button container
 std::unique_ptr<views::View> CreateButtonsView(
     base::RepeatingClosure cancel_callback,
-    base::RepeatingClosure action_callback,
-    UserNoteView::State state) {
+    base::RepeatingClosure add_callback) {
   auto button_container = std::make_unique<views::View>();
 
   // Cancel button
@@ -166,14 +162,12 @@
   cancel_button->SetEnabledTextColors(SK_ColorBLUE);
   button_container->AddChildView(std::move(cancel_button));
 
-  // Action button
-  auto action_button = std::make_unique<views::MdTextButton>(
-      action_callback,
-      l10n_util::GetStringUTF16(
-          state == UserNoteView::State::kCreating ? IDS_ADD : IDS_SAVE));
-  action_button->SetCustomPadding(button_padding);
-  action_button->SetProminent(true);
-  button_container->AddChildView(std::move(action_button));
+  // Add button
+  auto add_button = std::make_unique<views::MdTextButton>(
+      add_callback, l10n_util::GetStringUTF16(IDS_ADD));
+  add_button->SetCustomPadding(button_padding);
+  add_button->SetProminent(true);
+  button_container->AddChildView(std::move(add_button));
 
   // Button container layout
   ChromeLayoutProvider* const chrome_layout_provider =
@@ -246,8 +240,10 @@
   const int corner_radius = views::LayoutProvider::Get()->GetCornerRadiusMetric(
       views::Emphasis::kHigh);
   const int rounded_border_thickness = 1;
-  const SkColor border_color =
-      UserNoteView::State::kCreating == state ? SK_ColorBLUE : SK_ColorLTGRAY;
+  const SkColor border_color = UserNoteView::State::kCreating == state ||
+                                       UserNoteView::State::kEditing == state
+                                   ? SK_ColorBLUE
+                                   : SK_ColorLTGRAY;
 
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical)
@@ -269,7 +265,7 @@
                                              const std::string quote) {
   if (user_note_header_) {
     user_note_header_->SetVisible(true);
-    views::Label* date_view = views::AsViewClass<views::Label>(
+    views::Label* date_view = static_cast<views::Label*>(
         user_note_header_->GetViewByID(kUserNoteDateViewId));
     date_view->SetText(ConvertDate(date));
   } else {
@@ -294,8 +290,7 @@
   }
 }
 
-void UserNoteView::SetCreatingOrEditState(const std::string content,
-                                          UserNoteView::State state) {
+void UserNoteView::SetCreatingOrEditState(const std::string content) {
   if (text_area_) {
     text_area_->SetVisible(true);
   } else {
@@ -309,13 +304,10 @@
     button_container_->SetVisible(true);
   } else {
     button_container_ = AddChildView(CreateButtonsView(
-        base::BindRepeating(&UserNoteView::OnCancelUserNote,
-                            base::Unretained(this), state),
-        base::BindRepeating(state == UserNoteView::State::kCreating
-                                ? &UserNoteView::OnAddUserNote
-                                : &UserNoteView::OnSaveUserNote,
+        base::BindRepeating(&UserNoteView::OnCancelNewUserNote,
                             base::Unretained(this)),
-        state));
+        base::BindRepeating(&UserNoteView::OnAddUserNote,
+                            base::Unretained(this))));
   }
 }
 
@@ -328,13 +320,13 @@
       SetDefaultOrDetachedState(date, content, /*quote =*/std::string());
       break;
     case UserNoteView::State::kCreating:
-      SetCreatingOrEditState(/*content =*/std::string(), state);
+      SetCreatingOrEditState(/*content =*/std::string());
       break;
-    case UserNoteView::State::kDetached:
+    case UserNoteView::State::kOrphaned:
       SetDefaultOrDetachedState(date, content, quote);
       break;
     case UserNoteView::State::kEditing:
-      SetCreatingOrEditState(content, state);
+      SetCreatingOrEditState(content);
       break;
     default:
       SetBorder(nullptr);
@@ -376,22 +368,8 @@
   dialog_model_ = nullptr;
 }
 
-void UserNoteView::OnCancelUserNote(UserNoteView::State state) {
-  if (state == UserNoteView::State::kCreating) {
-    coordinator_->OnNoteCreationCancelled(UserNoteId(), this);
-    return;
-  }
-
-  // Hide editing state
-  GetBorder()->set_color(SK_ColorLTGRAY);
-  text_area_->SetVisible(false);
-  button_container_->SetVisible(false);
-
-  // Show default/detached state
-  user_note_body_->SetVisible(false);
-  if (user_note_quote_)
-    user_note_quote_->SetVisible(false);
-  user_note_header_->SetVisible(false);
+void UserNoteView::OnCancelNewUserNote() {
+  coordinator_->OnNoteCreationCancelled(UserNoteId());
 }
 
 void UserNoteView::OnAddUserNote() {
@@ -413,51 +391,13 @@
 }
 
 void UserNoteView::OnEditUserNote(int event_flags) {
-  const std::u16string note_content = user_note_body_->GetText();
-
-  // Hide default/detached state
-  GetBorder()->set_color(SK_ColorBLUE);
-  user_note_body_->SetVisible(false);
-  user_note_header_->SetVisible(false);
-  if (user_note_quote_) {
-    user_note_quote_->SetVisible(false);
-
-    // Show editing state
-    CreateOrUpdateNoteView(UserNoteView::State::kEditing, base::Time(),
-                           base::UTF16ToUTF8(note_content),
-                           /*quote =*/std::string());
-  }
+  // TODO(cheickcisse): Edit existing note.
 }
 
 void UserNoteView::OnDeleteUserNote(int event_flags) {
-  // TODO(cheickcisse): Delete existing note.
+  coordinator_->OnNoteDeleted(UserNoteId(), this);
 }
 
 void UserNoteView::OnLearnUserNote(int event_flags) {
   // TODO(cheickcisse): Learn more about user note.
 }
-
-void UserNoteView::OnSaveUserNote() {
-  const std::u16string note_content = text_area_->GetText();
-  const std::u16string note_quote =
-      user_note_quote_
-          ? views::AsViewClass<views::Label>(
-                user_note_quote_->GetViewByID(kUserNoteQuoteViewId))
-                ->GetText()
-          : std::u16string();
-  base::Time date = base::Time::Now();
-
-  // Hide editing state
-  GetBorder()->set_color(SK_ColorLTGRAY);
-  text_area_->SetVisible(false);
-  button_container_->SetVisible(false);
-
-  // Show default state
-  CreateOrUpdateNoteView(
-      user_note_quote_ ? UserNoteView::State::kDetached
-                       : UserNoteView::State::kDefault,
-      date, base::UTF16ToUTF8(note_content),
-      !note_quote.empty() ? base::UTF16ToUTF8(note_quote) : std::string());
-
-  coordinator_->OnNoteUpdated(UserNoteId(), base::UTF16ToUTF8(note_content));
-}
diff --git a/chrome/browser/ui/views/side_panel/user_note/user_note_view.h b/chrome/browser/ui/views/side_panel/user_note/user_note_view.h
index aa8f2d9b..de0c96a1 100644
--- a/chrome/browser/ui/views/side_panel/user_note/user_note_view.h
+++ b/chrome/browser/ui/views/side_panel/user_note/user_note_view.h
@@ -42,9 +42,9 @@
     kCreating,
     // State that will display an existing user note to be edited.
     kEditing,
-    // State that will display a detached user note (note without a highlight
-    // on the page).
-    kDetached
+    // State that will display an orphan user note (note without a highlight in
+    // the page).
+    kOrphaned
   };
 
   explicit UserNoteView(
@@ -64,16 +64,14 @@
                               base::Time date,
                               const std::string content,
                               const std::string quote);
-  void OnCancelUserNote(UserNoteView::State state);
+  void OnCancelNewUserNote();
   void OnAddUserNote();
-  void OnSaveUserNote();
-  void OnOpenMenu();
-  void OnMenuClosed();
   void OnEditUserNote(int event_flags);
   void OnDeleteUserNote(int event_flags);
   void OnLearnUserNote(int event_flags);
-  void SetCreatingOrEditState(const std::string content,
-                              UserNoteView::State state);
+  void OnOpenMenu();
+  void OnMenuClosed();
+  void SetCreatingOrEditState(const std::string content);
   void SetDefaultOrDetachedState(base::Time date,
                                  const std::string content,
                                  const std::string quote);
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.cc b/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.cc
index 8701683..9eb6b79 100644
--- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.cc
+++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.cc
@@ -13,6 +13,7 @@
 #include "components/constrained_window/constrained_window_views.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/views/layout/layout_provider.h"
 #include "url/gurl.h"
 
 // TODO(b/223434114): Add tests for AccessCodeCastDialog
@@ -30,6 +31,9 @@
 
 }  // namespace
 
+// The corner radius for system dialogs.
+constexpr int kSystemDialogCornerRadiusDp = 12;
+
 AccessCodeCastDialog::AccessCodeCastDialog(
     const CastModeSet& cast_mode_set,
     std::unique_ptr<MediaRouteStarter> media_route_starter)
@@ -51,7 +55,7 @@
     dialog_widget_->RemoveObserver(this);
 }
 
-void AccessCodeCastDialog::ShowWebDialog() {
+void AccessCodeCastDialog::ShowWebDialog(AccessCodeCastDialogMode dialog_mode) {
   // After a dialog is shown, |media_route_starter_| is transferred to the
   // associated |AccessCodeCastUI| - see |OnDialogShown| below. Since the c'tor
   // ensures that a |MediaRouteStarter| is passed in, if |media_route_starter_|
@@ -60,7 +64,7 @@
   if (!media_route_starter_)
     return;
 
-  auto extra_params = CreateParams();
+  auto extra_params = CreateParams(dialog_mode);
 
   dialog_creation_timestamp_ = base::Time::Now();
   gfx::NativeWindow dialog_window = chrome::ShowWebDialogWithParams(
@@ -70,7 +74,8 @@
   auto* dialog_widget = views::Widget::GetWidgetForNativeWindow(dialog_window);
   ObserveWidget(dialog_widget);
 
-  if (web_contents_) {
+  if (dialog_mode == AccessCodeCastDialogMode::kBrowserStandard &&
+      web_contents_) {
     constrained_window::UpdateWidgetModalDialogPosition(
         dialog_widget,
         CreateChromeConstrainedWindowViewsClient()->GetModalDialogHost(
@@ -82,11 +87,12 @@
 void AccessCodeCastDialog::Show(
     const media_router::CastModeSet& cast_mode_set,
     std::unique_ptr<media_router::MediaRouteStarter> media_route_starter,
-    AccessCodeCastDialogOpenLocation open_location) {
+    AccessCodeCastDialogOpenLocation open_location,
+    AccessCodeCastDialogMode dialog_mode) {
   std::unique_ptr<AccessCodeCastDialog> dialog =
       std::make_unique<AccessCodeCastDialog>(cast_mode_set,
                                              std::move(media_route_starter));
-  dialog->ShowWebDialog();
+  dialog->ShowWebDialog(dialog_mode);
   AccessCodeCastMetrics::RecordDialogOpenLocation(open_location);
   SetCurrentDialog(std::move(dialog));
 }
@@ -97,13 +103,20 @@
   CastModeSet desktop_mode = {MediaCastMode::DESKTOP_MIRROR};
   std::unique_ptr<MediaRouteStarter> starter =
       std::make_unique<MediaRouteStarter>(desktop_mode, nullptr, nullptr);
-  Show(desktop_mode, std::move(starter), open_location);
+  Show(desktop_mode, std::move(starter), open_location,
+       AccessCodeCastDialogMode::kSystem);
 }
 
-views::Widget::InitParams AccessCodeCastDialog::CreateParams() {
+views::Widget::InitParams AccessCodeCastDialog::CreateParams(
+    AccessCodeCastDialogMode dialog_mode) {
   views::Widget::InitParams params;
   params.remove_standard_frame = true;
-  params.corner_radius = 12;
+  // Use the corner radius which matches style based on the appropriate mode.
+  params.corner_radius =
+      (dialog_mode == AccessCodeCastDialogMode::kBrowserStandard)
+          ? views::LayoutProvider::Get()->GetCornerRadiusMetric(
+                views::Emphasis::kMedium)
+          : kSystemDialogCornerRadiusDp;
   params.type = views::Widget::InitParams::Type::TYPE_BUBBLE;
   // Make sure the dialog border is rendered correctly
   params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
diff --git a/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.h b/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.h
index 2e9f4b5..fb05358 100644
--- a/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.h
+++ b/chrome/browser/ui/webui/access_code_cast/access_code_cast_dialog.h
@@ -22,6 +22,17 @@
 }  // namespace content
 
 namespace media_router {
+
+enum class AccessCodeCastDialogMode {
+  // Dialog opened from the browser. This will match the styling of other
+  // browser dialogs (i.e. Cast dialog), and will be positioned in the center of
+  // the window and overlapping top-chrome.
+  kBrowserStandard = 0,
+  // Dialog is shown system modal, and matches the style for ChromeOS system
+  // dialogs.
+  kSystem = 1,
+};
+
 class AccessCodeCastDialog : public ui::WebDialogDelegate,
                              public views::WidgetObserver {
  public:
@@ -35,7 +46,9 @@
   static void Show(
       const media_router::CastModeSet& cast_mode_set,
       std::unique_ptr<media_router::MediaRouteStarter> media_route_starter,
-      AccessCodeCastDialogOpenLocation open_location);
+      AccessCodeCastDialogOpenLocation open_location,
+      AccessCodeCastDialogMode dialog_mode =
+          AccessCodeCastDialogMode::kBrowserStandard);
 
   // Show the access code dialog box for desktop mirroring.
   static void ShowForDesktopMirroring(
@@ -46,7 +59,8 @@
 
  protected:
   // Creates default params for showing AccessCodeCastDialog
-  virtual views::Widget::InitParams CreateParams();
+  virtual views::Widget::InitParams CreateParams(
+      AccessCodeCastDialogMode dialog_mode);
 
  private:
   ui::ModalType GetDialogModalType() const override;
@@ -72,7 +86,7 @@
                                   blink::mojom::MediaStreamType type) override;
 
   // Displays the dialog
-  void ShowWebDialog();
+  void ShowWebDialog(AccessCodeCastDialogMode dialog_mode);
 
   gfx::NativeView GetParentView();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
index fb4021e9..c34281e0 100644
--- a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.cc
@@ -17,6 +17,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/login/localized_values_builder.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/chromeos/devicetype_utils.h"
 
 namespace {
 
@@ -84,14 +85,40 @@
 
 void RecommendAppsScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
-  builder->Add("recommendAppsScreenTitle",
-               IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE);
+  // TODO(crbug.com/1261902): Clean-up old strings once feature is launched.
+  builder->Add("recommendAppsLoading", IDS_LOGIN_RECOMMEND_APPS_SCREEN_LOADING);
+  if (!features::IsOobeNewRecommendAppsEnabled()) {
+    builder->Add("recommendAppsScreenTitle",
+                 IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_TITLE);
+    builder->Add("recommendAppsScreenDescription",
+                 IDS_LOGIN_RECOMMEND_APPS_OLD_SCREEN_DESCRIPTION);
+    builder->Add("recommendAppsSkip", IDS_LOGIN_RECOMMEND_APPS_DO_IT_LATER);
+    builder->Add("recommendAppsInstall", IDS_LOGIN_RECOMMEND_APPS_DONE);
+    builder->Add("recommendAppsSelectAll",
+                 IDS_LOGIN_RECOMMEND_APPS_OLD_SELECT_ALL);
+    return;
+  }
+  builder->AddF("recommendAppsScreenTitle",
+                IDS_LOGIN_RECOMMEND_APPS_SCREEN_TITLE,
+                ui::GetChromeOSDeviceName());
   builder->Add("recommendAppsScreenDescription",
                IDS_LOGIN_RECOMMEND_APPS_SCREEN_DESCRIPTION);
-  builder->Add("recommendAppsSkip", IDS_LOGIN_RECOMMEND_APPS_DO_IT_LATER);
-  builder->Add("recommendAppsInstall", IDS_LOGIN_RECOMMEND_APPS_DONE);
-  builder->Add("recommendAppsLoading", IDS_LOGIN_RECOMMEND_APPS_SCREEN_LOADING);
+  builder->Add("recommendAppsSkip", IDS_LOGIN_RECOMMEND_APPS_SKIP);
+  builder->Add("recommendAppsInstall", IDS_LOGIN_RECOMMEND_APPS_INSTALL);
   builder->Add("recommendAppsSelectAll", IDS_LOGIN_RECOMMEND_APPS_SELECT_ALL);
+  builder->Add("recommendAppsInAppPurchases",
+               IDS_LOGIN_RECOMMEND_APPS_SCREEN_IN_APP_PURCHASES);
+  builder->Add("recommendAppsWasInstalled",
+               IDS_LOGIN_RECOMMEND_APPS_SCREEN_WAS_INSTALLED);
+  builder->Add("recommendAppsContainsAds",
+               IDS_LOGIN_RECOMMEND_APPS_SCREEN_CONTAINS_ADS);
+}
+
+void RecommendAppsScreenHandler::GetAdditionalParameters(
+    base::Value::Dict* dict) {
+  dict->Set("isOobeNewRecommendAppsEnabled",
+            features::IsOobeNewRecommendAppsEnabled());
+  BaseScreenHandler::GetAdditionalParameters(dict);
 }
 
 void RecommendAppsScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
index c301164..093ac999 100644
--- a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
@@ -58,6 +58,7 @@
   // BaseScreenHandler:
   void DeclareLocalizedValues(
       ::login::LocalizedValuesBuilder* builder) override;
+  void GetAdditionalParameters(base::Value::Dict* dict) override;
   void RegisterMessages() override;
 
   // RecommendAppsScreenView:
diff --git a/chrome/browser/win/browser_util.cc b/chrome/browser/win/browser_util.cc
index 31541c5..9d99ca6 100644
--- a/chrome/browser/win/browser_util.cc
+++ b/chrome/browser/win/browser_util.cc
@@ -6,12 +6,17 @@
 
 #include <windows.h>
 
+// sddl.h must come after windows.h.
+#include <sddl.h>
+
 #include <algorithm>
 #include <string>
 
 #include "base/base_paths.h"
+#include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/win/scoped_localalloc.h"
 #include "sandbox/win/src/win_utils.h"
 
 namespace browser_util {
@@ -46,7 +51,32 @@
   nt_dir_name = L"Global\\" + nt_dir_name;
   if (handle != NULL)
     ::CloseHandle(handle);
-  handle = ::CreateEventW(NULL, TRUE, TRUE, nt_dir_name.c_str());
+
+  // For this to work for both user and system installs, we need the event to be
+  // accessible to all interactive users so that we can correctly detect any
+  // instance they are running. Otherwise, we can end up executing pending
+  // upgrade actions while there are instances running, resulting in reliability
+  // issues for one of the users.
+  // Security Descriptor for the global browser running event:
+  //   SYSTEM : EVENT_ALL_ACCESS
+  //   Interactive User : EVENT_ALL_ACCESS
+  static constexpr wchar_t kAllAccessDescriptor[] =
+      L"D:P(A;;0x1F0003;;;SY)(A;;0x1F0003;;;IU)";
+  SECURITY_ATTRIBUTES attributes = {sizeof(SECURITY_ATTRIBUTES), nullptr,
+                                    FALSE};
+  if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
+          kAllAccessDescriptor, SDDL_REVISION_1,
+          &attributes.lpSecurityDescriptor, nullptr)) {
+    // If this fails, it usually means the security descriptor string is
+    // incorrect. As a fallback, create the event with the default descriptor
+    // by setting it to nullptr. This works for single user devices which is the
+    // most common case for Windows.
+    DPCHECK(false);
+    attributes.lpSecurityDescriptor = nullptr;
+  }
+  base::win::ScopedLocalAlloc scoped_sd(attributes.lpSecurityDescriptor);
+
+  handle = ::CreateEventW(&attributes, TRUE, TRUE, nt_dir_name.c_str());
   int error = ::GetLastError();
   return (error == ERROR_ALREADY_EXISTS || error == ERROR_ACCESS_DENIED);
 }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 6a088ed0..a165fc5 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1653393368-182a44bff780721f596be205111fb888cbbc2d54.profdata
+chrome-linux-main-1653415098-194ce5295f1889c17c5cbd97f10e30c876505bb6.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index b55e71e12..f4aa3679c 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1653403745-f35eb8169ac9d084cffac5f6d0e91b6d7f94857f.profdata
+chrome-win32-main-1653425953-ad7d9e0719b7ebad97915bd174f932f66c814492.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 6f3e5c6..3ad7cf6 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1653403745-9de227c605c94c6a39022a81c782aaca275139c8.profdata
+chrome-win64-main-1653425953-c386d65c130cd126e918ffff37a1d32f1be36ece.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d11a3e6f..c777bc9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3196,6 +3196,7 @@
         "../browser/ui/views/extensions/extensions_dialogs_browsertest.cc",
         "../browser/ui/views/extensions/extensions_dialogs_browsertest.h",
         "../browser/ui/views/extensions/extensions_request_access_button_hover_card_browsertest.cc",
+        "../browser/ui/views/extensions/extensions_request_access_dialog_view_browsertest.cc",
         "../browser/ui/views/extensions/media_galleries_dialog_views_browsertest.cc",
         "../browser/ui/views/extensions/settings_overridden_dialog_view_browsertest.cc",
         "../browser/ui/views/external_protocol_dialog_browsertest.cc",
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserService.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserService.java
index 8332dd56..f5e3dfe8 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserService.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserService.java
@@ -8,23 +8,38 @@
 import android.content.Intent;
 import android.os.IBinder;
 
+import org.chromium.base.Log;
+
 /**
- * This Service allows launching the Cast browser module through an Intent. When the service is
- * created, the browser main loop will start. This allows launching the browser module separately
- * from the base module, so that the memory overhead of the browser is only incurred when needed.
+ * This Service allows launching the Cast browser module through an Intent. When
+ * the service is created, the browser main loop will start. This allows
+ * launching the browser module separately from the base module, so that the
+ * memory overhead of the browser is only incurred when needed.
+ * 
+ * The owner must use Context.startService\stopService APIs to start the browser
+ * process. This bindService should not be used as it binds the browser service
+ * lifetime to the cast service one, hence resulting in more memory usage in
+ * idle.
  */
 public class CastBrowserService extends Service {
-    @Override
-    public void onCreate() {}
+    private static final String TAG = "CastBrowserService";
 
     @Override
     public IBinder onBind(Intent intent) {
-        CastBrowserHelper.initializeBrowser(getApplicationContext(), intent);
+        Log.d(TAG, "onBind");
         return null;
     }
 
     @Override
-    public boolean onUnbind(Intent intent) {
-        return true;
+    public int onStartCommand(Intent intent, int flag, int startId) {
+        Log.d(TAG, "onStartCommand");
+        CastBrowserHelper.initializeBrowser(getApplicationContext(), intent);
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy");
+        stopSelf();
     }
 }
diff --git a/chromecast/browser/extensions/api/tabs/tabs_api.cc b/chromecast/browser/extensions/api/tabs/tabs_api.cc
index 862bb47..26af6a10 100644
--- a/chromecast/browser/extensions/api/tabs/tabs_api.cc
+++ b/chromecast/browser/extensions/api/tabs/tabs_api.cc
@@ -891,7 +891,7 @@
     return RespondNow(Error(keys::kCannotZoomDisabledTabError));
   }
 
-  return RespondNow(ArgumentList(nullptr));
+  return RespondNow(ArgumentList(std::vector<base::Value>()));
 }
 
 ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
@@ -964,7 +964,7 @@
 
   ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode);
 
-  return RespondNow(ArgumentList(nullptr));
+  return RespondNow(ArgumentList(std::vector<base::Value>()));
 }
 
 ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/tile/TileView.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/tile/TileView.java
index 2e0d0e7..eafa673 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/tile/TileView.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/tile/TileView.java
@@ -5,7 +5,6 @@
 package org.chromium.components.browser_ui.widget.tile;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
@@ -14,7 +13,6 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.components.browser_ui.widget.R;
 import org.chromium.components.browser_ui.widget.RoundedCornerOutlineProvider;
 
@@ -80,13 +78,6 @@
         mIconView.setImageDrawable(icon);
     }
 
-    /**
-     * Applies or clears icon tint.
-     */
-    public void setIconTint(ColorStateList color) {
-        ApiCompatibilityUtils.setImageTintList(mIconView, color);
-    }
-
     /** Shows or hides the offline badge to reflect the offline availability. */
     protected void setOfflineBadgeVisibility(boolean showOfflineBadge) {
         mBadgeView.setVisibility(showOfflineBadge ? VISIBLE : GONE);
diff --git a/components/commerce/core/BUILD.gn b/components/commerce/core/BUILD.gn
index 0ebe5fbc..5fd812ec 100644
--- a/components/commerce/core/BUILD.gn
+++ b/components/commerce/core/BUILD.gn
@@ -69,7 +69,10 @@
 
 proto_library("proto") {
   proto_in_dir = "//"
-  sources = [ "proto/price_tracking.proto" ]
+  sources = [
+    "proto/merchant_trust.proto",
+    "proto/price_tracking.proto",
+  ]
 }
 
 if (is_android) {
diff --git a/components/commerce/core/proto/merchant_trust.proto b/components/commerce/core/proto/merchant_trust.proto
new file mode 100644
index 0000000..e14e298c
--- /dev/null
+++ b/components/commerce/core/proto/merchant_trust.proto
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+package commerce;
+
+option java_package = "org.chromium.components.commerce";
+
+option optimize_for = LITE_RUNTIME;
+
+message MerchantTrustSignalsV2 {
+  // Overall rating out of 5.
+  optional float merchant_star_rating = 1;
+
+  // Total number of reviews.
+  optional int32 merchant_count_rating = 2;
+
+  // Link to the merchant details page.
+  optional string merchant_details_page_url = 3;
+
+  // Whether we have return policy for the merchant.
+  optional bool has_return_policy = 4;
+
+  // Non-personalized familiarity score of the merchant, ranged from 0 to 1.
+  optional float non_personalized_familiarity_score = 5;
+
+  // Whether the merchant contains sensitive content.
+  optional bool contains_sensitive_content = 6;
+
+  // Whether proactively showing message is disabled for the merchant.
+  optional bool proactive_message_disabled = 7;
+}
diff --git a/components/commerce/core/shopping_service.cc b/components/commerce/core/shopping_service.cc
index e70efb3..00cf2263 100644
--- a/components/commerce/core/shopping_service.cc
+++ b/components/commerce/core/shopping_service.cc
@@ -14,6 +14,7 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/commerce/core/commerce_feature_list.h"
 #include "components/commerce/core/metrics/metrics_utils.h"
+#include "components/commerce/core/proto/merchant_trust.pb.h"
 #include "components/commerce/core/proto/price_tracking.pb.h"
 #include "components/commerce/core/shopping_bookmark_model_observer.h"
 #include "components/commerce/core/web_wrapper.h"
@@ -25,6 +26,9 @@
 
 ProductInfo::ProductInfo() = default;
 ProductInfo::~ProductInfo() = default;
+MerchantInfo::MerchantInfo() = default;
+MerchantInfo::MerchantInfo(MerchantInfo&&) = default;
+MerchantInfo::~MerchantInfo() = default;
 
 ShoppingService::ShoppingService(
     bookmarks::BookmarkModel* bookmark_model,
@@ -43,6 +47,9 @@
       types.push_back(
           optimization_guide::proto::OptimizationType::PRICE_TRACKING);
     }
+    if (IsMerchantInfoApiEnabled()) {
+      types.push_back(optimization_guide::proto::MERCHANT_TRUST_SIGNALS_V2);
+    }
 
     opt_guide_->RegisterOptimizationTypes(types);
   }
@@ -97,6 +104,21 @@
                      weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
 }
 
+void ShoppingService::GetMerchantInfoForUrl(const GURL& url,
+                                            MerchantInfoCallback callback) {
+  if (!opt_guide_)
+    return;
+
+  // Crash if this API is used without a valid experiment.
+  CHECK(IsMerchantInfoApiEnabled());
+
+  opt_guide_->CanApplyOptimization(
+      url,
+      optimization_guide::proto::OptimizationType::MERCHANT_TRUST_SIGNALS_V2,
+      base::BindOnce(&ShoppingService::HandleOptGuideMerchantInfoResponse,
+                     weak_ptr_factory_.GetWeakPtr(), url, std::move(callback)));
+}
+
 bool ShoppingService::IsProductInfoApiEnabled() {
   return base::FeatureList::IsEnabled(kShoppingList);
 }
@@ -105,6 +127,10 @@
   return base::FeatureList::IsEnabled(commerce::kShoppingPDPMetrics);
 }
 
+bool ShoppingService::IsMerchantInfoApiEnabled() {
+  return base::FeatureList::IsEnabled(kCommerceMerchantViewer);
+}
+
 void ShoppingService::HandleOptGuideProductInfoResponse(
     const GURL& url,
     ProductInfoCallback callback,
@@ -154,6 +180,65 @@
   std::move(callback).Run(url, info);
 }
 
+void ShoppingService::HandleOptGuideMerchantInfoResponse(
+    const GURL& url,
+    MerchantInfoCallback callback,
+    optimization_guide::OptimizationGuideDecision decision,
+    const optimization_guide::OptimizationMetadata& metadata) {
+  // If optimization guide returns negative, return a negative signal with an
+  // empty data object.
+  if (decision != optimization_guide::OptimizationGuideDecision::kTrue) {
+    std::move(callback).Run(url, absl::nullopt);
+    return;
+  }
+
+  absl::optional<MerchantInfo> info;
+
+  if (metadata.any_metadata().has_value()) {
+    absl::optional<commerce::MerchantTrustSignalsV2> parsed_any =
+        optimization_guide::ParsedAnyMetadata<commerce::MerchantTrustSignalsV2>(
+            metadata.any_metadata().value());
+    commerce::MerchantTrustSignalsV2 merchant_data = parsed_any.value();
+    if (parsed_any.has_value() && merchant_data.IsInitialized()) {
+      info.emplace();
+
+      if (merchant_data.has_merchant_star_rating()) {
+        info->star_rating = merchant_data.merchant_star_rating();
+      }
+
+      if (merchant_data.has_merchant_count_rating()) {
+        info->count_rating = merchant_data.merchant_count_rating();
+      }
+
+      if (merchant_data.has_merchant_details_page_url()) {
+        info->details_page_url =
+            GURL(merchant_data.merchant_details_page_url());
+      }
+
+      if (merchant_data.has_has_return_policy()) {
+        info->has_return_policy = merchant_data.has_return_policy();
+      }
+
+      if (merchant_data.has_non_personalized_familiarity_score()) {
+        info->non_personalized_familiarity_score =
+            merchant_data.non_personalized_familiarity_score();
+      }
+
+      if (merchant_data.has_contains_sensitive_content()) {
+        info->contains_sensitive_content =
+            merchant_data.contains_sensitive_content();
+      }
+
+      if (merchant_data.has_proactive_message_disabled()) {
+        info->proactive_message_disabled =
+            merchant_data.proactive_message_disabled();
+      }
+    }
+  }
+
+  std::move(callback).Run(url, std::move(info));
+}
+
 void ShoppingService::Shutdown() {}
 
 ShoppingService::~ShoppingService() = default;
diff --git a/components/commerce/core/shopping_service.h b/components/commerce/core/shopping_service.h
index 74cdec8..b247b76 100644
--- a/components/commerce/core/shopping_service.h
+++ b/components/commerce/core/shopping_service.h
@@ -51,10 +51,30 @@
   std::string country_code;
 };
 
+// Information returned by the merchant info APIs.
+struct MerchantInfo {
+  MerchantInfo();
+  MerchantInfo(const MerchantInfo&) = delete;
+  MerchantInfo& operator=(const MerchantInfo&) = delete;
+  MerchantInfo(MerchantInfo&&);
+  MerchantInfo& operator=(MerchantInfo&&) = default;
+  ~MerchantInfo();
+
+  float star_rating;
+  uint32_t count_rating;
+  GURL details_page_url;
+  bool has_return_policy;
+  float non_personalized_familiarity_score;
+  bool contains_sensitive_content;
+  bool proactive_message_disabled;
+};
+
 // Callbacks for querying a single URL or observing information from all
 // navigated urls.
 using ProductInfoCallback =
     base::OnceCallback<void(const GURL&, const absl::optional<ProductInfo>&)>;
+using MerchantInfoCallback =
+    base::OnceCallback<void(const GURL&, absl::optional<MerchantInfo>)>;
 
 class ShoppingService : public KeyedService, public base::SupportsUserData {
  public:
@@ -70,6 +90,8 @@
 
   void GetProductInfoForUrl(const GURL& url, ProductInfoCallback callback);
 
+  void GetMerchantInfoForUrl(const GURL& url, MerchantInfoCallback callback);
+
   void Shutdown() override;
 
   // A notification that a WebWrapper has been created. This typically
@@ -101,12 +123,22 @@
       optimization_guide::OptimizationGuideDecision decision,
       const optimization_guide::OptimizationMetadata& metadata);
 
+  // Whether APIs like |GetMerchantInfoForURL| are enabled and allowed to be
+  // used.
+  bool IsMerchantInfoApiEnabled();
+
   void HandleOptGuideProductInfoResponse(
       const GURL& url,
       ProductInfoCallback callback,
       optimization_guide::OptimizationGuideDecision decision,
       const optimization_guide::OptimizationMetadata& metadata);
 
+  void HandleOptGuideMerchantInfoResponse(
+      const GURL& url,
+      MerchantInfoCallback callback,
+      optimization_guide::OptimizationGuideDecision decision,
+      const optimization_guide::OptimizationMetadata& metadata);
+
   // A handle to optimization guide for information about URLs that have
   // recently been navigated to.
   raw_ptr<optimization_guide::NewOptimizationGuideDecider> opt_guide_;
diff --git a/components/commerce/core/shopping_service_test_base.cc b/components/commerce/core/shopping_service_test_base.cc
index 6ff1cd8..638915b9 100644
--- a/components/commerce/core/shopping_service_test_base.cc
+++ b/components/commerce/core/shopping_service_test_base.cc
@@ -8,6 +8,7 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
 #include "components/commerce/core/commerce_feature_list.h"
+#include "components/commerce/core/proto/merchant_trust.pb.h"
 #include "components/commerce/core/proto/price_tracking.pb.h"
 #include "components/optimization_guide/proto/common_types.pb.h"
 #include "components/optimization_guide/proto/hints.pb.h"
@@ -90,6 +91,30 @@
   return meta;
 }
 
+OptimizationMetadata MockOptGuideDecider::BuildMerchantTrustResponse(
+    const float star_rating,
+    const uint32_t count_rating,
+    const std::string& details_page_url,
+    const bool has_return_policy,
+    const bool contains_sensitive_content) {
+  OptimizationMetadata meta;
+
+  MerchantTrustSignalsV2 merchant_trust_data;
+  merchant_trust_data.set_merchant_star_rating(star_rating);
+  merchant_trust_data.set_merchant_count_rating(count_rating);
+  merchant_trust_data.set_merchant_details_page_url(details_page_url);
+  merchant_trust_data.set_has_return_policy(has_return_policy);
+  merchant_trust_data.set_contains_sensitive_content(
+      contains_sensitive_content);
+
+  Any any;
+  any.set_type_url(merchant_trust_data.GetTypeName());
+  merchant_trust_data.SerializeToString(any.mutable_value());
+  meta.set_any_metadata(any);
+
+  return meta;
+}
+
 MockWebWrapper::MockWebWrapper(const GURL& last_committed_url,
                                bool is_off_the_record)
     : last_committed_url_(last_committed_url),
diff --git a/components/commerce/core/shopping_service_test_base.h b/components/commerce/core/shopping_service_test_base.h
index 16b7b5e..fefc4aea 100644
--- a/components/commerce/core/shopping_service_test_base.h
+++ b/components/commerce/core/shopping_service_test_base.h
@@ -65,6 +65,13 @@
       const uint64_t product_cluster_id,
       const std::string& country_code);
 
+  OptimizationMetadata BuildMerchantTrustResponse(
+      const float star_rating,
+      const uint32_t count_rating,
+      const std::string& details_page_url,
+      const bool has_return_policy,
+      const bool contains_sensitive_content);
+
  private:
   absl::optional<GURL> response_url_;
   absl::optional<OptimizationType> optimization_type_;
diff --git a/components/commerce/core/shopping_service_unittest.cc b/components/commerce/core/shopping_service_unittest.cc
index b0fca04..d78c3685 100644
--- a/components/commerce/core/shopping_service_unittest.cc
+++ b/components/commerce/core/shopping_service_unittest.cc
@@ -26,6 +26,13 @@
 const uint64_t kOfferId = 123;
 const uint64_t kClusterId = 456;
 const char kCountryCode[] = "US";
+
+const char kMerchantUrl[] = "http://example.com/merchant";
+const float kStarRating = 4.5;
+const uint32_t kCountRating = 1000;
+const char kDetailsPageUrl[] = "http://example.com/merchant_details_page";
+const bool kHasReturnPolicy = true;
+const bool kContainsSensitiveContent = false;
 }  // namespace
 
 namespace commerce {
@@ -96,4 +103,42 @@
   ASSERT_TRUE(callback_executed);
 }
 
+// Test that merchant info is processed correctly.
+TEST_F(ShoppingServiceTest, TestMerchantInfoResponse) {
+  // Ensure a feature that uses merchant info is enabled.
+  base::test::ScopedFeatureList test_features;
+  test_features.InitAndEnableFeature(commerce::kCommerceMerchantViewer);
+
+  OptimizationMetadata meta = opt_guide_->BuildMerchantTrustResponse(
+      kStarRating, kCountRating, kDetailsPageUrl, kHasReturnPolicy,
+      kContainsSensitiveContent);
+
+  opt_guide_->SetResponse(GURL(kMerchantUrl),
+                          OptimizationType::MERCHANT_TRUST_SIGNALS_V2,
+                          OptimizationGuideDecision::kTrue, meta);
+
+  bool callback_executed = false;
+  shopping_service_->GetMerchantInfoForUrl(
+      GURL(kMerchantUrl),
+      base::BindOnce(
+          [](bool* callback_executed, const GURL& url,
+             absl::optional<MerchantInfo> info) {
+            ASSERT_EQ(kMerchantUrl, url.spec());
+            ASSERT_TRUE(info.has_value());
+
+            ASSERT_EQ(kStarRating, info->star_rating);
+            ASSERT_EQ(kCountRating, info->count_rating);
+            ASSERT_EQ(kDetailsPageUrl, info->details_page_url.spec());
+            ASSERT_EQ(kHasReturnPolicy, info->has_return_policy);
+            ASSERT_EQ(kContainsSensitiveContent,
+                      info->contains_sensitive_content);
+            *callback_executed = true;
+          },
+          &callback_executed));
+
+  // Make sure the callback was actually run. In testing the callback is run
+  // immediately, this check ensures that is actually the case.
+  ASSERT_TRUE(callback_executed);
+}
+
 }  // namespace commerce
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn
index 9e5fbe7..eda7994f 100644
--- a/components/enterprise/BUILD.gn
+++ b/components/enterprise/BUILD.gn
@@ -126,17 +126,20 @@
   sources = [
     "browser/reporting/chrome_profile_request_generator_unittest.cc",
     "browser/reporting/report_uploader_unittest.cc",
+    "common/proto/connectors_unittest.cc",
   ]
 
   deps = [
     ":enterprise",
     ":reporting_test_support",
+    "common/proto:connectors_proto",
     "//base/test:test_support",
     "//build:chromeos_buildflags",
     "//components/policy/core/common:test_support",
     "//components/version_info",
     "//testing/gmock",
     "//testing/gtest",
+    "//third_party/content_analysis_sdk:liblcasdk",
   ]
 
   if (!is_chromeos_ash) {
diff --git a/components/enterprise/DEPS b/components/enterprise/DEPS
index 5e16a50..5cdbeb3e 100644
--- a/components/enterprise/DEPS
+++ b/components/enterprise/DEPS
@@ -9,5 +9,6 @@
   "+crypto/signature_verifier.h",
   "+net",
   "+services/network/public",
-  "+third_party/protobuf"
+  "+third_party/protobuf",
+  "+third_party/content_analysis_sdk"
 ]
diff --git a/components/enterprise/common/proto/connectors_unittest.cc b/components/enterprise/common/proto/connectors_unittest.cc
new file mode 100644
index 0000000..05c7f956
--- /dev/null
+++ b/components/enterprise/common/proto/connectors_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// #include "third_party/content_analysis_sdk/src/proto/content_analysis/sdk/
+
+#include "components/enterprise/common/proto/connectors.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/content_analysis_sdk/src/proto/content_analysis/sdk/analysis.pb.h"
+
+namespace enterprise_connectors {
+
+TEST(EnterpriseConnectorsProtoTest, AnalysisConnectorEnum) {
+  EXPECT_EQ(enterprise_connectors::AnalysisConnector_ARRAYSIZE, 5);
+  EXPECT_EQ(enterprise_connectors::AnalysisConnector_ARRAYSIZE,
+            content_analysis::sdk::AnalysisConnector_ARRAYSIZE);
+
+  EXPECT_EQ((int)enterprise_connectors::ANALYSIS_CONNECTOR_UNSPECIFIED,
+            (int)content_analysis::sdk::ANALYSIS_CONNECTOR_UNSPECIFIED);
+  EXPECT_EQ((int)enterprise_connectors::FILE_DOWNLOADED,
+            (int)content_analysis::sdk::FILE_DOWNLOADED);
+  EXPECT_EQ((int)enterprise_connectors::FILE_ATTACHED,
+            (int)content_analysis::sdk::FILE_ATTACHED);
+  EXPECT_EQ((int)enterprise_connectors::BULK_DATA_ENTRY,
+            (int)content_analysis::sdk::BULK_DATA_ENTRY);
+  EXPECT_EQ((int)enterprise_connectors::PRINT,
+            (int)content_analysis::sdk::PRINT);
+}
+
+using ChromiumResult = enterprise_connectors::ContentAnalysisResponse::Result;
+using SdkResult = content_analysis::sdk::ContentAnalysisResponse::Result;
+
+TEST(EnterpriseConnectorsProtoTest, StatusEnum) {
+  EXPECT_EQ(ChromiumResult::Status_ARRAYSIZE, 3);
+  EXPECT_EQ(ChromiumResult::Status_ARRAYSIZE, SdkResult::Status_ARRAYSIZE);
+
+  EXPECT_EQ((int)ChromiumResult::STATUS_UNKNOWN,
+            (int)SdkResult::STATUS_UNKNOWN);
+  EXPECT_EQ((int)ChromiumResult::SUCCESS, (int)SdkResult::SUCCESS);
+  EXPECT_EQ((int)ChromiumResult::FAILURE, (int)SdkResult::FAILURE);
+}
+
+using ChromiumRule = ChromiumResult::TriggeredRule;
+using SdkRule = SdkResult::TriggeredRule;
+
+TEST(EnterpriseConnectorsProtoTest, TriggeredRuleActionEnum) {
+  EXPECT_EQ(ChromiumRule::Action_ARRAYSIZE, 4);
+  EXPECT_EQ(ChromiumRule::Action_ARRAYSIZE, SdkRule::Action_ARRAYSIZE);
+
+  EXPECT_EQ((int)ChromiumRule::ACTION_UNSPECIFIED,
+            (int)SdkRule::ACTION_UNSPECIFIED);
+  EXPECT_EQ((int)ChromiumRule::REPORT_ONLY, (int)SdkRule::REPORT_ONLY);
+  EXPECT_EQ((int)ChromiumRule::WARN, (int)SdkRule::WARN);
+  EXPECT_EQ((int)ChromiumRule::BLOCK, (int)SdkRule::BLOCK);
+}
+
+}  // namespace enterprise_connectors
diff --git a/components/metrics/structured/key_data.cc b/components/metrics/structured/key_data.cc
index 8117aeb..44a3cfad 100644
--- a/components/metrics/structured/key_data.cc
+++ b/components/metrics/structured/key_data.cc
@@ -23,9 +23,6 @@
 // The expected size of a key, in bytes.
 constexpr size_t kKeySize = 32;
 
-// The default maximum number of days before rotating keys.
-constexpr int kDefaultRotationPeriod = 90;
-
 // Generates a key, which is the string representation of
 // base::UnguessableToken, and is of size |kKeySize| bytes.
 std::string GenerateKey() {
@@ -92,7 +89,8 @@
 //---------------
 
 absl::optional<std::string> KeyData::ValidateAndGetKey(
-    const uint64_t project_name_hash) {
+    const uint64_t project_name_hash,
+    int key_rotation_period) {
   if (!is_initialized_) {
     NOTREACHED();
     return absl::nullopt;
@@ -103,20 +101,26 @@
 
   // Generate or rotate key.
   const int last_rotation = key.last_rotation();
+
   if (key.key().empty() || last_rotation == 0) {
     LogKeyValidation(KeyValidationState::kCreated);
     // If the key is empty, generate a new one. Set the last rotation to a
-    // uniformly selected day between today and |kDefaultRotationPeriod| days
+    // uniformly selected day between today and |key_rotation_period| days
     // ago, to uniformly distribute users amongst rotation cohorts.
-    const int rotation_seed = base::RandInt(0, kDefaultRotationPeriod - 1);
-    UpdateKey(&key, now - rotation_seed, kDefaultRotationPeriod);
-  } else if (now - last_rotation > kDefaultRotationPeriod) {
+    const int rotation_seed = base::RandInt(0, key_rotation_period - 1);
+    UpdateKey(&key, now - rotation_seed, key_rotation_period);
+  } else if (now - last_rotation > key_rotation_period) {
     LogKeyValidation(KeyValidationState::kRotated);
-    // If the key is outdated, generate a new one. Update the last rotation such
-    // that the user stays in the same cohort.
+
+    // If the key is outdated, generate a new one. Update the last rotation
+    // such that the user stays in the same cohort.
+    //
+    // Note that if the max key rotation period has changed, the new rotation
+    // period will be used to calculate whether the key should be rotated or
+    // not.
     const int new_last_rotation =
-        now - (now - last_rotation) % kDefaultRotationPeriod;
-    UpdateKey(&key, new_last_rotation, kDefaultRotationPeriod);
+        now - (now - last_rotation) % key_rotation_period;
+    UpdateKey(&key, new_last_rotation, key_rotation_period);
   } else {
     LogKeyValidation(KeyValidationState::kValid);
   }
@@ -131,11 +135,11 @@
 }
 
 void KeyData::UpdateKey(KeyProto* key,
-                        const int last_rotation,
-                        const int rotation_period) {
+                        int last_key_rotation,
+                        int key_rotation_period) {
   key->set_key(GenerateKey());
-  key->set_last_rotation(last_rotation);
-  key->set_rotation_period(rotation_period);
+  key->set_last_rotation(last_key_rotation);
+  key->set_rotation_period(key_rotation_period);
   proto_->QueueWrite();
 }
 
@@ -143,11 +147,13 @@
 // IDs and hashing
 //----------------
 
-uint64_t KeyData::Id(const uint64_t project_name_hash) {
+uint64_t KeyData::Id(const uint64_t project_name_hash,
+                     int key_rotation_period) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Retrieve the key for |project_name_hash|.
-  const absl::optional<std::string> key = ValidateAndGetKey(project_name_hash);
+  const absl::optional<std::string> key =
+      ValidateAndGetKey(project_name_hash, key_rotation_period);
   if (!key) {
     NOTREACHED();
     return 0u;
@@ -161,11 +167,13 @@
 
 uint64_t KeyData::HmacMetric(const uint64_t project_name_hash,
                              const uint64_t metric_name_hash,
-                             const std::string& value) {
+                             const std::string& value,
+                             int key_rotation_period) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Retrieve the key for |project_name_hash|.
-  const absl::optional<std::string> key = ValidateAndGetKey(project_name_hash);
+  const absl::optional<std::string> key =
+      ValidateAndGetKey(project_name_hash, key_rotation_period);
   if (!key) {
     NOTREACHED();
     return 0u;
diff --git a/components/metrics/structured/key_data.h b/components/metrics/structured/key_data.h
index ecfbf6f..2a60b26 100644
--- a/components/metrics/structured/key_data.h
+++ b/components/metrics/structured/key_data.h
@@ -69,7 +69,8 @@
   // Returns 0u in case of an error.
   uint64_t HmacMetric(uint64_t project_name_hash,
                       uint64_t metric_name_hash,
-                      const std::string& value);
+                      const std::string& value,
+                      int key_rotation_period);
 
   // Returns an ID for this (user, |project_name_hash|) pair.
   // |project_name_hash| is the name of a project, represented by the first 8
@@ -84,7 +85,9 @@
   // the server. This means events are associated with the client ID when
   // uploaded from the device. See the class comment of
   // StructuredMetricsProvider for more details.
-  uint64_t Id(uint64_t project_name_hash);
+  //
+  // Default |key_rotation_period| is 90 days.
+  uint64_t Id(uint64_t project_name_hash, int key_rotation_period);
 
   // Returns when the key for |project_name_hash| was last rotated, in days
   // since epoch. Returns nullopt if the key doesn't exist.
@@ -109,12 +112,15 @@
   void OnWrite(WriteStatus status);
 
   // Ensure that a valid key exists for |project|, and return it. Either returns
-  // a string of size |kKeySize| or absl::nullopt, which indicates an error.
-  absl::optional<std::string> ValidateAndGetKey(uint64_t project_name_hash);
+  // a string of size |kKeySize| or absl::nullopt, which indicates an error. If
+  // a key doesn't exist OR if the key needs to be rotated, then a new key with
+  // |key_rotation_period| will be created.
+  absl::optional<std::string> ValidateAndGetKey(uint64_t project_name_hash,
+                                                int key_rotation_period);
 
-  // Regenerate |key|, also updating the |last_rotation| and |rotation_period|.
-  // This triggers a save.
-  void UpdateKey(KeyProto* key, int last_rotation, int rotation_period);
+  // Regenerate |key|, also updating the |last_key_rotation| and
+  // |key_rotation_period|. This triggers a save.
+  void UpdateKey(KeyProto* key, int last_key_rotation, int key_rotation_period);
 
   // Storage for keys.
   std::unique_ptr<PersistentProto<KeyDataProto>> proto_;
diff --git a/components/metrics/structured/key_data_unittest.cc b/components/metrics/structured/key_data_unittest.cc
index b240745..9b06a9f 100644
--- a/components/metrics/structured/key_data_unittest.cc
+++ b/components/metrics/structured/key_data_unittest.cc
@@ -62,6 +62,8 @@
 constexpr char kValueOneHash[] = "805B8790DC69B773";
 constexpr char kValueTwoHash[] = "87CEF12FB15E0B3A";
 
+constexpr int kKeyRotationPeriod = 90;
+
 std::string HashToHex(const uint64_t hash) {
   return base::HexEncode(&hash, sizeof(uint64_t));
 }
@@ -161,8 +163,8 @@
 TEST_F(KeyDataTest, GeneratesKeysForProjects) {
   // Make key data and use two keys, in order to generate them.
   MakeKeyData();
-  key_data_->Id(kProjectOneHash);
-  key_data_->Id(kProjectTwoHash);
+  key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
+  key_data_->Id(kProjectTwoHash, kKeyRotationPeriod);
   SaveKeyData();
 
   const std::string key_one = GetKey(kProjectOneHash).key();
@@ -186,7 +188,7 @@
     // disk.
     ResetState();
     MakeKeyData();
-    key_data_->Id(kProjectOneHash);
+    key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
     SaveKeyData();
 
     keys.insert(GetKey(kProjectOneHash).key());
@@ -201,7 +203,7 @@
 TEST_F(KeyDataTest, ReuseExistingKeys) {
   // Create a file with one key.
   MakeKeyData();
-  const uint64_t id_one = key_data_->Id(kProjectOneHash);
+  const uint64_t id_one = key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
   SaveKeyData();
   ExpectKeyValidation(/*valid=*/0, /*created=*/1, /*rotated=*/0);
   const std::string key_one = GetKey(kProjectOneHash).key();
@@ -211,7 +213,7 @@
 
   // Open the file again and check we use the same key.
   MakeKeyData();
-  const uint64_t id_two = key_data_->Id(kProjectOneHash);
+  const uint64_t id_two = key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
   ExpectKeyValidation(/*valid=*/1, /*created=*/1, /*rotated=*/0);
   SaveKeyData();
   const std::string key_two = GetKey(kProjectOneHash).key();
@@ -224,8 +226,10 @@
 // value.
 TEST_F(KeyDataTest, DifferentEventsDifferentHashes) {
   MakeKeyData();
-  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "value"),
-            key_data_->HmacMetric(kProjectTwoHash, kMetricOneHash, "value"));
+  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "value",
+                                  kKeyRotationPeriod),
+            key_data_->HmacMetric(kProjectTwoHash, kMetricOneHash, "value",
+                                  kKeyRotationPeriod));
   ExpectNoErrors();
 }
 
@@ -233,8 +237,10 @@
 // value.
 TEST_F(KeyDataTest, DifferentMetricsDifferentHashes) {
   MakeKeyData();
-  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "value"),
-            key_data_->HmacMetric(kProjectOneHash, kMetricTwoHash, "value"));
+  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "value",
+                                  kKeyRotationPeriod),
+            key_data_->HmacMetric(kProjectOneHash, kMetricTwoHash, "value",
+                                  kKeyRotationPeriod));
   ExpectNoErrors();
 }
 
@@ -242,52 +248,56 @@
 // metric.
 TEST_F(KeyDataTest, DifferentValuesDifferentHashes) {
   MakeKeyData();
-  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "first"),
-            key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "second"));
+  EXPECT_NE(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "first",
+                                  kKeyRotationPeriod),
+            key_data_->HmacMetric(kProjectOneHash, kMetricOneHash, "second",
+                                  kKeyRotationPeriod));
   ExpectNoErrors();
 }
 
 // Ensure that KeyData::UserId is the expected value of SHA256(key).
 TEST_F(KeyDataTest, CheckUserIDs) {
-  SetupKey(kProjectOneHash, kKey, Today(), 90);
+  SetupKey(kProjectOneHash, kKey, Today(), kKeyRotationPeriod);
 
   MakeKeyData();
-  EXPECT_EQ(HashToHex(key_data_->Id(kProjectOneHash)), kUserId);
-  EXPECT_NE(HashToHex(key_data_->Id(kProjectTwoHash)), kUserId);
+  EXPECT_EQ(HashToHex(key_data_->Id(kProjectOneHash, kKeyRotationPeriod)),
+            kUserId);
+  EXPECT_NE(HashToHex(key_data_->Id(kProjectTwoHash, kKeyRotationPeriod)),
+            kUserId);
   ExpectKeyValidation(/*valid=*/1, /*created=*/1, /*rotated=*/0);
   ExpectNoErrors();
 }
 
 // Ensure that KeyData::Hash returns expected values for a known key and value.
 TEST_F(KeyDataTest, CheckHashes) {
-  SetupKey(kProjectOneHash, kKey, Today(), 90);
+  SetupKey(kProjectOneHash, kKey, Today(), kKeyRotationPeriod);
 
   MakeKeyData();
   EXPECT_EQ(HashToHex(key_data_->HmacMetric(kProjectOneHash, kMetricOneHash,
-                                            kValueOne)),
+                                            kValueOne, kKeyRotationPeriod)),
             kValueOneHash);
   EXPECT_EQ(HashToHex(key_data_->HmacMetric(kProjectOneHash, kMetricTwoHash,
-                                            kValueTwo)),
+                                            kValueTwo, kKeyRotationPeriod)),
             kValueTwoHash);
   ExpectKeyValidation(/*valid=*/2, /*created=*/0, /*rotated=*/0);
   ExpectNoErrors();
 }
 
-// Check that keys for a event are correctly rotated after the default 90 day
-// rotation period.
+// Check that keys for a event are correctly rotated after a given rotation
+// period.
 TEST_F(KeyDataTest, KeysRotated) {
   const int start_day = Today();
-  SetupKey(kProjectOneHash, kKey, start_day, 90);
+  SetupKey(kProjectOneHash, kKey, start_day, kKeyRotationPeriod);
 
   MakeKeyData();
-  const uint64_t first_id = key_data_->Id(kProjectOneHash);
+  const uint64_t first_id = key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
   EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash), start_day);
   ExpectKeyValidation(/*valid=*/1, /*created=*/0, /*rotated=*/0);
 
   {
-    // Advancing by 50 days, the key should not be rotated.
-    time_.Advance(base::Days(50));
-    EXPECT_EQ(key_data_->Id(kProjectOneHash), first_id);
+    // Advancing by |kKeyRotationPeriod|-1 days, the key should not be rotated.
+    time_.Advance(base::Days(kKeyRotationPeriod - 1));
+    EXPECT_EQ(key_data_->Id(kProjectOneHash, kKeyRotationPeriod), first_id);
     EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash), start_day);
     SaveKeyData();
 
@@ -296,33 +306,70 @@
   }
 
   {
-    // Advancing by another 50 days, the key should be rotated and the last
-    // rotation day should be incremented by 90.
-    time_.Advance(base::Days(50));
-    EXPECT_NE(key_data_->Id(kProjectOneHash), first_id);
+    // Advancing by another |key_rotation_period|+1 days, the key should be
+    // rotated and the last rotation day should be incremented by
+    // |key_rotation_period|.
+    time_.Advance(base::Days(kKeyRotationPeriod + 1));
+    EXPECT_NE(key_data_->Id(kProjectOneHash, kKeyRotationPeriod), first_id);
     SaveKeyData();
 
-    EXPECT_EQ(GetKey(kProjectOneHash).last_rotation(), start_day + 90);
-    EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash), start_day + 90);
+    int expected_last_key_rotation = start_day + 2 * kKeyRotationPeriod;
+    EXPECT_EQ(GetKey(kProjectOneHash).last_rotation(),
+              expected_last_key_rotation);
+    EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash),
+              expected_last_key_rotation);
     ExpectKeyValidation(/*valid=*/2, /*created=*/0, /*rotated=*/1);
 
-    // The rotation period could change here if it were ever updated in the xml.
-    // This test relies on it being 90 days.
-    ASSERT_EQ(GetKey(kProjectOneHash).rotation_period(), 90);
+    ASSERT_EQ(GetKey(kProjectOneHash).rotation_period(), kKeyRotationPeriod);
   }
 
   {
-    // Advancing by 453 days, the last rotation day should now 6 periods of 90
-    // days ahead.
-    time_.Advance(base::Days(453));
-    key_data_->Id(kProjectOneHash);
+    // Advancing by |2* kKeyRotationPeriod| days, the last rotation day should
+    // now 4 periods of |kKeyRotationPeriod| days ahead.
+    time_.Advance(base::Days(kKeyRotationPeriod * 2));
+    key_data_->Id(kProjectOneHash, kKeyRotationPeriod);
     SaveKeyData();
 
-    EXPECT_EQ(GetKey(kProjectOneHash).last_rotation(), start_day + 6 * 90);
-    EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash), start_day + 6 * 90);
+    int expected_last_key_rotation = start_day + 4 * kKeyRotationPeriod;
+    EXPECT_EQ(GetKey(kProjectOneHash).last_rotation(),
+              expected_last_key_rotation);
+    EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash),
+              expected_last_key_rotation);
     ExpectKeyValidation(/*valid=*/2, /*created=*/0, /*rotated=*/2);
   }
 }
 
+// Check that keys with updated rotations are correctly rotated.
+TEST_F(KeyDataTest, KeysWithUpdatedRotations) {
+  int first_key_rotation_period = 60;
+
+  const int start_day = Today();
+  SetupKey(kProjectOneHash, kKey, start_day, first_key_rotation_period);
+
+  MakeKeyData();
+  const uint64_t first_id =
+      key_data_->Id(kProjectOneHash, first_key_rotation_period);
+  EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash), start_day);
+  ExpectKeyValidation(/*valid=*/1, /*created=*/0, /*rotated=*/0);
+
+  // Advance days by |new_key_rotation_period| + 1. This should fall within the
+  // rotation of the |new_key_rotation_period| but outside
+  // |first_key_rotation_period|.
+  int new_key_rotation_period = 50;
+  time_.Advance(base::Days(new_key_rotation_period + 1));
+  const uint64_t second_id =
+      key_data_->Id(kProjectOneHash, new_key_rotation_period);
+  EXPECT_NE(first_id, second_id);
+  SaveKeyData();
+
+  // Key should have been rotated with new_key_rotation_period.
+  int expected_last_key_rotation = start_day + new_key_rotation_period;
+  EXPECT_EQ(GetKey(kProjectOneHash).last_rotation(),
+            expected_last_key_rotation);
+  EXPECT_EQ(key_data_->LastKeyRotation(kProjectOneHash),
+            expected_last_key_rotation);
+  ExpectKeyValidation(/*valid=*/1, /*created=*/0, /*rotated=*/1);
+}
+
 }  // namespace structured
 }  // namespace metrics
diff --git a/components/metrics/structured/structured_metrics_provider.cc b/components/metrics/structured/structured_metrics_provider.cc
index f0e38e9..e96b35c 100644
--- a/components/metrics/structured/structured_metrics_provider.cc
+++ b/components/metrics/structured/structured_metrics_provider.cc
@@ -411,7 +411,7 @@
   switch (event.id_type()) {
     case IdType::kProjectId:
       event_proto->set_profile_event_id(
-          key_data->Id(event.project_name_hash()));
+          key_data->Id(event.project_name_hash(), event.key_rotation_period()));
       break;
     case IdType::kUmaId:
       // TODO(crbug.com/1148168): Unimplemented.
@@ -447,7 +447,8 @@
     switch (metric.type) {
       case EventBase::MetricType::kHmac:
         metric_proto->set_value_hmac(key_data->HmacMetric(
-            event.project_name_hash(), metric.name_hash, metric.hmac_value));
+            event.project_name_hash(), metric.name_hash, metric.hmac_value,
+            event.key_rotation_period()));
         break;
       case EventBase::MetricType::kInt:
         metric_proto->set_value_int64(metric.int_value);
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 062fc005..b2c4b149 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -53,6 +53,7 @@
     "https_valid_in_chip.icon",
     "incognito.icon",
     "install_desktop.icon",
+    "journeys.icon",
     "keyword_search.icon",
     "offline_pin.icon",
     "page.icon",
diff --git a/components/omnibox/browser/actions/history_clusters_action.cc b/components/omnibox/browser/actions/history_clusters_action.cc
index fbc9b891..6f23a83 100644
--- a/components/omnibox/browser/actions/history_clusters_action.cc
+++ b/components/omnibox/browser/actions/history_clusters_action.cc
@@ -29,6 +29,10 @@
 #include "url/android/gurl_android.h"
 #endif
 
+#if defined(SUPPORT_PEDALS_VECTOR_ICONS)
+#include "components/omnibox/browser/vector_icons.h"  // nogncheck
+#endif
+
 namespace history_clusters {
 
 namespace {
@@ -84,6 +88,12 @@
     return static_cast<int32_t>(OmniboxActionId::HISTORY_CLUSTERS);
   }
 
+#if defined(SUPPORT_PEDALS_VECTOR_ICONS)
+  const gfx::VectorIcon& GetVectorIcon() const override {
+    return omnibox::kJourneysIcon;
+  }
+#endif
+
 #if BUILDFLAG(IS_ANDROID)
   base::android::ScopedJavaGlobalRef<jobject> GetJavaObject() const override {
     return j_omnibox_action_;
diff --git a/components/omnibox/browser/actions/omnibox_pedal_provider.cc b/components/omnibox/browser/actions/omnibox_pedal_provider.cc
index 18ad087..c585d75d 100644
--- a/components/omnibox/browser/actions/omnibox_pedal_provider.cc
+++ b/components/omnibox/browser/actions/omnibox_pedal_provider.cc
@@ -322,16 +322,6 @@
        concept_data->FindKey("pedals")->GetListDeprecated()) {
     DCHECK(pedal_value.is_dict());
     const int id = pedal_value.FindIntKey("id").value();
-    if (!locale_is_english) {
-      // These IDs are the first and last for batch 3. Skip loading if batch 3
-      // is not enabled for the current locale.
-      if (id >= static_cast<int>(OmniboxPedalId::CLOSE_INCOGNITO_WINDOWS) &&
-          id <=
-              static_cast<int>(OmniboxPedalId::MANAGE_CHROMEOS_ACCESSIBILITY) &&
-          !OmniboxFieldTrial::IsPedalsBatch3NonEnglishEnabled()) {
-        continue;
-      }
-    }
     const auto pedal_iter = pedals_.find(static_cast<OmniboxPedalId>(id));
     if (pedal_iter == pedals_.end()) {
       // Data may exist for Pedals that are intentionally not registered; skip.
diff --git a/components/omnibox/browser/actions/omnibox_pedal_provider_unittest.cc b/components/omnibox/browser/actions/omnibox_pedal_provider_unittest.cc
index 945ccd52..e0a4fbb 100644
--- a/components/omnibox/browser/actions/omnibox_pedal_provider_unittest.cc
+++ b/components/omnibox/browser/actions/omnibox_pedal_provider_unittest.cc
@@ -17,10 +17,7 @@
  protected:
   OmniboxPedalProviderTest() = default;
 
-  void SetUp() override {
-    feature_list_.InitWithFeatures({omnibox::kOmniboxPedalsBatch3NonEnglish},
-                                   {});
-  }
+  void SetUp() override { feature_list_.InitWithFeatures({}, {}); }
 
   base::test::ScopedFeatureList feature_list_;
 };
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 55842ab..5eabc98 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -614,10 +614,6 @@
   return base::FeatureList::IsEnabled(omnibox::kOmniboxPedalsAndroidBatch1);
 }
 
-bool OmniboxFieldTrial::IsPedalsBatch3NonEnglishEnabled() {
-  return base::FeatureList::IsEnabled(omnibox::kOmniboxPedalsBatch3NonEnglish);
-}
-
 bool OmniboxFieldTrial::IsExperimentalKeywordModeEnabled() {
   return base::FeatureList::IsEnabled(omnibox::kExperimentalKeywordMode);
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 12ec3b6a..a4633fd3 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -359,10 +359,6 @@
 // Returns true if the first batch of Pedals on Android is enabled.
 bool IsPedalsAndroidBatch1Enabled();
 
-// Returns true if the third batch of Pedals is enabled for non-English
-// locales.
-bool IsPedalsBatch3NonEnglishEnabled();
-
 // Simply a convenient wrapper for testing a flag. Used downstream for an
 // assortment of keyword mode experiments.
 bool IsExperimentalKeywordModeEnabled();
diff --git a/components/omnibox/browser/vector_icons/journeys.icon b/components/omnibox/browser/vector_icons/journeys.icon
new file mode 100644
index 0000000..14a6d2e
--- /dev/null
+++ b/components/omnibox/browser/vector_icons/journeys.icon
@@ -0,0 +1,57 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Source: conversion_path_BASELINE_P900.svg --> SVGOMG --> Skiafy
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 19, 21,
+R_QUADRATIC_TO, -0.97f, 0, -1.75f, -0.56f,
+R_QUADRATIC_TO, -0.77f, -0.56f, -1.07f, -1.44f,
+H_LINE_TO, 11,
+R_QUADRATIC_TO, -1.65f, 0, -2.82f, -1.17f,
+QUADRATIC_TO, 7, 16.65f, 7, 15,
+R_QUADRATIC_TO, 0, -1.65f, 1.18f, -2.82f,
+QUADRATIC_TO, 9.35f, 11, 11, 11,
+R_H_LINE_TO, 2,
+R_QUADRATIC_TO, 0.83f, 0, 1.41f, -0.59f,
+QUADRATIC_TO, 15, 9.82f, 15, 9,
+R_QUADRATIC_TO, 0, -0.82f, -0.59f, -1.41f,
+QUADRATIC_TO, 13.83f, 7, 13, 7,
+H_LINE_TO, 7.83f,
+R_QUADRATIC_TO, -0.32f, 0.88f, -1.09f, 1.44f,
+QUADRATIC_TO, 5.98f, 9, 5, 9,
+R_QUADRATIC_TO, -1.25f, 0, -2.12f, -0.87f,
+QUADRATIC_TO_SHORTHAND, 2, 6,
+R_QUADRATIC_TO, 0, -1.25f, 0.88f, -2.12f,
+QUADRATIC_TO_SHORTHAND, 5, 3,
+R_QUADRATIC_TO, 0.98f, 0, 1.74f, 0.56f,
+QUADRATIC_TO, 7.5f, 4.13f, 7.83f, 5,
+H_LINE_TO, 13,
+R_QUADRATIC_TO, 1.65f, 0, 2.83f, 1.18f,
+QUADRATIC_TO, 17, 7.35f, 17, 9,
+R_QUADRATIC_TO, 0, 1.65f, -1.17f, 2.83f,
+QUADRATIC_TO, 14.65f, 13, 13, 13,
+R_H_LINE_TO, -2,
+R_QUADRATIC_TO, -0.82f, 0, -1.41f, 0.59f,
+QUADRATIC_TO, 9, 14.18f, 9, 15,
+R_QUADRATIC_TO, 0, 0.83f, 0.59f, 1.41f,
+QUADRATIC_TO, 10.18f, 17, 11, 17,
+R_H_LINE_TO, 5.18f,
+R_QUADRATIC_TO, 0.33f, -0.87f, 1.09f, -1.44f,
+QUADRATIC_TO, 18.02f, 15, 19, 15,
+R_QUADRATIC_TO, 1.25f, 0, 2.13f, 0.88f,
+QUADRATIC_TO_SHORTHAND, 22, 18,
+R_QUADRATIC_TO, 0, 1.25f, -0.87f, 2.13f,
+QUADRATIC_TO_SHORTHAND, 19, 21,
+CLOSE,
+MOVE_TO, 5, 7,
+R_QUADRATIC_TO, 0.43f, 0, 0.71f, -0.29f,
+QUADRATIC_TO, 6, 6.43f, 6, 6,
+R_QUADRATIC_TO, 0, -0.43f, -0.29f, -0.71f,
+QUADRATIC_TO, 5.43f, 5, 5, 5,
+R_QUADRATIC_TO, -0.43f, 0, -0.71f, 0.29f,
+QUADRATIC_TO, 4, 5.58f, 4, 6,
+R_QUADRATIC_TO, 0, 0.42f, 0.29f, 0.71f,
+QUADRATIC_TO, 4.58f, 7, 5, 7,
+CLOSE
\ No newline at end of file
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 3988743..9ab8c4af 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -271,11 +271,6 @@
 const base::Feature kOmniboxPedalsAndroidBatch1{
     "OmniboxPedalsAndroidBatch1", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Feature used to enable the third batch of Pedals (Find your phone, etc.)
-// for non-English locales (English locales are 'en' and 'en-GB').
-const base::Feature kOmniboxPedalsBatch3NonEnglish{
-    "OmniboxPedalsBatch3NonEnglish", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // When enabled, use Assistant for omnibox voice query recognition instead of
 // Android's built-in voice recognition service. Only works on Android.
 const base::Feature kOmniboxAssistantVoiceSearch{
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index f957e1bd..902cddc 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -77,7 +77,6 @@
 extern const base::Feature kNtpRealboxTailSuggest;
 extern const base::Feature kOmniboxFuzzyUrlSuggestions;
 extern const base::Feature kOmniboxPedalsAndroidBatch1;
-extern const base::Feature kOmniboxPedalsBatch3NonEnglish;
 
 // Omnibox UI - these affect the UI or function of the location bar (not the
 // popup).
diff --git a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
index a54dca6e..beec227 100644
--- a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
+++ b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -226,6 +226,7 @@
           WebFeature::kCookieHasNotBeenRefreshedIn201To300Days,
           WebFeature::kCookieHasNotBeenRefreshedIn301To350Days,
           WebFeature::kCookieHasNotBeenRefreshedIn351To400Days,
+          WebFeature::kPartitionedCookies,
       }));
   return *opt_in_features;
 }
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
index 26dc103..d6bc556 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -25,6 +25,7 @@
 #include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
 #include "ui/base/cocoa/command_dispatcher.h"
 #include "ui/base/cocoa/weak_ptr_nsobject.h"
+#include "ui/base/cursor/cursor.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/display/display_observer.h"
 
@@ -121,6 +122,7 @@
 
   // Sets the cursor associated with the NSWindow. Retains |cursor|.
   void SetCursor(NSCursor* cursor);
+  void SetCursor(const ui::Cursor& cursor);
 
   // Called internally by the NSWindowDelegate when the window is closing.
   void OnWindowWillClose();
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 4c76aaff..23acd2a1 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -35,6 +35,7 @@
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
+#include "ui/base/cocoa/cursor_utils.h"
 #include "ui/base/cocoa/remote_accessibility_api.h"
 #import "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
@@ -913,6 +914,10 @@
   [window_delegate_ setCursor:cursor];
 }
 
+void NativeWidgetNSWindowBridge::SetCursor(const ui::Cursor& cursor) {
+  SetCursor(ui::GetNativeCursor(cursor));
+}
+
 void NativeWidgetNSWindowBridge::OnWindowWillClose() {
   fullscreen_controller_.OnWindowWillClose();
 
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn
index fe01197..7dbf9d3 100644
--- a/components/send_tab_to_self/BUILD.gn
+++ b/components/send_tab_to_self/BUILD.gn
@@ -2,6 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 static_library("send_tab_to_self") {
   sources = [
     "entry_point_display_reason.cc",
@@ -54,6 +58,21 @@
   }
 }
 
+if (is_android) {
+  java_cpp_enum("java_enum_srcjar") {
+    visibility = [ ":*" ]
+    sources = [ "entry_point_display_reason.h" ]
+  }
+
+  android_library("send_tab_to_self_java") {
+    srcjar_deps = [ ":java_enum_srcjar" ]
+
+    # Important: the generated enum uses the @IntDef annotation provided by
+    # this dependency.
+    deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
+  }
+}
+
 source_set("test_support") {
   testonly = true
   sources = [
diff --git a/components/send_tab_to_self/entry_point_display_reason.h b/components/send_tab_to_self/entry_point_display_reason.h
index 83d8a28e..d2ab8ec 100644
--- a/components/send_tab_to_self/entry_point_display_reason.h
+++ b/components/send_tab_to_self/entry_point_display_reason.h
@@ -18,6 +18,9 @@
 
 class SendTabToSelfSyncService;
 
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+//   org.chromium.chrome.browser.share.send_tab_to_self)
 enum class EntryPointDisplayReason {
   // The send-tab-to-self entry point should be shown because all the conditions
   // are met and the feature is ready to be used.
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
index 2422a169..0cd7df3a 100644
--- a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
+++ b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -1177,7 +1177,8 @@
       {u"tesł.net", "test.net"},
       {u"łest.net", "test.net"},
       {u"łesł.net", "test.net"},
-  };
+      // Test case for https://crbug.com/1207187
+      {u"စ2.com", "o2.com"}};
   for (const TestCase& test_case : kTestCases) {
     const TopDomainEntry entry =
         IDNSpoofChecker().GetSimilarTopDomain(test_case.hostname);
diff --git a/components/url_formatter/spoof_checks/skeleton_generator.cc b/components/url_formatter/spoof_checks/skeleton_generator.cc
index 02f6a36..8f04ea15 100644
--- a/components/url_formatter/spoof_checks/skeleton_generator.cc
+++ b/components/url_formatter/spoof_checks/skeleton_generator.cc
@@ -103,7 +103,7 @@
   //   - {U+0D1F (ട), U+0E23 (ร), U+0EA3 (ຣ), U+0EAE (ຮ)} => s
   //   - U+1042 (၂) => j
   //   - {U+0966 (०), U+09E6 (০), U+0A66 (੦), U+0AE6 (૦), U+0B30 (ଠ),
-  //      U+0B66 (୦), U+0CE6 (೦)} => o,
+  //      U+0B66 (୦), U+0CE6 (೦), U+1005 (စ)} => o,
   //   - {U+09ED (৭), U+0A67 (੧), U+0AE7 (૧)} => q,
   //   - {U+0E1A (บ), U+0E9A (ບ)} => u,
   //   - {U+03B8 (θ)} => 0,
@@ -129,7 +129,7 @@
               "[мӎ] > m; [єҽҿၔ] > e; ґ > r; [ғӻ] > f;"
               "[ҫင] > c; [ұ丫] > y; [χҳӽӿ乂] > x;"
               "[ԃძ]  > d; [ԍဌ] > g; [ടรຣຮ] > s; ၂ > j;"
-              "[०০੦૦ଠ୦೦] > o;"
+              "[०০੦૦ଠ୦೦စ] > o;"
               "[৭੧૧] > q;"
               "[บບ] > u;"
               "[θ] > 0;"
diff --git a/components/user_notes/browser/user_note_service.cc b/components/user_notes/browser/user_note_service.cc
index 54eeeff..aeb32626 100644
--- a/components/user_notes/browser/user_note_service.cc
+++ b/components/user_notes/browser/user_note_service.cc
@@ -157,6 +157,11 @@
   NOTIMPLEMENTED();
 }
 
+void UserNoteService::OnNoteDeleted(const base::UnguessableToken& id) {
+  DCHECK(IsUserNotesEnabled());
+  NOTIMPLEMENTED();
+}
+
 void UserNoteService::OnNoteCreationDone(const base::UnguessableToken& id,
                                          const std::string& note_content) {
   DCHECK(IsUserNotesEnabled());
@@ -194,12 +199,6 @@
   (*entry_it->second.managers.begin())->RemoveNote(id);
 }
 
-void UserNoteService::OnNoteUpdated(const base::UnguessableToken& id,
-                                    const std::string& note_content) {
-  DCHECK(IsUserNotesEnabled());
-  NOTIMPLEMENTED();
-}
-
 UserNoteService::ModelMapEntry::ModelMapEntry(std::unique_ptr<UserNote> model)
     : model(std::move(model)) {}
 
diff --git a/components/user_notes/browser/user_note_service.h b/components/user_notes/browser/user_note_service.h
index 3fcd1c0..2cecd13 100644
--- a/components/user_notes/browser/user_note_service.h
+++ b/components/user_notes/browser/user_note_service.h
@@ -84,11 +84,10 @@
 
   // UserNotesUIDelegate implementation.
   void OnNoteFocused(const base::UnguessableToken& id) override;
+  void OnNoteDeleted(const base::UnguessableToken& id) override;
   void OnNoteCreationDone(const base::UnguessableToken& id,
                           const std::string& note_content) override;
   void OnNoteCreationCancelled(const base::UnguessableToken& id) override;
-  void OnNoteUpdated(const base::UnguessableToken& id,
-                     const std::string& note_content) override;
 
  private:
   struct ModelMapEntry {
diff --git a/components/user_notes/interfaces/user_notes_ui_delegate.h b/components/user_notes/interfaces/user_notes_ui_delegate.h
index 16aa2bf..d7e7235 100644
--- a/components/user_notes/interfaces/user_notes_ui_delegate.h
+++ b/components/user_notes/interfaces/user_notes_ui_delegate.h
@@ -23,16 +23,15 @@
   // Called when a note in the UI is focused.
   virtual void OnNoteFocused(const base::UnguessableToken& id) = 0;
 
+  // Called when the user deletes a note in the UI.
+  virtual void OnNoteDeleted(const base::UnguessableToken& id) = 0;
+
   // Called when the user successfully creates a new note in the UI.
   virtual void OnNoteCreationDone(const base::UnguessableToken& id,
                                   const std::string& note_content) = 0;
 
   // Called when the user aborts the note creation process in the UI.
   virtual void OnNoteCreationCancelled(const base::UnguessableToken& id) = 0;
-
-  // Called when the user updates an existing note in the UI.
-  virtual void OnNoteUpdated(const base::UnguessableToken& id,
-                             const std::string& note_content) = 0;
 };
 
 }  // namespace user_notes
diff --git a/components/viz/service/display/overlay_processor_ozone.cc b/components/viz/service/display/overlay_processor_ozone.cc
index 1c83da9..3ae5364 100644
--- a/components/viz/service/display/overlay_processor_ozone.cc
+++ b/components/viz/service/display/overlay_processor_ozone.cc
@@ -128,7 +128,6 @@
         NOTREACHED();
     }
   }
-  MaybeObserveHardwareCapabilities();
 }
 
 OverlayProcessorOzone::~OverlayProcessorOzone() = default;
@@ -144,6 +143,8 @@
 void OverlayProcessorOzone::CheckOverlaySupportImpl(
     const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
     OverlayCandidateList* surfaces) {
+  MaybeObserveHardwareCapabilities();
+
   auto full_size = surfaces->size();
   if (primary_plane)
     full_size += 1;
@@ -252,6 +253,11 @@
 }
 
 void OverlayProcessorOzone::MaybeObserveHardwareCapabilities() {
+  if (tried_observing_hardware_capabilities_) {
+    return;
+  }
+  tried_observing_hardware_capabilities_ = true;
+
   // HardwareCapabilities isn't necessary unless attempting multiple overlays.
   if (max_overlays_config_ <= 1) {
     return;
@@ -265,16 +271,24 @@
 
 void OverlayProcessorOzone::ReceiveHardwareCapabilities(
     ui::HardwareCapabilities hardware_capabilities) {
-  // Subtract 1 because one of these overlay capable planes will be needed for
-  // the primary plane.
-  int max_overlays_supported =
-      hardware_capabilities.num_overlay_capable_planes - 1;
-  max_overlays_considered_ =
-      std::min(max_overlays_supported, max_overlays_config_);
+  UMA_HISTOGRAM_BOOLEAN(
+      "Compositing.Display.OverlayProcessorOzone.HardwareCapabilitiesIsValid",
+      hardware_capabilities.is_valid);
+  if (hardware_capabilities.is_valid) {
+    // Subtract 1 because one of these overlay capable planes will be needed for
+    // the primary plane.
+    int max_overlays_supported =
+        hardware_capabilities.num_overlay_capable_planes - 1;
+    max_overlays_considered_ =
+        std::min(max_overlays_supported, max_overlays_config_);
 
-  UMA_HISTOGRAM_COUNTS_100(
-      "Compositing.Display.OverlayProcessorOzone.MaxOverlaysSupported",
-      max_overlays_supported);
+    UMA_HISTOGRAM_COUNTS_100(
+        "Compositing.Display.OverlayProcessorOzone.MaxPlanesSupported",
+        hardware_capabilities.num_overlay_capable_planes);
+  } else {
+    // Default to attempting 1 overlay if we get an invalid response.
+    max_overlays_considered_ = 1;
+  }
 
   // Different hardware capabilities may mean a different result for a specific
   // combination of overlays, so clear this cache.
diff --git a/components/viz/service/display/overlay_processor_ozone.h b/components/viz/service/display/overlay_processor_ozone.h
index 5809388..b0ecacb1b 100644
--- a/components/viz/service/display/overlay_processor_ozone.h
+++ b/components/viz/service/display/overlay_processor_ozone.h
@@ -56,9 +56,11 @@
                                    const gpu::Mailbox& mailbox,
                                    bool is_primary);
 
+  bool tried_observing_hardware_capabilities_ = false;
   std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_;
   const std::vector<OverlayStrategy> available_strategies_;
   gpu::SharedImageInterface* const shared_image_interface_;
+
   base::WeakPtrFactory<OverlayProcessorOzone> weak_ptr_factory_{this};
 };
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_processor_ozone_unittest.cc b/components/viz/service/display/overlay_processor_ozone_unittest.cc
index 91ca684..d8c9251 100644
--- a/components/viz/service/display/overlay_processor_ozone_unittest.cc
+++ b/components/viz/service/display/overlay_processor_ozone_unittest.cc
@@ -261,6 +261,7 @@
 };
 
 TEST(OverlayProcessorOzoneTest, ObserveHardwareCapabilites) {
+  OverlayCandidateList candidates;
   // Enable 4 overlays
   const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
       feature_and_params_list = {{features::kEnableOverlayPrioritization, {}},
@@ -277,11 +278,12 @@
   auto fake_candidates_unique = std::make_unique<FakeOverlayCandidatesOzone>();
   auto* fake_candidates = fake_candidates_unique.get();
 
+  TestOverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
+                                      nullptr);
   // No receive_callback yet.
   EXPECT_TRUE(fake_candidates->receive_callback().is_null());
 
-  TestOverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
-                                      nullptr);
+  processor.CheckOverlaySupport(nullptr, &candidates);
 
   // Receive callback is set.
   EXPECT_FALSE(fake_candidates->receive_callback().is_null());
@@ -289,42 +291,30 @@
   EXPECT_EQ(processor.MaxOverlaysConsidered(), 1);
 
   ui::HardwareCapabilities hc;
+  hc.is_valid = true;
   hc.num_overlay_capable_planes = 6;
   fake_candidates->receive_callback().Run(hc);
 
   // Uses max_overlays_config_ = 4.
   EXPECT_EQ(processor.MaxOverlaysConsidered(), 4);
 
+  hc.is_valid = true;
   hc.num_overlay_capable_planes = 4;
   fake_candidates->receive_callback().Run(hc);
 
   // Uses (num_overlay_capable_planes - 1) = 3.
   EXPECT_EQ(processor.MaxOverlaysConsidered(), 3);
-}
 
-TEST(OverlayProcessorOzoneTest, NullOverlayCandidates) {
-  // Enable 4 overlays
-  const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
-      feature_and_params_list = {{features::kEnableOverlayPrioritization, {}},
-                                 {features::kUseMultipleOverlays,
-                                  {{features::kMaxOverlaysParam, "4"}}}};
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitWithFeaturesAndParameters(feature_and_params_list, {});
-  // When overlay prioritization is explicitly disabled (Lacros) we should
-  // skip multiple overlays tests.
-  if (!features::IsOverlayPrioritizationEnabled()) {
-    GTEST_SKIP();
-  }
+  hc.is_valid = false;
+  hc.num_overlay_capable_planes = 0;
+  fake_candidates->receive_callback().Run(hc);
 
-  // Verifies that MaybeObserveHardwareCapabilities() handles a null
-  // overlay_candidates_
-  TestOverlayProcessorOzone processor(nullptr, {}, nullptr);
-
-  // Max overlays is still 1.
+  // Defaults to 1 overlay when receiving an invalid response.
   EXPECT_EQ(processor.MaxOverlaysConsidered(), 1);
 }
 
 TEST(OverlayProcessorOzoneTest, NoObserveHardwareCapabilites) {
+  OverlayCandidateList candidates;
   // Multiple overlays disabled.
   base::test::ScopedFeatureList scoped_features;
   scoped_features.InitAndDisableFeature(features::kUseMultipleOverlays);
@@ -332,11 +322,13 @@
   auto fake_candidates_unique = std::make_unique<FakeOverlayCandidatesOzone>();
   auto* fake_candidates = fake_candidates_unique.get();
 
+  OverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
+                                  nullptr);
+
   // No receive_callback yet.
   EXPECT_TRUE(fake_candidates->receive_callback().is_null());
 
-  OverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
-                                  nullptr);
+  processor.CheckOverlaySupport(nullptr, &candidates);
 
   // Receive callback is still unset because multiple overlays is disabled.
   EXPECT_TRUE(fake_candidates->receive_callback().is_null());
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc
index ea2192c..b42bc06 100644
--- a/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -56,10 +56,10 @@
 constexpr char kShouldAttemptMultipleOverlaysHistogramName[] =
     "Compositing.Display.OverlayProcessorUsingStrategy."
     "ShouldAttemptMultipleOverlays";
-constexpr char kNumOverlaysAttemptedHistogramName[] =
-    "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysAttempted";
 constexpr char kNumOverlaysPromotedHistogramName[] =
     "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysPromoted";
+constexpr char kNumOverlaysAttemptedHistogramName[] =
+    "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysAttempted";
 constexpr char kNumOverlaysFailedHistogramName[] =
     "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysFailed";
 
@@ -161,6 +161,10 @@
   auto* render_pass = render_passes->back().get();
   bool success = false;
 
+  UMA_HISTOGRAM_COUNTS_1000(
+      "Compositing.Display.OverlayProcessorUsingStrategy.NumQuadsConsidered",
+      render_pass->quad_list.size());
+
   DBG_DRAW_RECT("overlay.incoming.damage", (*damage_rect));
   for (auto&& each : surface_damage_rect_list) {
     DBG_DRAW_RECT("overlay.surface.damage", each);
@@ -185,6 +189,8 @@
   LogCheckOverlaySupportMetrics();
 
   DCHECK(candidates->empty() || success);
+  UMA_HISTOGRAM_COUNTS_100(kNumOverlaysPromotedHistogramName,
+                           candidates->size());
 
   UpdateOverlayStatusMap(*candidates);
   UpdateDamageRect(surface_damage_rect_list, *damage_rect);
@@ -585,6 +591,11 @@
       num_proposed_pre_sort);
 
   SortProposedOverlayCandidatesPrioritized(&proposed_candidates);
+  if (proposed_candidates.size() == 0) {
+    LogStrategyEnumUMA(num_proposed_pre_sort != 0
+                           ? OverlayStrategy::kNoStrategyFailMin
+                           : OverlayStrategy::kNoStrategyUsed);
+  }
 
   if (ShouldAttemptMultipleOverlays(proposed_candidates)) {
     auto* render_pass = render_pass_list->back().get();
@@ -665,11 +676,7 @@
   }
   RegisterOverlayRequirement(has_required_overlay);
 
-  if (proposed_candidates.size() == 0) {
-    LogStrategyEnumUMA(num_proposed_pre_sort != 0
-                           ? OverlayStrategy::kNoStrategyFailMin
-                           : OverlayStrategy::kNoStrategyUsed);
-  } else {
+  if (proposed_candidates.size() != 0) {
     LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail);
   }
   OnOverlaySwitchUMA(ProposedCandidateKey());
@@ -717,6 +724,7 @@
     OverlayCandidateList& candidates) {
   if (sorted_candidates.empty()) {
     UMA_HISTOGRAM_COUNTS_100(kNumOverlaysAttemptedHistogramName, 0);
+    UMA_HISTOGRAM_COUNTS_100(kNumOverlaysFailedHistogramName, 0);
     return false;
   }
 
@@ -795,12 +803,11 @@
 
   UMA_HISTOGRAM_COUNTS_100(kNumOverlaysAttemptedHistogramName,
                            num_overlays_attempted);
-  UMA_HISTOGRAM_COUNTS_100(kNumOverlaysPromotedHistogramName,
-                           num_overlays_promoted);
   UMA_HISTOGRAM_COUNTS_100(kNumOverlaysFailedHistogramName,
                            num_overlays_attempted - num_overlays_promoted);
 
   if (candidates.empty()) {
+    LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail);
     return false;
   }
 
@@ -824,6 +831,7 @@
   // Commit successful candidates.
   for (auto& test_candidate : test_candidates) {
     test_candidate.strategy->CommitCandidate(test_candidate, render_pass);
+    LogStrategyEnumUMA(test_candidate.strategy->GetUMAEnum());
   }
 
   return true;
diff --git a/content/browser/back_forward_cache_basics_browsertest.cc b/content/browser/back_forward_cache_basics_browsertest.cc
index 3a93841..c51deb3a 100644
--- a/content/browser/back_forward_cache_basics_browsertest.cc
+++ b/content/browser/back_forward_cache_basics_browsertest.cc
@@ -1077,9 +1077,10 @@
 
 // Test pagehide's persisted value and whether the page can be BFCached when a
 // sticky/non-sticky feature is used on the mainframe/subframe.
+// TODO(crbug.com/1277888): flaky.
 IN_PROC_BROWSER_TEST_P(
     BackForwardCacheBrowserTestWithVaryingFrameAndFeatureStickinessType,
-    TestPagehidePersistedValue) {
+    DISABLED_TestPagehidePersistedValue) {
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url_a(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b)"));
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 68a96d4..b12b7683 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -22,7 +22,6 @@
 #include "base/memory/memory_pressure_monitor.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/no_destructor.h"
@@ -169,7 +168,6 @@
 #include "content/browser/android/tracing_controller_android.h"
 #include "content/browser/font_unique_name_lookup/font_unique_name_lookup.h"
 #include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
-#include "content/common/android/cpu_affinity_setter.h"
 #include "media/base/android/media_drm_bridge_client.h"
 #include "ui/android/screen_android.h"
 #include "ui/display/screen.h"
@@ -520,20 +518,6 @@
 int BrowserMainLoop::EarlyInitialization() {
   TRACE_EVENT0("startup", "BrowserMainLoop::EarlyInitialization");
 
-#if BUILDFLAG(IS_ANDROID)
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingBrowserMainBiggerParam, false)) {
-    SetCpuAffinityForCurrentThread(base::HasBiggerCpuCores()
-                                       ? base::CpuAffinityMode::kBiggerCoresOnly
-                                       : base::CpuAffinityMode::kBigCoresOnly);
-  } else if (base::GetFieldTrialParamByFeatureAsBool(
-                 features::kBigLittleScheduling,
-                 features::kBigLittleSchedulingBrowserMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
-#endif
-
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
   // The initialization of the sandbox host ends up with forking the Zygote
   // process and requires no thread been forked. The initialization has happened
diff --git a/content/browser/browser_process_io_thread.cc b/content/browser/browser_process_io_thread.cc
index 8239049..ea3923e9 100644
--- a/content/browser/browser_process_io_thread.cc
+++ b/content/browser/browser_process_io_thread.cc
@@ -9,7 +9,6 @@
 #include "base/clang_profiling_buildflags.h"
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/hang_watcher.h"
 #include "base/threading/thread_restrictions.h"
@@ -22,14 +21,12 @@
 #include "content/browser/utility_process_host.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/process_type.h"
 #include "net/url_request/url_fetcher.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/jni_android.h"
-#include "content/common/android/cpu_affinity_setter.h"
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -90,13 +87,6 @@
   if (!thread_name().empty()) {
     base::android::AttachCurrentThreadWithName(thread_name());
   }
-
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingBrowserIOBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
-
 #endif
 
   IOThreadRun(run_loop);
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 0c6808c..75a4318d 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -264,8 +264,6 @@
     if (gpu_feature_data.name == "skia_renderer" ||
         gpu_feature_data.name == "raw_draw" ||
         gpu_feature_data.name == "direct_rendering_display_compositor" ||
-        gpu_feature_data.name ==
-            "force_gpu_main_thread_to_normal_priority_drdc" ||
         gpu_feature_data.name == "viz_hit_test_surface_layer") {
       status = (gpu_feature_data.disabled ? "disabled_off_ok" : "enabled_on");
     } else if (gpu_feature_data.disabled || gpu_access_blocked ||
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc
index c095eb5..3ce5bf5c 100644
--- a/content/browser/network_service_instance_impl.cc
+++ b/content/browser/network_service_instance_impl.cc
@@ -16,7 +16,6 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/message_loop/message_pump_type.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
@@ -43,7 +42,6 @@
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/service_process_host.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/network_service_util.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -61,10 +59,6 @@
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/network_service_test.mojom.h"
 
-#if BUILDFLAG(IS_ANDROID)
-#include "content/common/android/cpu_affinity_setter.h"
-#endif  // BUILDFLAG(IS_ANDROID)
-
 #if !BUILDFLAG(IS_ANDROID)
 #include "content/browser/network_sandbox.h"
 #endif
@@ -132,14 +126,6 @@
 
 void CreateInProcessNetworkServiceOnThread(
     mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
-#if BUILDFLAG(IS_ANDROID)
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingNetworkMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
-#endif
-
   // The test interface doesn't need to be implemented in the in-process case.
   auto registry = std::make_unique<service_manager::BinderRegistry>();
   registry->AddInterface(base::BindRepeating(
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 2a3518b4..dcbd1e9 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -12830,12 +12830,10 @@
 // Ensure that we do not corrupt a NavigationEntry's PageState if two forward
 // navigations compete in different frames, and the main frame entry contains an
 // iframe of its own.  See https://crbug.com/623319.
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       PageStateWithIframeAfterForwardInCompetingFrames) {
-  // TODO(https://crbug.com/1101292): Remove this when test passes. It only
-  // fails on ASAN builder.
-  if (ShouldCreateNewHostForSameSiteSubframe())
-    return;
+// TODO(https://crbug.com/1101292): flaky.
+IN_PROC_BROWSER_TEST_P(
+    NavigationControllerBrowserTest,
+    DISABLED_PageStateWithIframeAfterForwardInCompetingFrames) {
   // Navigate to a page with an iframe.
   GURL url_a(embedded_test_server()->GetURL(
       "/navigation_controller/page_with_data_iframe.html"));
@@ -16704,8 +16702,10 @@
 // history.back() called twice in the renderer process should not make the user
 // navigate back twice.
 // Regression test for https://crbug.com/869710
-IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
-                       HistoryBackTwiceFromRendererWithoutUserGesture) {
+// TODO(crbug.com/1328912): flaky.
+IN_PROC_BROWSER_TEST_P(
+    NavigationControllerBrowserTest,
+    DISABLED_HistoryBackTwiceFromRendererWithoutUserGesture) {
   GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
   GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
   GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index 6b41128..9974afd 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -1302,9 +1302,10 @@
                                                     url1);
   ASSERT_TRUE(controller.GetVisibleEntry());
 
-  // Make the entry believe its RenderProcessHost is a guest.
+  // Ensure the entry's SiteInstance and RenderProcessHost are for a guest.
   NavigationEntryImpl* entry1 = controller.GetVisibleEntry();
-  ASSERT_EQ(entry1->site_instance(), guest_instance);
+  ASSERT_EQ(entry1->site_instance()->GetStoragePartitionConfig(),
+            kGuestPartitionConfig);
   ASSERT_TRUE(entry1->site_instance()->IsGuest());
   ASSERT_TRUE(entry1->site_instance()->GetProcess()->IsForGuestsOnly());
 
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index bd369ed..afdc7cc6 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -41,6 +41,7 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/render_widget_host_observer.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -1455,49 +1456,75 @@
             rfh2->GetRenderViewHost()->opener_frame_token());
 }
 
-// Test that we reuse the same guest SiteInstance if we navigate across sites.
-TEST_P(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
+// Test guest navigation behavior when navigating across sites.  With site
+// isolation for guests, we should swap guest SiteInstances, otherwise the
+// guest SiteInstance should be reused.
+TEST_P(RenderFrameHostManagerTest, GuestNavigations) {
   // Create a custom StoragePartitionConfig for the guest SiteInstance. The
   // resulting SiteInstance should become associated with this
   // StoragePartitionConfig rather than a default one.
   const StoragePartitionConfig kGuestPartitionConfig =
       StoragePartitionConfig::Create(browser_context(), "someapp",
                                      "somepartition", /*in_memory=*/false);
-  scoped_refptr<SiteInstance> instance =
+  scoped_refptr<SiteInstance> initial_instance =
       SiteInstance::CreateForGuest(browser_context(), kGuestPartitionConfig);
   std::unique_ptr<TestWebContents> web_contents(
-      TestWebContents::Create(browser_context(), instance));
+      TestWebContents::Create(browser_context(), initial_instance));
 
-  EXPECT_TRUE(instance->IsGuest());
-  EXPECT_EQ(kGuestPartitionConfig, instance->GetStoragePartitionConfig());
+  EXPECT_TRUE(initial_instance->IsGuest());
+  EXPECT_EQ(kGuestPartitionConfig,
+            initial_instance->GetStoragePartitionConfig());
 
   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
+  RenderFrameHostImpl* initial_host = manager->current_frame_host();
 
-  RenderFrameHostImpl* host = nullptr;
-
-  // 1) The first navigation. --------------------------
+  // 1) First navigation. ------------------------
+  // Start the first navigation, but do not commit.
   const GURL kUrl1("http://www.google.com/");
   NavigationEntryImpl entry1(
       nullptr /* instance */, kUrl1, Referrer(), absl::nullopt,
       std::u16string() /* title */, ui::PAGE_TRANSITION_TYPED,
       false /* is_renderer_init */, nullptr /* blob_url_loader_factory */,
       false /* is_initial_entry */);
-  host = NavigateToEntry(manager, &entry1);
+  RenderFrameHostImpl* host = NavigateToEntry(manager, &entry1);
 
-  // The RenderFrameHost created in Init will be reused.
-  EXPECT_TRUE(host == manager->current_frame_host());
+  // The SiteInstance of the navigating RenderFrameHost should still be a guest
+  // SiteInstance in the same StoragePartition.
+  scoped_refptr<SiteInstanceImpl> first_instance = host->GetSiteInstance();
+  EXPECT_EQ(first_instance->GetStoragePartitionConfig(), kGuestPartitionConfig);
+  EXPECT_TRUE(first_instance->IsGuest());
+
+  // Without site isolation for guests, we should stay in the same initial
+  // RenderFrameHost and SiteInstance.  With site isolation for guests, we have
+  // to swap SiteInstances and RenderFrameHosts, since the initial SiteInstance
+  // (`instance`) has an empty site and process lock, whereas the navigation
+  // needs a SiteInstance with the site URL that corresponds to `kUrl1`.  Note
+  // that even in that case, there will be no speculative RenderFrameHost since
+  // the new RenderFrameHost will be committed right away due to the early
+  // commit optimization. This behavior may change if the early commit
+  // optimization is removed in https://crbug.com/1072817.
+  if (SiteIsolationPolicy::IsSiteIsolationForGuestsEnabled()) {
+    EXPECT_NE(first_instance, initial_instance);
+    EXPECT_NE(host, initial_host);
+    EXPECT_EQ("http://google.com/",
+              first_instance->GetSiteInfo().site_url().spec());
+  } else {
+    EXPECT_EQ(first_instance, initial_instance);
+    EXPECT_EQ(host, initial_host);
+  }
   EXPECT_FALSE(manager->speculative_frame_host());
-  EXPECT_EQ(manager->current_frame_host()->GetSiteInstance(), instance);
+  EXPECT_EQ(host, manager->current_frame_host());
 
   // Commit.
   DidNavigateFrame(manager, host);
-  // Commit to SiteInstance should be delayed until RenderFrame commit.
   EXPECT_EQ(host, manager->current_frame_host());
   ASSERT_TRUE(host);
   EXPECT_TRUE(host->GetSiteInstance()->HasSite());
 
-  // 2) Navigate to a different domain. -------------------------
-  // Guests stay in the same process on navigation.
+  // 2) Second navigation. ------------------------
+  // Navigate to a different site. If site isolation for guests is enabled,
+  // this will swap processes. Otherwise, the guest will stay in the same
+  // process.
   const GURL kUrl2("http://www.chromium.org");
   const url::Origin kInitiatorOrigin =
       url::Origin::Create(GURL("https://initiator.example.com"));
@@ -1509,15 +1536,30 @@
       false /* is_initial_entry */);
   host = NavigateToEntry(manager, &entry2);
 
-  // The RenderFrameHost created in Init will be reused.
-  EXPECT_EQ(host, manager->current_frame_host());
-  EXPECT_FALSE(manager->speculative_frame_host());
+  // The first RenderFrameHost will be reused only when there's no site
+  // isolation for guests.
+  if (SiteIsolationPolicy::IsSiteIsolationForGuestsEnabled()) {
+    EXPECT_NE(host, manager->current_frame_host());
+    EXPECT_TRUE(manager->speculative_frame_host());
+  } else {
+    EXPECT_EQ(host, manager->current_frame_host());
+    EXPECT_FALSE(manager->speculative_frame_host());
+  }
 
   // Commit.
   DidNavigateFrame(manager, host);
   EXPECT_EQ(host, manager->current_frame_host());
   ASSERT_TRUE(host);
-  EXPECT_EQ(host->GetSiteInstance(), instance);
+  EXPECT_TRUE(host->GetSiteInstance()->IsGuest());
+
+  // We should swap SiteInstances with site isolation for guests.
+  if (SiteIsolationPolicy::IsSiteIsolationForGuestsEnabled()) {
+    EXPECT_NE(host->GetSiteInstance(), first_instance);
+    EXPECT_EQ("http://chromium.org/",
+              host->GetSiteInstance()->GetSiteInfo().site_url().spec());
+  } else {
+    EXPECT_EQ(host->GetSiteInstance(), first_instance);
+  }
 }
 
 namespace {
diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc
index b49b9e2c..5332678 100644
--- a/content/browser/service_worker/service_worker_process_manager_unittest.cc
+++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -217,10 +217,8 @@
   EXPECT_TRUE(worker_process_map().empty());
 }
 
-// Tests that ServiceWorkerProcessManager uses
-// StoragePartitionImpl::site_for_guest_service_worker_or_shared_worker() when
-// it's set. This enables finding the appropriate process when inside a
-// StoragePartition for guests (e.g., the <webview> tag).
+// Tests that ServiceWorkerProcessManager finds the appropriate process when
+// inside a StoragePartition for guests (e.g., the <webview> tag).
 // https://crbug.com/781313
 TEST_F(ServiceWorkerProcessManagerTest,
        AllocateWorkerProcess_StoragePartitionForGuests) {
@@ -266,9 +264,8 @@
   storage_partition->set_is_guest();
   process_manager_->set_storage_partition(storage_partition);
 
-  // Allocate a process to a worker. It should use the site URL of
-  // |guest_site_instance| instead of |script_url_| as the site URL of the
-  // SiteInstance, and it should be in the guest's StoragePartition.
+  // Allocate a process to a worker. It should be in the guest's
+  // StoragePartition.
   {
     const int kEmbeddedWorkerId = 77;  // dummy value
     ServiceWorkerProcessManager::AllocatedProcessInfo process_info;
@@ -278,9 +275,9 @@
             network::mojom::CrossOriginEmbedderPolicyValue::kNone,
             true /* can_use_existing_process */, &process_info);
     EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
-    EXPECT_EQ(
-        guest_site_instance->GetSiteURL(),
-        render_process_host_factory_->last_site_instance_used()->GetSiteURL());
+    EXPECT_EQ(guest_site_instance->GetStoragePartitionConfig(),
+              render_process_host_factory_->last_site_instance_used()
+                  ->GetStoragePartitionConfig());
     EXPECT_TRUE(
         render_process_host_factory_->last_site_instance_used()->IsGuest());
     auto* rph = RenderProcessHost::FromID(process_info.process_id);
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 0924b5c..333e930b 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -1781,15 +1781,17 @@
   }
 
   // Verify that a SiteInstance created with CreateForGuest() is considered
-  // a <webview> guest and has a site URL that reflects the guest's
-  // StoragePartition configuration.
+  // a <webview> guest.  Without site isolation for guests, its site URL
+  // should reflect the guest's StoragePartition configuration.
   const StoragePartitionConfig kGuestConfig = StoragePartitionConfig::Create(
       context(), "appid", "partition_name", /*in_memory=*/false);
   const GURL kGuestSiteUrl(std::string(kGuestScheme) +
                            "://appid/persist?partition_name#nofallback");
   auto instance2 = SiteInstanceImpl::CreateForGuest(context(), kGuestConfig);
   EXPECT_TRUE(instance2->IsGuest());
-  EXPECT_EQ(kGuestSiteUrl, instance2->GetSiteURL());
+  EXPECT_EQ(instance2->GetStoragePartitionConfig(), kGuestConfig);
+  if (!SiteIsolationPolicy::IsSiteIsolationForGuestsEnabled())
+    EXPECT_EQ(kGuestSiteUrl, instance2->GetSiteURL());
 }
 
 TEST_F(SiteInstanceTest, DoesSiteRequireDedicatedProcess) {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index e6a9931..44b16d2 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -345,6 +345,8 @@
           {"EditContext", blink::features::kEditContext},
           {"ElementSuperRareData", blink::features::kElementSuperRareData},
           {"FileHandling", blink::features::kFileHandlingAPI},
+          {"FixedElementsDontOverscroll",
+           blink::features::kFixedElementsDontOverscroll},
           {"Fledge", blink::features::kFledge, kSetOnlyIfOverridden},
           {"Fledge", features::kPrivacySandboxAdsAPIsOverride,
            kSetOnlyIfOverridden},
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index dd51f5ec..3069930 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -257,8 +257,6 @@
 
   if (is_android) {
     sources += [
-      "android/cpu_affinity_setter.cc",
-      "android/cpu_affinity_setter.h",
       "android/cpu_time_metrics.cc",
       "android/cpu_time_metrics.h",
       "android/cpu_time_metrics_internal.cc",
diff --git a/content/common/android/cpu_affinity_setter.cc b/content/common/android/cpu_affinity_setter.cc
deleted file mode 100644
index 61333e2d..0000000
--- a/content/common/android/cpu_affinity_setter.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/android/cpu_affinity_setter.h"
-
-#include "base/no_destructor.h"
-#include "base/threading/thread_local.h"
-#include "base/timer/timer.h"
-
-namespace content {
-
-namespace {
-
-class CpuAffinitySetter;
-
-base::ThreadLocalOwnedPointer<CpuAffinitySetter>& GetCpuAffinitySetter() {
-  static base::NoDestructor<base::ThreadLocalOwnedPointer<CpuAffinitySetter>>
-      setter;
-  return *setter;
-}
-
-class CpuAffinitySetter {
- public:
-  CpuAffinitySetter() = default;
-  ~CpuAffinitySetter() = default;
-
-  void SetCpuAffinity(base::CpuAffinityMode mode) {
-    mode_ = mode;
-    SetModeInternal();
-
-    if (mode == base::CpuAffinityMode::kDefault) {
-      timer_.Stop();
-    } else if (!timer_.IsRunning()) {
-      timer_.Start(FROM_HERE, base::Seconds(15), this,
-                   &CpuAffinitySetter::SetModeInternal);
-    }
-  }
-
- private:
-  void SetModeInternal() {
-    auto current = base::CurrentThreadCpuAffinityMode();
-    if (!current || *current != mode_)
-      base::SetThreadCpuAffinityMode(base::PlatformThread::CurrentId(), mode_);
-  }
-
-  base::CpuAffinityMode mode_;
-  base::RepeatingTimer timer_;
-};
-
-}  // namespace
-
-void SetCpuAffinityForCurrentThread(base::CpuAffinityMode mode) {
-  auto& setter = GetCpuAffinitySetter();
-  if (!setter.Get())
-    setter.Set(std::make_unique<CpuAffinitySetter>());
-
-  setter.Get()->SetCpuAffinity(mode);
-}
-
-}  // namespace content
diff --git a/content/common/android/cpu_affinity_setter.h b/content/common/android/cpu_affinity_setter.h
deleted file mode 100644
index 731f250e..0000000
--- a/content/common/android/cpu_affinity_setter.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_ANDROID_CPU_AFFINITY_SETTER_H_
-#define CONTENT_COMMON_ANDROID_CPU_AFFINITY_SETTER_H_
-
-#include "base/cpu_affinity_posix.h"
-
-namespace content {
-
-// Sets the given CPU affinity for the current thread and polls every 15 seconds
-// to check if it was changed and if so sets it to |mode| again.
-void SetCpuAffinityForCurrentThread(base::CpuAffinityMode mode);
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_ANDROID_CPU_AFFINITY_SETTER_H_
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 3375ce2..6c394c4d 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -14,7 +14,6 @@
 #include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
 #include "base/message_loop/message_pump_type.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/clamped_math.h"
 #include "base/process/process_metrics.h"
@@ -38,7 +37,6 @@
 #include "content/gpu/gpu_child_thread.h"
 #include "content/gpu/gpu_process.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/result_codes.h"
@@ -76,7 +74,6 @@
 #if BUILDFLAG(IS_ANDROID)
 #include "base/trace_event/memory_dump_manager.h"
 #include "components/tracing/common/graphics_memory_dump_provider_android.h"
-#include "content/common/android/cpu_affinity_setter.h"
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -391,11 +388,6 @@
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics",
       nullptr);
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingGpuMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
 #endif
 
   internal::PartitionAllocSupport::Get()->ReconfigureAfterTaskRunnerInit(
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc
index a49d51672..8d95b36 100644
--- a/content/gpu/in_process_gpu_thread.cc
+++ b/content/gpu/in_process_gpu_thread.cc
@@ -5,13 +5,11 @@
 #include "content/gpu/in_process_gpu_thread.h"
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/gpu/gpu_child_thread.h"
 #include "content/gpu/gpu_process.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/config/gpu_preferences.h"
 #include "gpu/ipc/service/gpu_init.h"
@@ -23,7 +21,6 @@
 
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/jni_android.h"
-#include "content/common/android/cpu_affinity_setter.h"
 #endif
 
 namespace content {
@@ -51,12 +48,6 @@
   base::android::AttachCurrentThreadWithName(thread_name());
   // Up the priority of the |io_thread_| on Android.
   io_thread_priority = base::ThreadPriority::DISPLAY;
-
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingGpuMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
 #endif
 
   gpu_process_ = new GpuProcess(io_thread_priority);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 4d88b735..c4fe28125 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -1156,11 +1156,6 @@
     "BackgroundMediaRendererHasModerateBinding",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Takes advantage of specifying which big.LITTLE cores to schedule different
-// threads on.
-const base::Feature kBigLittleScheduling{"BigLittleScheduling",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Coalesce independent begin frame by ignoring begin frame that is out of date.
 const base::Feature kCoalesceIndependentBeginFrame{
     "CoalesceIndependentBeginFrame", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -1193,19 +1188,6 @@
 // https://w3c.github.io/web-nfc/
 const base::Feature kWebNfc{"WebNFC", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const char kBigLittleSchedulingBrowserMainBiggerParam[] =
-    "BigLittleSchedulingBrowserMainBiggerParam";
-const char kBigLittleSchedulingBrowserMainBigParam[] =
-    "BigLittleSchedulingBrowserMainBigParam";
-const char kBigLittleSchedulingBrowserIOBigParam[] =
-    "BigLittleSchedulingBrowserIOBigParam";
-const char kBigLittleSchedulingRenderMainBigParam[] =
-    "BigLittleSchedulingRenderMainBigParam";
-const char kBigLittleSchedulingNetworkMainBigParam[] =
-    "BigLittleSchedulingNetworkMainBigParam";
-const char kBigLittleSchedulingGpuMainBigParam[] =
-    "BigLittleSchedulingGpuMainBigParam";
-
 // When the context menu is triggered, the browser allows motion in a small
 // region around the initial touch location menu to allow for finger jittering.
 // This param holds the movement threshold in DIPs to consider drag an
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 050f180..229e147 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -287,7 +287,6 @@
 CONTENT_EXPORT extern const base::Feature kAccessibilityPageZoom;
 CONTENT_EXPORT extern const base::Feature
     kBackgroundMediaRendererHasModerateBinding;
-CONTENT_EXPORT extern const base::Feature kBigLittleScheduling;
 CONTENT_EXPORT extern const base::Feature kCoalesceIndependentBeginFrame;
 CONTENT_EXPORT extern const base::Feature kOnDemandAccessibilityEvents;
 CONTENT_EXPORT extern const base::Feature kRequestDesktopSiteExceptions;
@@ -296,12 +295,6 @@
 CONTENT_EXPORT extern const base::Feature kWarmUpNetworkProcess;
 CONTENT_EXPORT extern const base::Feature kWebNfc;
 
-extern const char kBigLittleSchedulingBrowserMainBiggerParam[];
-extern const char kBigLittleSchedulingBrowserMainBigParam[];
-extern const char kBigLittleSchedulingBrowserIOBigParam[];
-extern const char kBigLittleSchedulingRenderMainBigParam[];
-extern const char kBigLittleSchedulingNetworkMainBigParam[];
-extern const char kBigLittleSchedulingGpuMainBigParam[];
 extern const char kDragAndDropMovementThresholdDipParam[];
 
 CONTENT_EXPORT extern const base::Feature kOptimizeEarlyNavigation;
diff --git a/content/renderer/pepper/video_encoder_shim.cc b/content/renderer/pepper/video_encoder_shim.cc
index 1a007c3fe..f368c53 100644
--- a/content/renderer/pepper/video_encoder_shim.cc
+++ b/content/renderer/pepper/video_encoder_shim.cc
@@ -391,6 +391,7 @@
     // notions of denominator/numerator.
     profile.max_framerate_numerator = config.g_timebase.den;
     profile.max_framerate_denominator = config.g_timebase.num;
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     profiles.push_back(profile);
   }
 
@@ -400,6 +401,7 @@
     profile.max_resolution = gfx::Size(kMaxWidth, kMaxHeight);
     profile.max_framerate_numerator = config.g_timebase.den;
     profile.max_framerate_denominator = config.g_timebase.num;
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     profile.profile = media::VP9PROFILE_PROFILE0;
     profiles.push_back(profile);
   }
diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc
index 3af0b8d..62b55fe 100644
--- a/content/renderer/render_process_impl.cc
+++ b/content/renderer/render_process_impl.cc
@@ -25,7 +25,6 @@
 #include "base/debug/stack_trace.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/system/sys_info.h"
 #include "base/task/thread_pool/initialization_util.h"
@@ -51,10 +50,6 @@
 #include "v8/include/v8-wasm-trap-handler-posix.h"
 #endif
 
-#if BUILDFLAG(IS_ANDROID)
-#include "content/common/android/cpu_affinity_setter.h"
-#endif
-
 namespace {
 
 void SetV8FlagIfFeature(const base::Feature& feature, const char* v8_flag) {
@@ -169,13 +164,7 @@
   bool enable_shared_array_buffer_unconditionally =
       base::FeatureList::IsEnabled(features::kSharedArrayBuffer);
 
-#if BUILDFLAG(IS_ANDROID)
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingRenderMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
-#else
+#if !BUILDFLAG(IS_ANDROID)
   // Bypass the SAB restriction for the Finch "kill switch".
   enable_shared_array_buffer_unconditionally =
       enable_shared_array_buffer_unconditionally ||
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc
index 5ff436dbf..c9f681c 100644
--- a/content/renderer/renderer_main_platform_delegate_android.cc
+++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -5,10 +5,8 @@
 #include "content/renderer/renderer_main_platform_delegate.h"
 
 #include "base/android/build_info.h"
-#include "base/cpu_affinity_posix.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
-#include "content/public/common/content_features.h"
 #include "content/renderer/seccomp_sandbox_status_android.h"
 #include "sandbox/linux/seccomp-bpf-helpers/seccomp_starter_android.h"
 #include "sandbox/sandbox_buildflags.h"
@@ -39,8 +37,6 @@
 #if BUILDFLAG(USE_SECCOMP_BPF)
   sandbox::BaselinePolicyAndroid::RuntimeOptions options(
       starter.GetDefaultBaselineOptions());
-  options.allow_sched_affinity =
-      base::FeatureList::IsEnabled(features::kBigLittleScheduling);
   starter.set_policy(std::make_unique<sandbox::BaselinePolicyAndroid>(options));
 #endif
   starter.StartSandbox();
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c89f78f..9bab0de 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -3061,3 +3061,20 @@
     ]
   }
 }
+
+group("gpu_pytype") {
+  testonly = true
+
+  data = [
+    "//content/test/gpu/run_pytype.py",
+
+    "//build/util/lib/results/",
+  ]
+
+  data_deps = [
+    # This includes more than we strictly need to, but this ensures that we
+    # don't accidentally omit Python files that the real tests would be using.
+    ":telemetry_gpu_integration_test_scripts_only",
+    ":telemetry_gpu_integration_test_support",
+  ]
+}
diff --git a/content/test/gpu/PRESUBMIT.py b/content/test/gpu/PRESUBMIT.py
index ac6cabf..4686d20b 100644
--- a/content/test/gpu/PRESUBMIT.py
+++ b/content/test/gpu/PRESUBMIT.py
@@ -11,9 +11,10 @@
 USE_PYTHON3 = True
 
 EXTRA_PATHS_COMPONENTS = [
-    tuple(['build']),
+    ('build', ),
     ('build', 'fuchsia'),
-    tuple(['testing']),
+    ('build', 'util'),
+    ('testing', ),
     ('third_party', 'catapult', 'common', 'py_utils'),
     ('third_party', 'catapult', 'devil'),
     ('third_party', 'catapult', 'telemetry'),
@@ -21,11 +22,8 @@
     ('tools', 'perf'),
 ]
 
-# Directories that should have pytype run on them when Python files are changed.
-PYTYPE_DIRECTORIES = []
 
-
-def CommonChecks(input_api, output_api, run_pytype):
+def CommonChecks(input_api, output_api):
   results = []
 
   gpu_env = dict(input_api.environ)
@@ -92,58 +90,12 @@
       version='2.7')
   results.extend(input_api.RunTests(pylint_checks))
 
-  # pytype can take quite a long time to run on the GPU code, likely due to all
-  # the dependencies that it has to check as well. So, don't run pytype except
-  # on commit (i.e. on the bots).
-  if run_pytype:
-    # pytype specifies that the provided PYTHONPATH is :-separated.
-    pytype_paths = [testing_path, current_path] + pylint_extra_paths
-    pytype_python_path = ':'.join(pytype_paths)
-    results.extend(RunPytype(input_api, output_api, pytype_python_path,
-                             gpu_env))
-
   results.extend(CheckForNewSkipExpectations(input_api, output_api))
+  results.extend(CheckPytypePathsInSync(input_api, output_api))
 
   return results
 
 
-def RunPytype(input_api, output_api, python_path, gpu_env):
-  """Runs pytype on changed Python files to enforce type hinting."""
-  affected_directories = set()
-  abspath_directories = {
-      input_api.os_path.join(input_api.PresubmitLocalPath(), d): d
-      for d in PYTYPE_DIRECTORIES
-  }
-  file_filter = lambda f: f.AbsoluteLocalPath().endswith('.py')
-  for affected_file in input_api.AffectedFiles(file_filter=file_filter):
-    for abs_d, d in abspath_directories.items():
-      if affected_file.AbsoluteLocalPath().startswith(abs_d):
-        affected_directories.add(d)
-        break
-
-  if not affected_directories:
-    return []
-
-  script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
-                                       'run_pytype.py')
-  pytype_cmd = [
-      input_api.python3_executable,
-      script_path,
-      '--pythonpath',
-      python_path,
-      '--keep-going',
-      '--jobs',
-      'auto',
-  ]
-  pytype_cmd.extend(list(affected_directories))
-  pytype_test = input_api.Command(name='run_content_test_gpu_pytype',
-                                  cmd=pytype_cmd,
-                                  kwargs={'env': gpu_env},
-                                  message=output_api.PresubmitPromptWarning,
-                                  python3=True)
-  return input_api.RunTests([pytype_test])
-
-
 def CheckForNewSkipExpectations(input_api, output_api):
   """Checks for and dissuades the addition of new Skip expectations."""
   new_skips = []
@@ -170,9 +122,37 @@
   return result
 
 
+def CheckPytypePathsInSync(input_api, output_api):
+  """Checks that run_pytype.py's paths are in sync with PRESUBMIT.py's"""
+  filepath = input_api.os_path.join(input_api.PresubmitLocalPath(),
+                                    'run_pytype.py')
+  with open(filepath) as infile:
+    contents = infile.read()
+  # Grab the EXTRA_PATHS_COMPONENTS = [...] portion as a string.
+  match = input_api.re.search(r'(EXTRA_PATHS_COMPONENTS\s*=\s*[^=]*\]\n)',
+                              contents, input_api.re.DOTALL)
+  if not match:
+    return [
+        output_api.PresubmitError(
+            'Unable to find EXTRA_PATHS_COMPONENTS in run_pytype.py. Maybe '
+            'the code in PRESUBMIT.py needs to be updated?')
+    ]
+  expression = match.group(0)
+  expression = expression.split('=', 1)[1]
+  expression = expression.lstrip()
+  pytype_path_components = input_api.ast.literal_eval(expression)
+  if EXTRA_PATHS_COMPONENTS != pytype_path_components:
+    return [
+        output_api.PresubmitError(
+            'EXTRA_PATHS_COMPONENTS is not synced between PRESUBMIT.py and '
+            'run_pytype.py, please ensure they are identical.')
+    ]
+  return []
+
+
 def CheckChangeOnUpload(input_api, output_api):
-  return CommonChecks(input_api, output_api, run_pytype=False)
+  return CommonChecks(input_api, output_api)
 
 
 def CheckChangeOnCommit(input_api, output_api):
-  return CommonChecks(input_api, output_api, run_pytype=True)
+  return CommonChecks(input_api, output_api)
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index 0597496a..3cf655f 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -92,6 +92,7 @@
 crbug.com/1208827 [ chromeos-board-amd64-generic ] WebCodecs_Encode_capture_avc1.42001E_prefer-hardware [ RetryOnFailure ]
 
 crbug.com/1286918 [ android android-pixel-6 ] WebCodecs_TexImage2d_sw_decoder [ Failure ]
+crbug.com/1286918 [ android android-pixel-6 ] WebCodecs_TexImage2d_capture [ Failure ]
 crbug.com/1288914 [ android android-pixel-6 ] WebCodecs_TexImage2d_camera [ Failure ]
 
 crbug.com/1311091 WebCodecs_WebRTCPeerConnection_* [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index 16ac148..f35821c9 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -621,6 +621,7 @@
 crbug.com/1287249 [ android android-pixel-6 no-passthrough ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ Failure ]
 crbug.com/1287249 [ android android-pixel-6 no-passthrough ] conformance/glsl/bugs/constant-precision-qualifier.html [ Failure ]
 crbug.com/1287249 [ android android-pixel-6 no-passthrough ] conformance/textures/misc/video-rotation.html [ Failure ]
+crbug.com/1287249 [ android android-pixel-6 no-passthrough ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ]
 crbug.com/1287280 [ android android-pixel-6 no-passthrough ] conformance/more/conformance/quickCheckAPI-A.html [ Failure ]
 crbug.com/1287280 [ android android-pixel-6 no-passthrough ] conformance/offscreencanvas/context-lost-restored-worker.html [ Failure ]
 crbug.com/1287280 [ android android-pixel-6 no-passthrough ] conformance/offscreencanvas/context-lost-restored.html [ Failure ]
diff --git a/content/test/gpu/run_pytype.py b/content/test/gpu/run_pytype.py
index 1f835624..cc1f0df 100755
--- a/content/test/gpu/run_pytype.py
+++ b/content/test/gpu/run_pytype.py
@@ -4,17 +4,190 @@
 # found in the LICENSE file.
 """Simple helper script to run pytype on GPU Python code."""
 
+import argparse
+import json
 import os
 import subprocess
 import sys
+import time
+import typing
 
-if sys.platform != 'linux':
-  print('pytype is currently only supported on Linux, see '
-        'https://github.com/google/pytype/issues/1154')
-  sys.exit(0)
+# We can't depend on gpu_path_util, otherwise pytype's dependency graph ends up
+# finding a cycle.
+GPU_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_SRC_DIR = os.path.realpath(os.path.join(GPU_DIR, '..', '..', '..'))
 
-# pytype looks for a 'python' or 'python3' executable in PATH, so make sure that
-# the Python 3 executable from vpython is in the path.
-executable_dir = os.path.dirname(sys.executable)
-os.environ['PATH'] = executable_dir + os.pathsep + os.environ['PATH']
-subprocess.run([sys.executable, '-m', 'pytype'] + sys.argv[1:], check=True)
+sys.path.append(os.path.join(CHROMIUM_SRC_DIR, 'build', 'util'))
+
+# pylint: disable=wrong-import-position
+from lib.results import result_sink
+from lib.results import result_types
+# pylint: disable=wrong-import-position
+
+# This list should be kept in sync with EXTRA_PATH_COMPONENTS in PRESUBMIT.py
+EXTRA_PATHS_COMPONENTS = [
+    ('build', ),
+    ('build', 'fuchsia'),
+    ('build', 'util'),
+    ('testing', ),
+    ('third_party', 'catapult', 'common', 'py_utils'),
+    ('third_party', 'catapult', 'devil'),
+    ('third_party', 'catapult', 'telemetry'),
+    ('third_party', 'catapult', 'third_party', 'typ'),
+    ('tools', 'perf'),
+]
+EXTRA_PATHS = [
+    os.path.join(CHROMIUM_SRC_DIR, *p) for p in EXTRA_PATHS_COMPONENTS
+]
+EXTRA_PATHS.append(GPU_DIR)
+
+FILES_AND_DIRECTORIES_TO_CHECK = [
+    'gpu_tests',
+]
+
+TEST_NAME = 'gpu_pytype'
+TEST_LOCATION = '//content/test/gpu/run_pytype.py'
+
+
+# pylint: disable=too-many-arguments
+def report_results(status: str,
+                   duration: float,
+                   log: str,
+                   output_file: typing.Optional[str],
+                   sink_client: typing.Optional[result_sink.ResultSinkClient],
+                   failure_reason: typing.Optional[str] = None) -> None:
+  """Report results on bots.
+
+  Args:
+    status: A string containing the test status.
+    duration: An float containing the test duration in seconds.
+    log: A string containing the log output of the test.
+    output_dir: An optional string containing a path to a file to output JSON
+        to.
+    sink_client: An optional client for reporting results to ResultDB.
+    failure_reason: An optional string containing a reason why the test failed.
+  """
+  if output_file:
+    report_json_results(status, duration, output_file)
+  if sink_client:
+    sink_client.Post(test_id=TEST_NAME,
+                     status=status,
+                     duration=(duration * 1000),
+                     test_log=log,
+                     test_file=TEST_LOCATION,
+                     failure_reason=failure_reason)
+
+
+# pylint: enable=too-many-arguments
+
+
+def report_json_results(status: str, duration: float, output_file: str):
+  num_passes = 1 if status == result_types.PASS else 0
+  num_fails = 1 if status == result_types.FAIL else 0
+  num_skips = 1 if status == result_types.SKIP else 0
+  expected_result = (result_types.SKIP
+                     if status == result_types.SKIP else result_types.PASS)
+
+  output_json = {
+      'version': 3,
+      'interrupted': False,
+      'path_delimiter': '/',
+      'seconds_since_epoch': int(time.time()),
+      'num_failures_by_type': {
+          'FAIL': num_fails,
+          'TIMEOUT': 0,
+          'CRASH': 0,
+          'PASS': num_passes,
+          'SKIP': num_skips,
+      },
+      'num_regressions': 0 if status == expected_result else 1,
+      'tests': {
+          TEST_NAME: {
+              'expected': expected_result,
+              'actual': status,
+              'times': [
+                  duration,
+              ]
+          }
+      }
+  }
+
+  with open(output_file, 'w') as outfile:
+    json.dump(output_json, outfile)
+
+
+def parse_args():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--isolated-script-test-output',
+                      dest='output_file',
+                      help=('Path to JSON output file.'))
+
+  args, _ = parser.parse_known_args()
+  return args
+
+
+def main():
+  sink_client = result_sink.TryInitClient()
+  args = parse_args()
+
+  if sys.platform != 'linux':
+    print('pytype is currently only supported on Linux, see '
+          'https://github.com/google/pytype/issues/1154')
+    report_results(result_types.SKIP, 0, 'Skipped due to unsupported platform.',
+                   args.output_file, sink_client)
+    sys.exit(0)
+
+  # pytype looks for a 'python' or 'python3' executable in PATH, so make sure
+  # that the Python 3 executable from vpython is in the path.
+  executable_dir = os.path.dirname(sys.executable)
+  os.environ['PATH'] = executable_dir + os.pathsep + os.environ['PATH']
+
+  # pytype specifies that the provided PYTHONPATH is :-separated.
+  pythonpath = ':'.join(EXTRA_PATHS)
+  pytype_cmd = [
+      sys.executable,
+      '-m',
+      'pytype',
+      '--pythonpath',
+      pythonpath,
+      '--keep-going',
+      '--jobs',
+      'auto',
+  ]
+  pytype_cmd.extend(FILES_AND_DIRECTORIES_TO_CHECK)
+
+  if sink_client:
+    stdout_handle = subprocess.PIPE
+    stderr_handle = subprocess.STDOUT
+  else:
+    stdout_handle = None
+    stderr_handle = None
+
+  start_time = time.time()
+  try:
+    proc = subprocess.run(pytype_cmd,
+                          check=True,
+                          cwd=GPU_DIR,
+                          stdout=stdout_handle,
+                          stderr=stderr_handle,
+                          text=True)
+    stdout = proc.stdout
+    status = result_types.PASS
+    failure_reason = None
+  except subprocess.CalledProcessError as e:
+    stdout = e.stdout
+    status = result_types.FAIL
+    failure_reason = 'Checking Python 3 type hinting on GPU code failed.'
+  duration = (time.time() - start_time)
+
+  if stdout:
+    print(stdout)
+  report_results(status, duration, stdout or '', args.output_file, sink_client,
+                 failure_reason)
+
+  if status == result_types.FAIL:
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/content/utility/services.cc b/content/utility/services.cc
index dd837307..c82adda45 100644
--- a/content/utility/services.cc
+++ b/content/utility/services.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
@@ -15,7 +14,6 @@
 #include "components/services/storage/public/mojom/storage_service.mojom.h"
 #include "components/services/storage/storage_service_impl.h"
 #include "content/child/child_process.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/utility/content_utility_client.h"
 #include "content/public/utility/utility_thread.h"
@@ -39,8 +37,6 @@
 #include "base/mac/mach_logging.h"
 #include "sandbox/mac/system_services.h"
 #include "sandbox/policy/sandbox.h"
-#elif BUILDFLAG(IS_ANDROID)
-#include "content/common/android/cpu_affinity_setter.h"
 #endif
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
@@ -158,14 +154,6 @@
 
 auto RunNetworkService(
     mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
-#if BUILDFLAG(IS_ANDROID)
-  if (base::GetFieldTrialParamByFeatureAsBool(
-          features::kBigLittleScheduling,
-          features::kBigLittleSchedulingNetworkMainBigParam, false)) {
-    SetCpuAffinityForCurrentThread(base::CpuAffinityMode::kBigCoresOnly);
-  }
-#endif
-
   auto binders = std::make_unique<service_manager::BinderRegistry>();
   GetContentClient()->utility()->RegisterNetworkBinders(binders.get());
   return std::make_unique<network::NetworkService>(
diff --git a/docs/security/origin-vs-url.md b/docs/security/origin-vs-url.md
index 4fcb2c35..25bc0e6 100644
--- a/docs/security/origin-vs-url.md
+++ b/docs/security/origin-vs-url.md
@@ -88,21 +88,21 @@
 ```c++
 GURL url = ...;
 GURL origin = url.DeprecatedGetOriginAsURL();
-// BUG: |origin| will be incorrect if |url| is an "about:blank" URL
-// BUG: |origin| will be incorrect if |url| came from a sandboxed frame.
-// BUG: |origin| will be incorrect when |url| (rather than
-//      |base_url_for_data_url|) is used when working with loadDataWithBaseUrl
+// BUG: `origin` will be incorrect if `url` is an "about:blank" URL
+// BUG: `origin` will be incorrect if `url` came from a sandboxed frame.
+// BUG: `origin` will be incorrect when `url` (rather than
+//      `base_url_for_data_url`) is used when working with loadDataWithBaseUrl
 //      (see also https://crbug.com/1201514).
-// BUG: |origin| will be empty if |url| is a blob: URL like
+// BUG: `origin` will be empty if `url` is a blob: URL like
 //      "blob:http://origin/guid-goes-here".
-// NOTE: |GURL origin| is also an anti-pattern; see the "Use correct type to
+// NOTE: `GURL origin` is also an anti-pattern; see the "Use correct type to
 //       represent origins" section below.
 
 // Blink-specific example:
 KURL url = ...;
 scoped_refptr<SecurityOrigin> origin = SecurityOrigin::Create(url);
-// BUG: |origin| will be incorrect if |url| is an "about:blank" URL
-// BUG: |origin| will be incorrect if |url| came from a sandboxed frame.
+// BUG: `origin` will be incorrect if `url` is an "about:blank" URL
+// BUG: `origin` will be incorrect if `url` came from a sandboxed frame.
 ```
 
 ### Risky
@@ -116,14 +116,14 @@
 const GURL& url = ...;
 
 // WARNING: `url::Origin::Create(url)` can give unexpected results if:
-// 1) |url| is "about:blank", or "about:srcdoc"
+// 1) `url` is "about:blank", or "about:srcdoc"
 //    (returning unique, opaque origin rather than the real origin of the frame)
-// 2) |url| comes from a sandboxed frame
+// 2) `url` comes from a sandboxed frame
 //    (potentially returning a non-opaque origin, when an opaque one is needed)
-// 3) |base_url_for_data_url| should be used instead of |url|
+// 3) `base_url_for_data_url` should be used instead of `url`
 //
 // WARNING: `url::Origin::Create(url)` has some additional subtleties:
-// 4) if |url| is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
+// 4) if `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
 //    then the inner origin will be returned (unlike with `url::SchemeHostPort`)
 // 5) data: URLs will be correctly be translated into opaque origins, but the
 //    precursor origin will be lost (unlike with `url::Resolve`).
@@ -132,23 +132,23 @@
 // WARNING: `url::SchemeHostPort(url)` will *mechanically* extract the scheme,
 // host, and port of the URL, discarding other parts of the URL.  This may have
 // unexpected results when:
-// 1) |url| is "about:blank", or "about:srcdoc"
-// 2) |url| comes from a sandboxed frame, i.e. when an opaque origin is expected
-// 3) |url| is a data: URL, i.e. when an opaque origin is expected
-// 4) |url| is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
+// 1) `url` is "about:blank", or "about:srcdoc"
+// 2) `url` comes from a sandboxed frame, i.e. when an opaque origin is expected
+// 3) `url` is a data: URL, i.e. when an opaque origin is expected
+// 4) `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
 //    (the inner origin will *not* be returned - unlike `url::Origin::Create`)
 url::SchemeHostPort scheme_host_port = url::SchemeHostPort(url);
 
-// url::Origin::Resolve should work okay when:
-// 1) |url| is "about:blank", or "about:srcdoc"
-// 2) |url| comes from a sandboxed frame (i.e. when `base_origin` is opaque)
-// 3) |url| is a data: URL (i.e. propagating precursor of `base_origin`)
-// 4) |url| is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
+// `url::Origin::Resolve` should work okay when:
+// 1) `url` is "about:blank", or "about:srcdoc"
+// 2) `url` comes from a sandboxed frame (i.e. when `base_origin` is opaque)
+// 3) `url` is a data: URL (i.e. propagating precursor of `base_origin`)
+// 4) `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
 //
-// WARNING: It is simpler and more robust to just use GetLastCommittedOrigin
-// (instead of combining GetLastCommittedOrigin and GetLastCommittedURL using
-// url::Origin::Resolve).
-// WARNING: url::Origin::Resolve is unaware of `base_url_for_data_url`.
+// WARNING: It is simpler and more robust to just use `GetLastCommittedOrigin`
+// (instead of combining `GetLastCommittedOrigin` and `GetLastCommittedURL`
+// using `url::Origin::Resolve`).
+// WARNING: `url::Origin::Resolve` is unaware of `base_url_for_data_url`.
 const url::Origin& base_origin = ...
 url::Origin origin = url::Origin::Resolve(url, base_origin);
 ```
diff --git a/extensions/browser/api/async_api_function.cc b/extensions/browser/api/async_api_function.cc
index 5c05867..680d66fb 100644
--- a/extensions/browser/api/async_api_function.cc
+++ b/extensions/browser/api/async_api_function.cc
@@ -96,7 +96,12 @@
 void AsyncApiFunction::SendResponse(bool success) {
   ResponseValue response;
   if (success) {
-    response = ArgumentList(std::move(results_));
+    std::vector<base::Value> arguments;
+    if (results_) {
+      std::unique_ptr<base::ListValue> results = std::move(results_);
+      arguments = std::move(*results).TakeListDeprecated();
+    }
+    response = ArgumentList(std::move(arguments));
   } else if (results_) {
     std::unique_ptr<base::ListValue> results = std::move(results_);
     response =
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index cc5ac5c..49eefc9e 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -688,15 +688,6 @@
   return ResponseValue(new ArgumentListResponseValue(this, std::move(list)));
 }
 
-ExtensionFunction::ResponseValue ExtensionFunction::ArgumentList(
-    std::unique_ptr<base::ListValue> args) {
-  base::Value::List new_args;
-  if (args)
-    new_args = std::move(args->GetList());
-  return ResponseValue(
-      new ArgumentListResponseValue(this, std::move(new_args)));
-}
-
 ExtensionFunction::ResponseValue ExtensionFunction::Error(std::string error) {
   return ResponseValue(new ErrorResponseValue(this, std::move(error)));
 }
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 8686e15a..0e92b82 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -32,7 +32,6 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"
 
 namespace base {
-class ListValue;
 class Value;
 }
 
@@ -229,7 +228,7 @@
   // base::Value of type LIST.
   void SetArgs(base::Value args);
 
-  // Retrieves the results of the function as a ListValue.
+  // Retrieves the results of the function as a base::Value::List.
   const base::Value::List* GetResultList() const;
 
   // Retrieves any error string from the function.
@@ -380,14 +379,6 @@
   ResponseValue TwoArguments(base::Value arg1, base::Value arg2);
   // Success, a list of arguments |results| to pass to caller.
   ResponseValue ArgumentList(std::vector<base::Value> results);
-  // TODO(crbug.com/1139221): Deprecate this when Create() returns a base::Value
-  // instead of a std::unique_ptr<>.
-  //
-  // Success, a list of arguments |results| to pass to caller.
-  // - a std::unique_ptr<> for convenience, since callers usually get this from
-  //   the result of a Create(...) call on the generated Results struct. For
-  //   example, alarms::Get::Results::Create(alarm).
-  ResponseValue ArgumentList(std::unique_ptr<base::ListValue> results);
   // Error. chrome.runtime.lastError.message will be set to |error|.
   ResponseValue Error(std::string error);
   // Error with formatting. Args are processed using
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 5617a28..d5fdb2e97 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -983,7 +983,7 @@
   // remove live RenderFrameHosts here, as they could still need their
   // WebViewRendererState entry while in pending deletion state.  For those
   // cases, we rely on calling RemoveGuest() from RenderFrameDeleted().
-  if (!old_host->IsRenderFrameCreated()) {
+  if (!old_host->IsRenderFrameLive()) {
     WebViewRendererState::GetInstance()->RemoveGuest(
         old_host->GetProcess()->GetID(), old_host->GetRoutingID());
   }
diff --git a/infra/config/generated/builders/ci/mac-official/properties.json b/infra/config/generated/builders/ci/mac-official/properties.json
index 9acf9519c..87b58e30 100644
--- a/infra/config/generated/builders/ci/mac-official/properties.json
+++ b/infra/config/generated/builders/ci/mac-official/properties.json
@@ -23,7 +23,7 @@
                 "apply_configs": [
                   "checkout_pgo_profiles"
                 ],
-                "config": "chromium"
+                "config": "chromium_no_telemetry_dependencies"
               }
             }
           }
diff --git a/infra/config/generated/builders/try/mac-official/properties.json b/infra/config/generated/builders/try/mac-official/properties.json
index 046f5307..56df05c 100644
--- a/infra/config/generated/builders/try/mac-official/properties.json
+++ b/infra/config/generated/builders/try/mac-official/properties.json
@@ -23,7 +23,7 @@
                 "apply_configs": [
                   "checkout_pgo_profiles"
                 ],
-                "config": "chromium"
+                "config": "chromium_no_telemetry_dependencies"
               }
             }
           }
diff --git a/infra/config/subprojects/chromium/ci/chromium.star b/infra/config/subprojects/chromium/ci/chromium.star
index 15759d64..aa0dc72 100644
--- a/infra/config/subprojects/chromium/ci/chromium.star
+++ b/infra/config/subprojects/chromium/ci/chromium.star
@@ -473,7 +473,7 @@
     branch_selector = branches.DESKTOP_EXTENDED_STABLE_MILESTONE,
     builder_spec = builder_config.builder_spec(
         gclient_config = builder_config.gclient_config(
-            config = "chromium",
+            config = "chromium_no_telemetry_dependencies",
             apply_configs = [
                 "checkout_pgo_profiles",
             ],
diff --git a/ios/chrome/browser/follow/follow_tab_helper.mm b/ios/chrome/browser/follow/follow_tab_helper.mm
index 4ee195fc..fe64060 100644
--- a/ios/chrome/browser/follow/follow_tab_helper.mm
+++ b/ios/chrome/browser/follow/follow_tab_helper.mm
@@ -130,25 +130,32 @@
 }
 
 void FollowTabHelper::UpdateFollowMenuItem(FollowWebPageURLs* web_page_urls) {
-  BOOL status =
-      ios::GetChromeBrowserProvider().GetFollowProvider()->GetFollowStatus(
-          web_page_urls);
+  DCHECK(web_state_);
 
-  std::string domainName =
-      web::GetMainFrame(web_state_)->GetSecurityOrigin().host();
-  if (domainName.substr(0, kRemovablePrefix.length()) == kRemovablePrefix) {
-    domainName =
-        domainName.substr(kRemovablePrefix.length(), domainName.length());
+  web::WebFrame* web_frame = web::GetMainFrame(web_state_);
+  // Only update the follow menu item when web_page_urls is not null and when
+  // webFrame can be retrieved. Otherwise, leave the option disabled.
+  if (web_page_urls && web_frame) {
+    BOOL status =
+        ios::GetChromeBrowserProvider().GetFollowProvider()->GetFollowStatus(
+            web_page_urls);
+
+    std::string domainName = web_frame->GetSecurityOrigin().host();
+    if (domainName.substr(0, kRemovablePrefix.length()) == kRemovablePrefix) {
+      domainName =
+          domainName.substr(kRemovablePrefix.length(), domainName.length());
+    }
+
+    bool enabled = GetFollowActionState(web_state_) == FollowActionStateEnabled;
+
+    [follow_menu_updater_
+        updateFollowMenuItemWithFollowWebPageURLs:web_page_urls
+                                           status:status
+                                       domainName:base::SysUTF8ToNSString(
+                                                      domainName)
+                                          enabled:enabled];
   }
 
-  bool enabled = GetFollowActionState(web_state_) == FollowActionStateEnabled;
-
-  [follow_menu_updater_
-      updateFollowMenuItemWithFollowWebPageURLs:web_page_urls
-                                         status:status
-                                     domainName:base::SysUTF8ToNSString(
-                                                    domainName)
-                                        enabled:enabled];
   should_update_follow_item_ = false;
 }
 
diff --git a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
index 25da5797..4282b41b 100644
--- a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_egtest.mm
@@ -231,7 +231,8 @@
 #pragma mark - Tests
 
 // Tests the sign-in screen with accounts that are already available.
-- (void)testSignInScreenWithAccount {
+// TODO(crbug.com/1328822): flaky.
+- (void)DISABLED_testSignInScreenWithAccount {
   // Add an identity to sign-in to enable the "Continue as ..." button in the
   // sign-in screen.
   FakeChromeIdentity* fakeIdentity = [FakeChromeIdentity fakeIdentity1];
@@ -267,7 +268,8 @@
 
 // Tests the sign-in screen without accounts where an account has to be added
 // before signing in.
-- (void)testSignInScreenWithoutAccount {
+// TODO(crbug.com/1328822): flaky.
+- (void)DISABLED_testSignInScreenWithoutAccount {
   // Tap on the "Sign in" button.
   [[EarlGrey
       selectElementWithMatcher:grey_text(l10n_util::GetNSString(
@@ -752,7 +754,8 @@
 // Tests that intents are only handled when sign-in is done regardless of the
 // type of sign-in prompt (regular or forced). This test chains the regular
 // sign-in prompt and the forced sign-in prompt.
-- (void)testHandlingIntentWhenSigninAfterSkippingRegularPrompt {
+// TODO(crbug.com/1328822): flaky.
+- (void)DISABLED_testHandlingIntentWhenSigninAfterSkippingRegularPrompt {
   // Serve the test page locally using the internal embedded server.
   self.testServer->RegisterRequestHandler(
       base::BindRepeating(&PageHttpResponse));
diff --git a/media/formats/hls/media_playlist.cc b/media/formats/hls/media_playlist.cc
index 442df42..4e5e5284 100644
--- a/media/formats/hls/media_playlist.cc
+++ b/media/formats/hls/media_playlist.cc
@@ -56,6 +56,7 @@
   absl::optional<InfTag> inf_tag;
   absl::optional<XGapTag> gap_tag;
   absl::optional<XDiscontinuityTag> discontinuity_tag;
+  absl::optional<XByteRangeTag> byterange_tag;
   absl::optional<XPlaylistTypeTag> playlist_type_tag;
   absl::optional<XEndListTag> end_list_tag;
   absl::optional<XIFramesOnlyTag> i_frames_only_tag;
@@ -199,6 +200,15 @@
           discontinuity_sequence_number = discontinuity_sequence_tag->number;
           break;
         }
+        case MediaPlaylistTagName::kXByteRange: {
+          // TODO(https://crbug.com/1328528): Investigate supporting aspects of
+          // this tag not described by the spec
+          auto error = ParseUniqueTag(*tag, byterange_tag);
+          if (error.has_value()) {
+            return std::move(error).value();
+          }
+          break;
+        }
       }
 
       continue;
@@ -228,14 +238,43 @@
     const types::DecimalInteger media_sequence_number =
         (media_sequence_tag ? media_sequence_tag->number : 0) + segments.size();
 
+    absl::optional<types::ByteRange> byterange;
+    if (byterange_tag.has_value()) {
+      auto range = byterange_tag->range;
+
+      // If this media segment had an EXT-X-BYTERANGE tag without an offset, the
+      // previous media segment must have been a byterange of the same resource.
+      // In that case, the offset is that of the byte following the previous
+      // media segment.
+      types::DecimalInteger offset;
+      if (range.offset.has_value()) {
+        offset = range.offset.value();
+      } else if (segments.empty()) {
+        return ParseStatusCode::kByteRangeRequiresOffset;
+      } else if (!segments.back().GetByteRange().has_value()) {
+        return ParseStatusCode::kByteRangeRequiresOffset;
+      } else if (segments.back().GetUri() != segment_uri) {
+        return ParseStatusCode::kByteRangeRequiresOffset;
+      } else {
+        offset = segments.back().GetByteRange()->GetEnd();
+      }
+
+      byterange = types::ByteRange::Validate(range.length, offset);
+      if (!byterange) {
+        return ParseStatusCode::kByteRangeInvalid;
+      }
+    }
+
     segments.emplace_back(inf_tag->duration, media_sequence_number,
                           discontinuity_sequence_number, std::move(segment_uri),
-                          discontinuity_tag.has_value(), gap_tag.has_value());
+                          byterange, discontinuity_tag.has_value(),
+                          gap_tag.has_value());
 
     // Reset per-segment tags
     inf_tag.reset();
     gap_tag.reset();
     discontinuity_tag.reset();
+    byterange_tag.reset();
   }
 
   if (!target_duration_tag.has_value()) {
diff --git a/media/formats/hls/media_playlist_test_builder.h b/media/formats/hls/media_playlist_test_builder.h
index 245d228..e1cf4320 100644
--- a/media/formats/hls/media_playlist_test_builder.h
+++ b/media/formats/hls/media_playlist_test_builder.h
@@ -12,6 +12,8 @@
 #include "media/formats/hls/media_playlist.h"
 #include "media/formats/hls/media_segment.h"
 #include "media/formats/hls/playlist_test_builder.h"
+#include "media/formats/hls/types.h"
+#include "url/gurl.h"
 
 namespace media::hls {
 
@@ -135,6 +137,22 @@
   EXPECT_EQ(segment.GetUri(), uri) << from.ToString();
 }
 
+// Checks that the latest media segment has the given byte range.
+inline void HasByteRange(absl::optional<types::ByteRange> range,
+                         const base::Location& from,
+                         const MediaSegment& segment) {
+  ASSERT_EQ(segment.GetByteRange().has_value(), range.has_value())
+      << from.ToString();
+  if (range.has_value()) {
+    EXPECT_EQ(segment.GetByteRange()->GetOffset(), range->GetOffset())
+        << from.ToString();
+    EXPECT_EQ(segment.GetByteRange()->GetLength(), range->GetLength())
+        << from.ToString();
+    EXPECT_EQ(segment.GetByteRange()->GetEnd(), range->GetEnd())
+        << from.ToString();
+  }
+}
+
 // Checks the latest media segment's `HasDiscontinuity` property against the
 // given value.
 inline void HasDiscontinuity(bool value,
diff --git a/media/formats/hls/media_playlist_unittest.cc b/media/formats/hls/media_playlist_unittest.cc
index 774427b..f327dabd 100644
--- a/media/formats/hls/media_playlist_unittest.cc
+++ b/media/formats/hls/media_playlist_unittest.cc
@@ -13,6 +13,7 @@
 #include "media/formats/hls/multivariant_playlist.h"
 #include "media/formats/hls/parse_status.h"
 #include "media/formats/hls/tags.h"
+#include "media/formats/hls/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -747,4 +748,207 @@
   fork.ExpectOk();
 }
 
+TEST(HlsMediaPlaylistTest, XByteRangeTag) {
+  MediaPlaylistTestBuilder builder;
+  builder.AppendLine("#EXTM3U");
+  builder.AppendLine("#EXT-X-TARGETDURATION:10");
+
+  // EXT-X-BYTERANGE content must be a valid ByteRange
+  {
+    for (base::StringPiece x :
+         {"", ":", ": 12@34", ":12@34 ", ":12@", ":12@{$offset}"}) {
+      auto fork = builder;
+      fork.AppendLine("#EXT-X-BYTERANGE", x);
+      fork.AppendLine("#EXTINF:9.2,\t");
+      fork.AppendLine("segment.ts");
+      fork.ExpectError(ParseStatusCode::kMalformedTag);
+    }
+  }
+  // EXT-X-BYTERANGE may not appear twice per-segment.
+  // TODO(https://crbug.com/1328528): Some players support this, using only the
+  // final occurrence.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXT-X-BYTERANGE:34@56");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectError(ParseStatusCode::kPlaylistHasDuplicateTags);
+  }
+  // Offset is required if this is the first media segment.
+  // TODO(https://crbug.com/1328528): Some players support this, default offset
+  // to 0.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeRequiresOffset);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasByteRange, CreateByteRange(12, 34));
+    fork.ExpectOk();
+  }
+  // Offset is required if the previous media segment is not a byterange.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.AppendLine("#EXT-X-BYTERANGE:12");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeRequiresOffset);
+
+    fork = builder;
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment.ts"));
+    fork.ExpectSegment(HasByteRange, absl::nullopt);
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(12, 34));
+    fork.ExpectOk();
+  }
+  // Offset is required if the previous media segment is a byterange of a
+  // different resource.
+  // TODO(https://crbug.com/1328528): Some players support this.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.AppendLine("#EXT-X-BYTERANGE:56");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment2.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeRequiresOffset);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(12, 34));
+    fork.AppendLine("#EXT-X-BYTERANGE:56@78");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment2.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment2.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(56, 78));
+    fork.ExpectOk();
+  }
+  // Offset is required even if a prior segment is a byterange of the same
+  // resource, but not the immediately previous segment.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment2.ts");
+    fork.AppendLine("#EXT-X-BYTERANGE:45");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeRequiresOffset);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(12, 34));
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment2.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment2.ts"));
+    fork.ExpectSegment(HasByteRange, absl::nullopt);
+    fork.AppendLine("#EXT-X-BYTERANGE:56@78");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(56, 78));
+    fork.ExpectOk();
+  }
+  // Offset can be elided if the previous segment is a byterange of the same
+  // resource.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:12@34");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(12, 34));
+    fork.AppendLine("#EXT-X-BYTERANGE:56");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(56, 46));
+
+    // If an explicit offset is given (even it it's eligible to be elided), it
+    // must be used.
+    fork.AppendLine("#EXT-X-BYTERANGE:78@99999");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasUri, GURL("http://localhost/segment1.ts"));
+    fork.ExpectSegment(HasByteRange, CreateByteRange(78, 99999));
+    fork.ExpectOk();
+  }
+  // Range given by tag may not be empty or overflow a uint64, even across
+  // segments.
+  {
+    auto fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:0@0");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeInvalid);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:18446744073709551615@1");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeInvalid);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:1@18446744073709551615");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeInvalid);
+
+    fork = builder;
+    fork.AppendLine(
+        "#EXT-X-BYTERANGE:18446744073709551615@18446744073709551615");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeInvalid);
+
+    fork = builder;
+    fork.AppendLine("#EXT-X-BYTERANGE:1@18446744073709551614");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectAdditionalSegment();
+    fork.ExpectSegment(HasByteRange, CreateByteRange(1, 18446744073709551614u));
+    fork.ExpectOk();
+
+    // Since the previous segment ends at uint64_t::max, an additional
+    // contiguous byterange would overflow.
+    fork.AppendLine("#EXT-X-BYTERANGE:1");
+    fork.AppendLine("#EXTINF:9.2,\t");
+    fork.AppendLine("segment1.ts");
+    fork.ExpectError(ParseStatusCode::kByteRangeInvalid);
+  }
+}
+
 }  // namespace media::hls
diff --git a/media/formats/hls/media_segment.cc b/media/formats/hls/media_segment.cc
index 9aa8416..5e81aa3 100644
--- a/media/formats/hls/media_segment.cc
+++ b/media/formats/hls/media_segment.cc
@@ -13,12 +13,14 @@
                            types::DecimalInteger media_sequence_number,
                            types::DecimalInteger discontinuity_sequence_number,
                            GURL uri,
+                           absl::optional<types::ByteRange> byte_range,
                            bool has_discontinuity,
                            bool is_gap)
     : duration_(duration),
       media_sequence_number_(media_sequence_number),
       discontinuity_sequence_number_(discontinuity_sequence_number),
       uri_(std::move(uri)),
+      byte_range_(byte_range),
       has_discontinuity_(has_discontinuity),
       is_gap_(is_gap) {}
 MediaSegment::~MediaSegment() = default;
diff --git a/media/formats/hls/media_segment.h b/media/formats/hls/media_segment.h
index b97815fe..21a4720 100644
--- a/media/formats/hls/media_segment.h
+++ b/media/formats/hls/media_segment.h
@@ -17,6 +17,7 @@
                types::DecimalInteger media_sequence_number,
                types::DecimalInteger discontinuity_sequence_number,
                GURL uri,
+               absl::optional<types::ByteRange> byte_range,
                bool has_discontinuity,
                bool is_gap);
   ~MediaSegment();
@@ -43,6 +44,10 @@
   // `gap` is true, in which case this URI should not be used.
   const GURL& GetUri() const { return uri_; }
 
+  // If this media segment is a subrange of its resource, this indicates the
+  // range.
+  absl::optional<types::ByteRange> GetByteRange() const { return byte_range_; }
+
   // Whether there is a decoding discontinuity between the previous media
   // segment and this one.
   bool HasDiscontinuity() const { return has_discontinuity_; }
@@ -56,6 +61,7 @@
   types::DecimalInteger media_sequence_number_;
   types::DecimalInteger discontinuity_sequence_number_;
   GURL uri_;
+  absl::optional<types::ByteRange> byte_range_;
   bool has_discontinuity_;
   bool is_gap_;
 };
diff --git a/media/formats/hls/parse_status.cc b/media/formats/hls/parse_status.cc
index 8a56774..9c5ee9d8 100644
--- a/media/formats/hls/parse_status.cc
+++ b/media/formats/hls/parse_status.cc
@@ -47,6 +47,8 @@
     PARSE_STATUS_CODE_CASE(kMediaSegmentBeforeMediaSequenceTag);
     PARSE_STATUS_CODE_CASE(kMediaSegmentBeforeDiscontinuitySequenceTag);
     PARSE_STATUS_CODE_CASE(kDiscontinuityTagBeforeDiscontinuitySequenceTag);
+    PARSE_STATUS_CODE_CASE(kByteRangeRequiresOffset);
+    PARSE_STATUS_CODE_CASE(kByteRangeInvalid);
   }
 
   NOTREACHED();
diff --git a/media/formats/hls/parse_status.h b/media/formats/hls/parse_status.h
index 99d602b..a1fcc12 100644
--- a/media/formats/hls/parse_status.h
+++ b/media/formats/hls/parse_status.h
@@ -44,6 +44,8 @@
   kMediaSegmentBeforeMediaSequenceTag,
   kMediaSegmentBeforeDiscontinuitySequenceTag,
   kDiscontinuityTagBeforeDiscontinuitySequenceTag,
+  kByteRangeRequiresOffset,
+  kByteRangeInvalid,
 };
 
 struct ParseStatusTraits {
diff --git a/media/formats/hls/tag_name.cc b/media/formats/hls/tag_name.cc
index fb4283c..65ede55 100644
--- a/media/formats/hls/tag_name.cc
+++ b/media/formats/hls/tag_name.cc
@@ -50,6 +50,7 @@
 // Mapping of tag names to their constants. This must remain sorted by the
 // string value.
 constexpr auto kTagNames = base::MakeFixedFlatMap({
+    TagNameEntry("EXT-X-BYTERANGE", MediaPlaylistTagName::kXByteRange),
     TagNameEntry("EXT-X-CONTENT-STEERING",
                  MultivariantPlaylistTagName::kXContentSteering),
     TagNameEntry("EXT-X-DEFINE", CommonTagName::kXDefine),
diff --git a/media/formats/hls/tag_name.h b/media/formats/hls/tag_name.h
index a89fee3d..884d36b5 100644
--- a/media/formats/hls/tag_name.h
+++ b/media/formats/hls/tag_name.h
@@ -59,7 +59,8 @@
   kXPlaylistType,
   kXMediaSequence,
   kXDiscontinuitySequence,
-  kMaxValue = kXDiscontinuitySequence,
+  kXByteRange,
+  kMaxValue = kXByteRange,
 };
 
 constexpr TagKind GetTagKind(CommonTagName) {
diff --git a/media/formats/hls/tags.cc b/media/formats/hls/tags.cc
index 67b05c7a..db5be0b 100644
--- a/media/formats/hls/tags.cc
+++ b/media/formats/hls/tags.cc
@@ -454,4 +454,19 @@
   return ParseDecimalIntegerTag(tag, &XDiscontinuitySequenceTag::number);
 }
 
+ParseStatus::Or<XByteRangeTag> XByteRangeTag::Parse(TagItem tag) {
+  DCHECK(tag.GetName() == ToTagName(XByteRangeTag::kName));
+  if (!tag.GetContent().has_value()) {
+    return ParseStatusCode::kMalformedTag;
+  }
+
+  auto range = types::ByteRangeExpression::Parse(*tag.GetContent());
+  if (range.has_error()) {
+    return ParseStatus(ParseStatusCode::kMalformedTag)
+        .AddCause(std::move(range).error());
+  }
+
+  return XByteRangeTag{.range = std::move(range).value()};
+}
+
 }  // namespace media::hls
diff --git a/media/formats/hls/tags.h b/media/formats/hls/tags.h
index 44ec810..06dc612 100644
--- a/media/formats/hls/tags.h
+++ b/media/formats/hls/tags.h
@@ -189,6 +189,14 @@
   types::DecimalInteger number;
 };
 
+// Represents the contents of the #EXT-X-BYTERANGE tag.
+struct MEDIA_EXPORT XByteRangeTag {
+  static constexpr auto kName = MediaPlaylistTagName::kXByteRange;
+  static ParseStatus::Or<XByteRangeTag> Parse(TagItem);
+
+  types::ByteRangeExpression range;
+};
+
 }  // namespace media::hls
 
 #endif  // MEDIA_FORMATS_HLS_TAGS_H_
diff --git a/media/formats/hls/tags_unittest.cc b/media/formats/hls/tags_unittest.cc
index 3eebae59..17d9b41 100644
--- a/media/formats/hls/tags_unittest.cc
+++ b/media/formats/hls/tags_unittest.cc
@@ -475,4 +475,24 @@
   RunDecimalIntegerTagTest(&XDiscontinuitySequenceTag::number);
 }
 
+TEST(HlsTagsTest, ParseXByteRangeTag) {
+  RunTagIdenficationTest<XByteRangeTag>("#EXT-X-BYTERANGE:12@34\n", "12@34");
+
+  auto tag = OkTest<XByteRangeTag>("12");
+  EXPECT_EQ(tag.range.length, 12u);
+  EXPECT_EQ(tag.range.offset, absl::nullopt);
+  tag = OkTest<XByteRangeTag>("12@34");
+  EXPECT_EQ(tag.range.length, 12u);
+  EXPECT_EQ(tag.range.offset, 34u);
+
+  ErrorTest<XByteRangeTag>("FOOBAR", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>("12@", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>("@34", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>("@", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>(" 12@34", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>("12@34 ", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>("", ParseStatusCode::kMalformedTag);
+  ErrorTest<XByteRangeTag>(absl::nullopt, ParseStatusCode::kMalformedTag);
+}
+
 }  // namespace media::hls
diff --git a/media/formats/hls/test_util.h b/media/formats/hls/test_util.h
index 2b342ab..fdc5506 100644
--- a/media/formats/hls/test_util.h
+++ b/media/formats/hls/test_util.h
@@ -16,6 +16,11 @@
       .value();
 }
 
+inline types::ByteRange CreateByteRange(types::DecimalInteger length,
+                                        types::DecimalInteger offset) {
+  return types::ByteRange::Validate(length, offset).value();
+}
+
 }  // namespace media::hls
 
 #endif
diff --git a/media/formats/hls/types.cc b/media/formats/hls/types.cc
index c28c5973..264f44d 100644
--- a/media/formats/hls/types.cc
+++ b/media/formats/hls/types.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <cmath>
+#include <limits>
 
 #include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
@@ -227,7 +228,8 @@
                            .height = std::move(height).value()};
 }
 
-ParseStatus::Or<ByteRange> ByteRange::Parse(SourceString source_str) {
+ParseStatus::Or<ByteRangeExpression> ByteRangeExpression::Parse(
+    SourceString source_str) {
   // If this ByteRange has an offset, it will be separated from the length by
   // '@'.
   const auto at_index = source_str.Str().find_first_of('@');
@@ -251,7 +253,22 @@
     offset = std::move(offset_result).value();
   }
 
-  return ByteRange{.length = std::move(length).value(), .offset = offset};
+  return ByteRangeExpression{.length = std::move(length).value(),
+                             .offset = offset};
+}
+
+absl::optional<ByteRange> ByteRange::Validate(DecimalInteger length,
+                                              DecimalInteger offset) {
+  if (length == 0) {
+    return absl::nullopt;
+  }
+
+  // Ensure that `length+offset` won't overflow `DecimalInteger`
+  if (std::numeric_limits<DecimalInteger>::max() - offset < length) {
+    return absl::nullopt;
+  }
+
+  return ByteRange(length, offset);
 }
 
 ParseStatus::Or<base::StringPiece> ParseQuotedString(
diff --git a/media/formats/hls/types.h b/media/formats/hls/types.h
index 95e4c12..22f08ead 100644
--- a/media/formats/hls/types.h
+++ b/media/formats/hls/types.h
@@ -45,11 +45,11 @@
   types::DecimalInteger height;
 };
 
-// A `ByteRange` describes a sub-range of a resource. There are a couple tags
-// that use this type, and they all have the format `length[@offset]`.
+// A `ByteRangeExpression` represents the 'length[@offset]' syntax that appears
+// in tags describing byte ranges of a resource.
 // https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.4.2
-struct MEDIA_EXPORT ByteRange {
-  static ParseStatus::Or<ByteRange> Parse(SourceString source_str);
+struct MEDIA_EXPORT ByteRangeExpression {
+  static ParseStatus::Or<ByteRangeExpression> Parse(SourceString source_str);
 
   // The length of the sub-range, in bytes.
   types::DecimalInteger length;
@@ -61,6 +61,30 @@
   absl::optional<types::DecimalInteger> offset;
 };
 
+// This is similar to `ByteRangeExpression`, but with a stronger contract:
+// - `length` is non-zero
+// - `offset` is non-optional
+// - `offset+length` may not overflow `types::DecimalInteger`
+class MEDIA_EXPORT ByteRange {
+ public:
+  // Validates that the range given by `[offset,offset+length)` is non-empty and
+  // that `GetEnd()` would not exceed the max value representable by a
+  // `DecimalInteger`.
+  static absl::optional<ByteRange> Validate(DecimalInteger length,
+                                            DecimalInteger offset);
+
+  DecimalInteger GetLength() const { return length_; }
+  DecimalInteger GetOffset() const { return offset_; }
+  DecimalInteger GetEnd() const { return offset_ + length_; }
+
+ private:
+  ByteRange(DecimalInteger length, DecimalInteger offset)
+      : length_(length), offset_(offset) {}
+
+  DecimalInteger length_;
+  DecimalInteger offset_;
+};
+
 // Parses a string surrounded by double-quotes ("), returning the inner string.
 // These appear in the context of attribute-lists, and are subject to variable
 // substitution. `sub_buffer` must outlive the returned string.
diff --git a/media/formats/hls/types_unittest.cc b/media/formats/hls/types_unittest.cc
index 1dd5602..1b482cdd 100644
--- a/media/formats/hls/types_unittest.cc
+++ b/media/formats/hls/types_unittest.cc
@@ -638,27 +638,27 @@
   error_test("18446744073709551616x18446744073709551616");
 }
 
-TEST(HlsTypesTest, ParseByteRange) {
+TEST(HlsTypesTest, ParseByteRangeExpression) {
   const auto error_test = [](base::StringPiece input,
                              const base::Location& from =
                                  base::Location::Current()) {
-    auto result =
-        types::ByteRange::Parse(SourceString::CreateForTesting(input));
+    auto result = types::ByteRangeExpression::Parse(
+        SourceString::CreateForTesting(input));
     ASSERT_TRUE(result.has_error());
     auto error = std::move(result).error();
     EXPECT_EQ(error.code(), ParseStatusCode::kFailedToParseByteRange)
         << from.ToString();
   };
-  const auto ok_test = [](base::StringPiece input, types::ByteRange expected,
-                          const base::Location& from =
-                              base::Location::Current()) {
-    auto result =
-        types::ByteRange::Parse(SourceString::CreateForTesting(input));
-    ASSERT_TRUE(result.has_value());
-    auto value = std::move(result).value();
-    EXPECT_EQ(value.length, expected.length);
-    EXPECT_EQ(value.offset, expected.offset);
-  };
+  const auto ok_test =
+      [](base::StringPiece input, types::ByteRangeExpression expected,
+         const base::Location& from = base::Location::Current()) {
+        auto result = types::ByteRangeExpression::Parse(
+            SourceString::CreateForTesting(input));
+        ASSERT_TRUE(result.has_value());
+        auto value = std::move(result).value();
+        EXPECT_EQ(value.length, expected.length);
+        EXPECT_EQ(value.offset, expected.offset);
+      };
 
   // Empty string is not allowed
   error_test("");
@@ -689,26 +689,65 @@
   error_test("\"12@34\"");
 
   // Test some valid inputs
-  ok_test("0", types::ByteRange{.length = 0, .offset = absl::nullopt});
-  ok_test("12", types::ByteRange{.length = 12, .offset = absl::nullopt});
-  ok_test("12@0", types::ByteRange{.length = 12, .offset = 0});
-  ok_test("12@34", types::ByteRange{.length = 12, .offset = 34});
-  ok_test("0@34", types::ByteRange{.length = 0, .offset = 34});
-  ok_test("0@0", types::ByteRange{.length = 0, .offset = 0});
+  ok_test("0",
+          types::ByteRangeExpression{.length = 0, .offset = absl::nullopt});
+  ok_test("12",
+          types::ByteRangeExpression{.length = 12, .offset = absl::nullopt});
+  ok_test("12@0", types::ByteRangeExpression{.length = 12, .offset = 0});
+  ok_test("12@34", types::ByteRangeExpression{.length = 12, .offset = 34});
+  ok_test("0@34", types::ByteRangeExpression{.length = 0, .offset = 34});
+  ok_test("0@0", types::ByteRangeExpression{.length = 0, .offset = 0});
 
-  // Test max supported values
-  ok_test("18446744073709551615@0",
-          types::ByteRange{.length = 18446744073709551615u, .offset = 0});
+  // Test max supported values. These are valid ByteRangeExpressions, but not
+  // necessarily valid ByteRanges.
+  ok_test(
+      "18446744073709551615@0",
+      types::ByteRangeExpression{.length = 18446744073709551615u, .offset = 0});
   error_test("18446744073709551616@0");
-  ok_test("0@18446744073709551615",
-          types::ByteRange{.length = 0, .offset = 18446744073709551615u});
+  ok_test(
+      "0@18446744073709551615",
+      types::ByteRangeExpression{.length = 0, .offset = 18446744073709551615u});
   error_test("0@18446744073709551616");
   ok_test("18446744073709551615@18446744073709551615",
-          types::ByteRange{.length = 18446744073709551615u,
-                           .offset = 18446744073709551615u});
+          types::ByteRangeExpression{.length = 18446744073709551615u,
+                                     .offset = 18446744073709551615u});
   error_test("18446744073709551616@18446744073709551615");
   error_test("18446744073709551615@18446744073709551616");
   error_test("18446744073709551616@18446744073709551616");
 }
 
+TEST(HlsTypesTest, ValidateByteRange) {
+  // Any non-empty range where `ByteRange::GetEnd()` doesn't overflow
+  // `DecimalInteger` is valid.
+  constexpr auto ok_test =
+      [](types::DecimalInteger length, types::DecimalInteger offset,
+         const base::Location& from = base::Location::Current()) {
+        const auto result = types::ByteRange::Validate(length, offset);
+        EXPECT_TRUE(result.has_value()) << from.ToString();
+      };
+  constexpr auto error_test =
+      [](types::DecimalInteger length, types::DecimalInteger offset,
+         const base::Location& from = base::Location::Current()) {
+        const auto result = types::ByteRange::Validate(length, offset);
+        EXPECT_FALSE(result.has_value()) << from.ToString();
+      };
+
+  ok_test(1, 1);
+  ok_test(1, 0);
+
+  // Empty range is not allowed
+  error_test(0, 0);
+  error_test(0, 1);
+  error_test(0, 18446744073709551615u);
+
+  // Overflowing range is not allowed
+  ok_test(18446744073709551615u, 0);
+  error_test(18446744073709551615u, 1);
+  error_test(1, 18446744073709551615u);
+  error_test(18446744073709551615u, 18446744073709551615u);
+  error_test(9223372036854775808u, 9223372036854775808u);
+  ok_test(9223372036854775808u, 9223372036854775807u);
+  ok_test(9223372036854775807u, 9223372036854775808u);
+}
+
 }  // namespace media::hls
diff --git a/media/gpu/android/android_video_encode_accelerator.cc b/media/gpu/android/android_video_encode_accelerator.cc
index 80c152e..7a1890b 100644
--- a/media/gpu/android/android_video_encode_accelerator.cc
+++ b/media/gpu/android/android_video_encode_accelerator.cc
@@ -135,6 +135,7 @@
     profile.max_resolution.SetSize(kMaxEncodeFrameWidth, kMaxEncodeFrameHeight);
     profile.max_framerate_numerator = kMaxFramerateNumerator;
     profile.max_framerate_denominator = kMaxFramerateDenominator;
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     profiles.push_back(profile);
   }
   return profiles;
diff --git a/media/gpu/android/ndk_video_encode_accelerator.cc b/media/gpu/android/ndk_video_encode_accelerator.cc
index 991cede..b945f45 100644
--- a/media/gpu/android/ndk_video_encode_accelerator.cc
+++ b/media/gpu/android/ndk_video_encode_accelerator.cc
@@ -186,6 +186,9 @@
   supported_profile.max_resolution.SetSize(1920, 1080);
   supported_profile.max_framerate_numerator = 30;
   supported_profile.max_framerate_denominator = 1;
+  supported_profile.rate_control_modes =
+      media::VideoEncodeAccelerator::kConstantMode |
+      media::VideoEncodeAccelerator::kVariableMode;
 
   for (auto profile : {H264PROFILE_BASELINE, VP8PROFILE_ANY}) {
     if (!IsThereGoodMediaCodecFor(VideoCodecProfileToVideoCodec(profile)))
diff --git a/media/gpu/gpu_video_accelerator_util.cc b/media/gpu/gpu_video_accelerator_util.cc
index 284ea1e..eee356b 100644
--- a/media/gpu/gpu_video_accelerator_util.cc
+++ b/media/gpu/gpu_video_accelerator_util.cc
@@ -137,6 +137,8 @@
     profile.max_resolution = gpu_profile.max_resolution;
     profile.max_framerate_numerator = gpu_profile.max_framerate_numerator;
     profile.max_framerate_denominator = gpu_profile.max_framerate_denominator;
+    // If VBR is supported in the future, remove this hard-coding of CBR.
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     profiles.push_back(profile);
   }
   return profiles;
diff --git a/media/gpu/mac/vt_video_encode_accelerator_mac.cc b/media/gpu/mac/vt_video_encode_accelerator_mac.cc
index 0b622f1..965e398 100644
--- a/media/gpu/mac/vt_video_encode_accelerator_mac.cc
+++ b/media/gpu/mac/vt_video_encode_accelerator_mac.cc
@@ -19,6 +19,7 @@
 #include "media/base/mac/video_frame_mac.h"
 #include "media/base/media_log.h"
 #include "media/base/video_frame.h"
+#include "media/video/video_encode_accelerator.h"
 
 // This is a min version of macOS where we want to support SVC encoding via
 // EnableLowLatencyRateControl flag. The flag is actually supported since 11.3,
@@ -149,6 +150,8 @@
   SupportedProfile profile;
   profile.max_framerate_numerator = kMaxFrameRateNumerator;
   profile.max_framerate_denominator = kMaxFrameRateDenominator;
+  profile.rate_control_modes = VideoEncodeAccelerator::kConstantMode |
+                               VideoEncodeAccelerator::kVariableMode;
   profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
   if (__builtin_available(macOS LOW_LATENCY_FLAG_AVAILABLE_VER, *))
     profile.scalability_modes.push_back(SVCScalabilityMode::kL1T2);
@@ -169,6 +172,8 @@
   SupportedProfile profile;
   profile.max_framerate_numerator = kMaxFrameRateNumerator;
   profile.max_framerate_denominator = kMaxFrameRateDenominator;
+  profile.rate_control_modes = VideoEncodeAccelerator::kConstantMode |
+                               VideoEncodeAccelerator::kVariableMode;
   profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
   for (const auto& supported_profile : kSupportedProfiles) {
     profile.profile = supported_profile;
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
index de2800fd..241b328 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
@@ -2060,6 +2060,8 @@
     VideoEncodeAccelerator::SupportedProfile profile;
     profile.max_framerate_numerator = 30;
     profile.max_framerate_denominator = 1;
+    // TODO(b/182240945): remove hard-coding when VBR is supported
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     gfx::Size min_resolution;
     GetSupportedResolution(pixelformat, &min_resolution,
                            &profile.max_resolution);
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index a9126a6..1e08463b 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -1551,6 +1551,8 @@
     constexpr int kMaxEncoderFramerate = 30;
     profile.max_framerate_numerator = kMaxEncoderFramerate;
     profile.max_framerate_denominator = 1;
+    // TODO(b/193680666): remove hard-coding when VBR is supported
+    profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
     profile.scalability_modes =
         GetSupportedScalabilityModes(media_profile, va_profile);
     profiles.push_back(profile);
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index e5fddbb..890b86c9 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -47,6 +47,9 @@
 namespace {
 const uint32_t kDefaultGOPLength = 3000;
 const uint32_t kDefaultTargetBitrate = 5000000u;
+const VideoEncodeAccelerator::SupportedRateControlMode kSupportedProfileModes =
+    VideoEncodeAccelerator::kConstantMode |
+    VideoEncodeAccelerator::kVariableMode;
 const size_t kMaxFrameRateNumerator = 30;
 const size_t kMaxFrameRateDenominator = 1;
 const size_t kMaxResolutionWidth = 1920;
@@ -321,6 +324,7 @@
   // fallback as well.
   profile.max_framerate_numerator = kMaxFrameRateNumerator;
   profile.max_framerate_denominator = kMaxFrameRateDenominator;
+  profile.rate_control_modes = kSupportedProfileModes;
   profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
   if (svc_supported) {
     profile.scalability_modes.push_back(SVCScalabilityMode::kL1T2);
diff --git a/media/media_options.gni b/media/media_options.gni
index 13c374b8..b57e768 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -81,10 +81,10 @@
 
   # Enable inclusion of the HEVC/H265 parser and also enable HEVC/H265 decoding
   # with hardware acceleration assist. Enabled by default for fuzzer builds,
-  # ChromeOS builds with protected content support and Windows.
+  # ChromeOS builds with protected content support, Windows and Mac.
   enable_hevc_parser_and_hw_decoder =
       proprietary_codecs &&
-      (use_fuzzing_engine || use_chromeos_protected_media || is_win)
+      (use_fuzzing_engine || use_chromeos_protected_media || is_win || is_mac)
 }
 
 # Use another declare_args() to allow dependence on
diff --git a/media/mojo/mojom/video_encode_accelerator.mojom b/media/mojo/mojom/video_encode_accelerator.mojom
index b76407a..9e720fdf 100644
--- a/media/mojo/mojom/video_encode_accelerator.mojom
+++ b/media/mojo/mojom/video_encode_accelerator.mojom
@@ -36,12 +36,19 @@
 // of these messages are acknowledged.
 
 
+enum VideoEncodeAcceleratorSupportedRateControlMode {
+  kNoMode,
+  kConstantMode,
+  kVariableMode
+};
+
 struct VideoEncodeAcceleratorSupportedProfile {
   VideoCodecProfile profile;
   gfx.mojom.Size min_resolution;
   gfx.mojom.Size max_resolution;
   uint32 max_framerate_numerator;
   uint32 max_framerate_denominator;
+  array<VideoEncodeAcceleratorSupportedRateControlMode> rate_control_modes;
   array<SVCScalabilityMode> scalability_modes;
 };
 
diff --git a/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc b/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc
index 14dfad5..0a098ea 100644
--- a/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc
+++ b/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc
@@ -7,12 +7,56 @@
 #include "base/notreached.h"
 #include "media/base/video_bitrate_allocation.h"
 #include "media/mojo/mojom/video_encode_accelerator.mojom.h"
+#include "media/video/video_encode_accelerator.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace mojo {
 
 // static
+media::mojom::VideoEncodeAcceleratorSupportedRateControlMode
+EnumTraits<media::mojom::VideoEncodeAcceleratorSupportedRateControlMode,
+           media::VideoEncodeAccelerator::SupportedRateControlMode>::
+    ToMojom(media::VideoEncodeAccelerator::SupportedRateControlMode mode) {
+  switch (mode) {
+    case media::VideoEncodeAccelerator::kNoMode:
+      return media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+          kNoMode;
+    case media::VideoEncodeAccelerator::kConstantMode:
+      return media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+          kConstantMode;
+    case media::VideoEncodeAccelerator::kVariableMode:
+      return media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+          kVariableMode;
+  }
+  NOTREACHED();
+  return media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+      kConstantMode;
+}
+
+// static
+bool EnumTraits<media::mojom::VideoEncodeAcceleratorSupportedRateControlMode,
+                media::VideoEncodeAccelerator::SupportedRateControlMode>::
+    FromMojom(media::mojom::VideoEncodeAcceleratorSupportedRateControlMode mode,
+              media::VideoEncodeAccelerator::SupportedRateControlMode* out) {
+  switch (mode) {
+    case media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::kNoMode:
+      *out = media::VideoEncodeAccelerator::kNoMode;
+      return true;
+    case media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+        kConstantMode:
+      *out = media::VideoEncodeAccelerator::kConstantMode;
+      return true;
+    case media::mojom::VideoEncodeAcceleratorSupportedRateControlMode::
+        kVariableMode:
+      *out = media::VideoEncodeAccelerator::kVariableMode;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+// static
 bool StructTraits<media::mojom::VideoEncodeAcceleratorSupportedProfileDataView,
                   media::VideoEncodeAccelerator::SupportedProfile>::
     Read(media::mojom::VideoEncodeAcceleratorSupportedProfileDataView data,
@@ -25,6 +69,13 @@
 
   out->max_framerate_numerator = data.max_framerate_numerator();
   out->max_framerate_denominator = data.max_framerate_denominator();
+  out->rate_control_modes = media::VideoEncodeAccelerator::kNoMode;
+  std::vector<media::VideoEncodeAccelerator::SupportedRateControlMode> modes;
+  if (!data.ReadRateControlModes(&modes))
+    return false;
+  for (const auto& mode : modes) {
+    out->rate_control_modes |= mode;
+  }
 
   std::vector<media::SVCScalabilityMode> scalability_modes;
   if (!data.ReadScalabilityModes(&scalability_modes))
diff --git a/media/mojo/mojom/video_encode_accelerator_mojom_traits.h b/media/mojo/mojom/video_encode_accelerator_mojom_traits.h
index 7430b716..2a8d33c8 100644
--- a/media/mojo/mojom/video_encode_accelerator_mojom_traits.h
+++ b/media/mojo/mojom/video_encode_accelerator_mojom_traits.h
@@ -18,6 +18,17 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<media::mojom::VideoEncodeAcceleratorSupportedRateControlMode,
+                  media::VideoEncodeAccelerator::SupportedRateControlMode> {
+  static media::mojom::VideoEncodeAcceleratorSupportedRateControlMode ToMojom(
+      media::VideoEncodeAccelerator::SupportedRateControlMode mode);
+
+  static bool FromMojom(
+      media::mojom::VideoEncodeAcceleratorSupportedRateControlMode input,
+      media::VideoEncodeAccelerator::SupportedRateControlMode* out);
+};
+
+template <>
 struct StructTraits<
     media::mojom::VideoEncodeAcceleratorSupportedProfileDataView,
     media::VideoEncodeAccelerator::SupportedProfile> {
@@ -46,6 +57,22 @@
     return profile.max_framerate_denominator;
   }
 
+  static std::vector<media::VideoEncodeAccelerator::SupportedRateControlMode>
+  rate_control_modes(
+      const media::VideoEncodeAccelerator::SupportedProfile& profile) {
+    std::vector<media::VideoEncodeAccelerator::SupportedRateControlMode> modes;
+    if (profile.rate_control_modes &
+        media::VideoEncodeAccelerator::kConstantMode) {
+      modes.push_back(media::VideoEncodeAccelerator::kConstantMode);
+    }
+    if (profile.rate_control_modes &
+        media::VideoEncodeAccelerator::kVariableMode) {
+      modes.push_back(media::VideoEncodeAccelerator::kVariableMode);
+    }
+
+    return modes;
+  }
+
   static const std::vector<media::SVCScalabilityMode>& scalability_modes(
       const media::VideoEncodeAccelerator::SupportedProfile& profile) {
     return profile.scalability_modes;
diff --git a/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc b/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
index 85715d7..ec2add2 100644
--- a/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
@@ -21,6 +21,8 @@
   input.max_resolution = gfx::Size(4096, 4096);
   input.max_framerate_numerator = 30;
   input.max_framerate_denominator = 1;
+  input.rate_control_modes = VideoEncodeAccelerator::kConstantMode |
+                             VideoEncodeAccelerator::kVariableMode;
   input.scalability_modes.push_back(::media::SVCScalabilityMode::kL1T3);
   input.scalability_modes.push_back(::media::SVCScalabilityMode::kL3T3Key);
 
diff --git a/media/remoting/demuxer_stream_adapter.cc b/media/remoting/demuxer_stream_adapter.cc
index 704eb27..b1b3026a 100644
--- a/media/remoting/demuxer_stream_adapter.cc
+++ b/media/remoting/demuxer_stream_adapter.cc
@@ -237,12 +237,25 @@
 void DemuxerStreamAdapter::EnableBitstreamConverter() {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   DEMUXER_VLOG(2) << "Received RPC_DS_ENABLEBITSTREAMCONVERTER";
+  bool is_command_sent = true;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   demuxer_stream_->EnableBitstreamConverter();
 #else
+  is_command_sent = false;
   DEMUXER_VLOG(1) << "Ignoring EnableBitstreamConverter() RPC: Proprietary "
                      "codecs not enabled in this Chromium build.";
 #endif
+
+  if (remote_callback_handle_ != RpcMessenger::kInvalidHandle) {
+    auto rpc = std::make_unique<openscreen::cast::RpcMessage>();
+    rpc->set_handle(remote_callback_handle_);
+    rpc->set_proc(
+        openscreen::cast::RpcMessage::RPC_DS_ENABLEBITSTREAMCONVERTER_CALLBACK);
+    rpc->set_boolean_value(is_command_sent);
+    main_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&RpcMessenger::SendMessageToRemote,
+                                  rpc_messenger_, *rpc));
+  }
 }
 
 void DemuxerStreamAdapter::RequestBuffer() {
diff --git a/media/video/fake_video_encode_accelerator.cc b/media/video/fake_video_encode_accelerator.cc
index 3ea8272..aee0e86 100644
--- a/media/video/fake_video_encode_accelerator.cc
+++ b/media/video/fake_video_encode_accelerator.cc
@@ -40,6 +40,7 @@
   profile.max_resolution.SetSize(1920, 1088);
   profile.max_framerate_numerator = 30;
   profile.max_framerate_denominator = 1;
+  profile.rate_control_modes = media::VideoEncodeAccelerator::kConstantMode;
 
   profile.profile = media::H264PROFILE_MAIN;
   profiles.push_back(profile);
diff --git a/media/video/video_encode_accelerator.cc b/media/video/video_encode_accelerator.cc
index 1624301..9c04460 100644
--- a/media/video/video_encode_accelerator.cc
+++ b/media/video/video_encode_accelerator.cc
@@ -152,11 +152,13 @@
     const gfx::Size& max_resolution,
     uint32_t max_framerate_numerator,
     uint32_t max_framerate_denominator,
+    SupportedRateControlMode rc_modes,
     const std::vector<SVCScalabilityMode>& scalability_modes)
     : profile(profile),
       max_resolution(max_resolution),
       max_framerate_numerator(max_framerate_numerator),
       max_framerate_denominator(max_framerate_denominator),
+      rate_control_modes(rc_modes),
       scalability_modes(scalability_modes) {}
 
 VideoEncodeAccelerator::SupportedProfile::SupportedProfile(
@@ -202,6 +204,7 @@
          l.max_resolution == r.max_resolution &&
          l.max_framerate_numerator == r.max_framerate_numerator &&
          l.max_framerate_denominator == r.max_framerate_denominator &&
+         l.rate_control_modes == r.rate_control_modes &&
          l.scalability_modes == r.scalability_modes;
 }
 
diff --git a/media/video/video_encode_accelerator.h b/media/video/video_encode_accelerator.h
index 8c9e816b..4711981 100644
--- a/media/video/video_encode_accelerator.h
+++ b/media/video/video_encode_accelerator.h
@@ -141,6 +141,13 @@
 // Video encoder interface.
 class MEDIA_EXPORT VideoEncodeAccelerator {
  public:
+  // Bitmask values for supported rate control modes.
+  enum SupportedRateControlMode : uint8_t {
+    kNoMode = 0,  // for uninitialized profiles only
+    kConstantMode = 0b0001,
+    kVariableMode = 0b0010,
+  };
+
   // Specification of an encoding profile supported by an encoder.
   struct MEDIA_EXPORT SupportedProfile {
     SupportedProfile();
@@ -149,6 +156,7 @@
         const gfx::Size& max_resolution,
         uint32_t max_framerate_numerator = 0u,
         uint32_t max_framerate_denominator = 1u,
+        SupportedRateControlMode rc_modes = kConstantMode,
         const std::vector<SVCScalabilityMode>& scalability_modes = {});
     SupportedProfile(const SupportedProfile& other);
     SupportedProfile& operator=(const SupportedProfile& other) = default;
@@ -158,6 +166,7 @@
     gfx::Size max_resolution;
     uint32_t max_framerate_numerator{0};
     uint32_t max_framerate_denominator{0};
+    SupportedRateControlMode rate_control_modes = kNoMode;
     std::vector<SVCScalabilityMode> scalability_modes;
   };
   using SupportedProfiles = std::vector<SupportedProfile>;
@@ -445,6 +454,35 @@
     const VideoEncodeAccelerator::Config::SpatialLayer& r);
 MEDIA_EXPORT bool operator==(const VideoEncodeAccelerator::Config& l,
                              const VideoEncodeAccelerator::Config& r);
+
+MEDIA_EXPORT inline VideoEncodeAccelerator::SupportedRateControlMode operator|(
+    VideoEncodeAccelerator::SupportedRateControlMode lhs,
+    VideoEncodeAccelerator::SupportedRateControlMode rhs) {
+  return static_cast<VideoEncodeAccelerator::SupportedRateControlMode>(
+      static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
+}
+
+MEDIA_EXPORT inline VideoEncodeAccelerator::SupportedRateControlMode&
+operator|=(VideoEncodeAccelerator::SupportedRateControlMode& lhs,
+           VideoEncodeAccelerator::SupportedRateControlMode rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+
+MEDIA_EXPORT inline VideoEncodeAccelerator::SupportedRateControlMode operator&(
+    VideoEncodeAccelerator::SupportedRateControlMode lhs,
+    VideoEncodeAccelerator::SupportedRateControlMode rhs) {
+  return static_cast<VideoEncodeAccelerator::SupportedRateControlMode>(
+      static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
+}
+
+MEDIA_EXPORT inline VideoEncodeAccelerator::SupportedRateControlMode&
+operator&=(VideoEncodeAccelerator::SupportedRateControlMode& lhs,
+           VideoEncodeAccelerator::SupportedRateControlMode rhs) {
+  lhs = lhs & rhs;
+  return lhs;
+}
+
 }  // namespace media
 
 namespace std {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index a91042e..de59777 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3698,6 +3698,29 @@
         "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
       },
       {
+        "isolate_name": "gpu_pytype",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_pytype",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://content/test:gpu_pytype/"
+      },
+      {
         "isolate_name": "grit_python_unittests",
         "isolate_profile_data": true,
         "merge": {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 90cdc50..8bf88109 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -925,6 +925,11 @@
     "script": "//testing/scripts/run_performance_tests.py",
     "type": "script",
   },
+  "gpu_pytype": {
+    "label": "//content/test:gpu_pytype",
+    "script": "//content/test/gpu/run_pytype.py",
+    "type": "script",
+  },
   "gpu_unittests": {
     "label": "//gpu:gpu_unittests",
     "type": "windowed_test_launcher",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 5cf9e23..0a964dd 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1807,6 +1807,11 @@
       'Android FYI Release (Pixel 2)',
     ],
   },
+  'gpu_pytype': {
+    'remove_from': [
+      'linux-code-coverage',
+    ],
+  },
   'gpu_unittests': {
     'modifications': {
       'fuchsia-code-coverage': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 9d85112..b3defca 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4644,6 +4644,14 @@
       },
     },
 
+    'pytype_tests': {
+      'gpu_pytype': {
+        'mixins': [
+          'has_native_resultdb_integration',
+        ],
+      },
+    },
+
     'rendering_desktop_representative_perf_tests_isolated_scripts': {
       'rendering_representative_perf_tests': {
         'isolate_name': 'rendering_representative_perf_tests',
@@ -6017,6 +6025,7 @@
       'desktop_chromium_isolated_scripts',
       'linux_specific_chromium_isolated_scripts',
       'mojo_python_unittests_isolated_scripts',
+      'pytype_tests',
       'telemetry_perf_unittests_isolated_scripts',
       'vulkan_swiftshader_isolated_scripts',
       'chromium_web_tests_high_dpi_isolated_scripts',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6ebfb36..3a5fac2a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1639,6 +1639,21 @@
             ]
         }
     ],
+    "BatchImageDecoding": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "BatchImageDecoding"
+                    ]
+                }
+            ]
+        }
+    ],
     "BatchSimpleURLLoader": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 28548c5..c0fa03ed 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -62,6 +62,11 @@
 const base::FeatureParam<double> kMinimumEntropyForLCP{
     &kExcludeLowEntropyImagesFromLCP, "min_bpp", 2};
 
+// Used as a binding for controlling the runtime enabled blink feature
+// "FixedElementsDontOverscroll". This is needed for experimentation.
+const base::Feature kFixedElementsDontOverscroll{
+    "FixedElementsDontOverscroll", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kGMSCoreEmoji{"GMSCoreEmoji",
                                   base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index e368cc2..459c42e 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -30,6 +30,7 @@
 BLINK_COMMON_EXPORT extern const base::Feature kExcludeLowEntropyImagesFromLCP;
 BLINK_COMMON_EXPORT extern const base::FeatureParam<double>
     kMinimumEntropyForLCP;
+BLINK_COMMON_EXPORT extern const base::Feature kFixedElementsDontOverscroll;
 BLINK_COMMON_EXPORT extern const base::Feature kGMSCoreEmoji;
 BLINK_COMMON_EXPORT extern const base::Feature kPaintHolding;
 BLINK_COMMON_EXPORT extern const base::Feature kPaintHoldingCrossOrigin;
diff --git a/third_party/blink/public/mojom/unhandled_tap_notifier/unhandled_tap_notifier.mojom b/third_party/blink/public/mojom/unhandled_tap_notifier/unhandled_tap_notifier.mojom
index b18b727..20d71b7 100644
--- a/third_party/blink/public/mojom/unhandled_tap_notifier/unhandled_tap_notifier.mojom
+++ b/third_party/blink/public/mojom/unhandled_tap_notifier/unhandled_tap_notifier.mojom
@@ -11,9 +11,6 @@
 // This data is used to notifying the Browser to show UI for an unhandled tap if needed.
 struct UnhandledTapInfo {
     gfx.mojom.Point tapped_position_in_viewport;
-    // These values default to 0,  which indicates an undetermined value.
-    uint32 font_size_in_pixels = 0;
-    uint32 element_text_run_length = 0;
 };
 
 interface UnhandledTapNotifier {
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index 4144f46c..0381065b 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -448,30 +448,39 @@
     }
   };
 
-  if (const CascadePriority* priority =
-          map_.Find(CSSPropertyName(CSSPropertyID::kWebkitBorderImage))) {
-    LookupAndApply(GetCSSPropertyWebkitBorderImage(), resolver);
+  const CSSProperty& webkit_border_image = GetCSSPropertyWebkitBorderImage();
+  if (!resolver.filter_.Rejects(webkit_border_image)) {
+    if (const CascadePriority* priority =
+            map_.Find(webkit_border_image.GetCSSPropertyName())) {
+      LookupAndApply(webkit_border_image, resolver);
 
-    const auto& shorthand = borderImageShorthand();
-    const CSSProperty** longhands = shorthand.properties();
-    for (unsigned i = 0; i < shorthand.length(); ++i) {
-      maybe_skip(*longhands[i], *priority);
+      const auto& shorthand = borderImageShorthand();
+      const CSSProperty** longhands = shorthand.properties();
+      for (unsigned i = 0; i < shorthand.length(); ++i) {
+        maybe_skip(*longhands[i], *priority);
+      }
     }
   }
 
-  if (const CascadePriority* priority =
-          map_.Find(CSSPropertyName(CSSPropertyID::kPerspectiveOrigin))) {
-    LookupAndApply(GetCSSPropertyPerspectiveOrigin(), resolver);
-    maybe_skip(GetCSSPropertyWebkitPerspectiveOriginX(), *priority);
-    maybe_skip(GetCSSPropertyWebkitPerspectiveOriginY(), *priority);
+  const CSSProperty& perspective_origin = GetCSSPropertyPerspectiveOrigin();
+  if (!resolver.filter_.Rejects(perspective_origin)) {
+    if (const CascadePriority* priority =
+            map_.Find(perspective_origin.GetCSSPropertyName())) {
+      LookupAndApply(perspective_origin, resolver);
+      maybe_skip(GetCSSPropertyWebkitPerspectiveOriginX(), *priority);
+      maybe_skip(GetCSSPropertyWebkitPerspectiveOriginY(), *priority);
+    }
   }
 
-  if (const CascadePriority* priority =
-          map_.Find(CSSPropertyName(CSSPropertyID::kTransformOrigin))) {
-    LookupAndApply(GetCSSPropertyTransformOrigin(), resolver);
-    maybe_skip(GetCSSPropertyWebkitTransformOriginX(), *priority);
-    maybe_skip(GetCSSPropertyWebkitTransformOriginY(), *priority);
-    maybe_skip(GetCSSPropertyWebkitTransformOriginZ(), *priority);
+  const CSSProperty& transform_origin = GetCSSPropertyTransformOrigin();
+  if (!resolver.filter_.Rejects(transform_origin)) {
+    if (const CascadePriority* priority =
+            map_.Find(transform_origin.GetCSSPropertyName())) {
+      LookupAndApply(transform_origin, resolver);
+      maybe_skip(GetCSSPropertyWebkitTransformOriginX(), *priority);
+      maybe_skip(GetCSSPropertyWebkitTransformOriginY(), *priority);
+      maybe_skip(GetCSSPropertyWebkitTransformOriginZ(), *priority);
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index f50a1f20..c0af13c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -3109,6 +3109,37 @@
   EXPECT_EQ("inline", cascade.ComputedValue("display"));
 }
 
+TEST_F(StyleCascadeTest, FilterWebkitBorderImage) {
+  TestCascade cascade(GetDocument());
+  cascade.Add("border-image:linear-gradient(green, red) 1 / 2 / 3 round",
+              Origin::kAuthor);
+  cascade.Add(
+      "-webkit-border-image:linear-gradient(green, red) 4 / 5 / 6 round",
+      Origin::kAuthor);
+  cascade.Apply(CascadeFilter(CSSProperty::kLegacyOverlapping, true));
+  EXPECT_EQ("linear-gradient(rgb(0, 128, 0), rgb(255, 0, 0)) 1 / 2 / 3 round",
+            cascade.ComputedValue("-webkit-border-image"));
+}
+
+TEST_F(StyleCascadeTest, FilterPerspectiveOrigin) {
+  TestCascade cascade(GetDocument());
+  cascade.Add("-webkit-perspective-origin-x:10px");
+  cascade.Add("-webkit-perspective-origin-y:20px");
+  cascade.Add("perspective-origin:30px 40px");
+  cascade.Apply(CascadeFilter(CSSProperty::kLegacyOverlapping, false));
+  EXPECT_EQ("10px 20px", cascade.ComputedValue("perspective-origin"));
+}
+
+TEST_F(StyleCascadeTest, FilterTransformOrigin) {
+  TestCascade cascade(GetDocument());
+  cascade.Add("-webkit-transform-origin-x:10px");
+  cascade.Add("-webkit-transform-origin-y:20px");
+  cascade.Add("-webkit-transform-origin-z:30px");
+  cascade.Add("transform-origin:40px 50px 60px");
+  cascade.Apply(CascadeFilter(CSSProperty::kLegacyOverlapping, false));
+  EXPECT_EQ("10px 20px 30px", cascade.ComputedValue("transform-origin"));
+}
+
 TEST_F(StyleCascadeTest, HasAuthorBackground) {
   Vector<String> properties = {"background-attachment", "background-blend-mode",
                                "background-clip",       "background-image",
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index aafe46c7..3ba8bfc 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -4828,27 +4828,19 @@
       mojom::blink::UnhandledTapInfoPtr unhandled_tap_info) override {
     was_unhandled_tap_ = true;
     tapped_position_ = unhandled_tap_info->tapped_position_in_viewport;
-    element_text_run_length_ = unhandled_tap_info->element_text_run_length;
-    font_size_ = unhandled_tap_info->font_size_in_pixels;
   }
   bool WasUnhandledTap() const { return was_unhandled_tap_; }
   int GetTappedXPos() const { return tapped_position_.x(); }
   int GetTappedYPos() const { return tapped_position_.y(); }
-  int GetFontSize() const { return font_size_; }
-  int GetElementTextRunLength() const { return element_text_run_length_; }
   void Reset() {
     was_unhandled_tap_ = false;
     tapped_position_ = gfx::Point();
-    element_text_run_length_ = 0;
-    font_size_ = 0;
     receiver_.reset();
   }
 
  private:
   bool was_unhandled_tap_ = false;
   gfx::Point tapped_position_;
-  int element_text_run_length_ = 0;
-  int font_size_ = 0;
 
   mojo::Receiver<mojom::blink::UnhandledTapNotifier> receiver_{this};
 };
@@ -4934,8 +4926,6 @@
   EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
   EXPECT_EQ(64, mock_notifier_.GetTappedXPos());
   EXPECT_EQ(278, mock_notifier_.GetTappedYPos());
-  EXPECT_EQ(16, mock_notifier_.GetFontSize());
-  EXPECT_EQ(7, mock_notifier_.GetElementTextRunLength());
 
   // Test basic tap handling and notification.
   Tap("target");
@@ -4963,8 +4953,6 @@
   constexpr float expected_y = 82 * scale - (scale * visual_y);
   EXPECT_EQ(expected_x, mock_notifier_.GetTappedXPos());
   EXPECT_EQ(expected_y, mock_notifier_.GetTappedYPos());
-  EXPECT_EQ(16, mock_notifier_.GetFontSize());
-  EXPECT_EQ(28, mock_notifier_.GetElementTextRunLength());
 }
 
 TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithMutateDom) {
@@ -5006,16 +4994,6 @@
   EXPECT_FALSE(mock_notifier_.WasUnhandledTap());
 }
 
-TEST_F(ShowUnhandledTapTest, ShowUnhandledTapUIIfNeededWithTextSizes) {
-  Tap("large");
-  EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
-  EXPECT_EQ(20, mock_notifier_.GetFontSize());
-
-  Tap("small");
-  EXPECT_TRUE(mock_notifier_.WasUnhandledTap());
-  EXPECT_EQ(10, mock_notifier_.GetFontSize());
-}
-
 #endif  // BUILDFLAG(ENABLE_UNHANDLED_TAP)
 
 TEST_F(WebViewTest, ShouldSuppressKeyboardForPasswordField) {
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 5e3cc908..99dbe24b 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -14305,4 +14305,36 @@
             mojom::blink::ColorScheme::kDark);
 }
 
+TEST_F(WebFrameSimTest, RenderBlockingPromotesResource) {
+  ScopedBlockingAttributeForTest enabled_scope(true);
+
+  SimRequest main_request("https://example.com/", "text/html");
+  SimSubresourceRequest script_request("https://example.com/script.js",
+                                       "text/javascript");
+
+  LoadURL("https://example.com/");
+  main_request.Write(R"HTML(
+    <!doctype html>
+    <script defer fetchpriority="low" src="script.js"></script>
+  )HTML");
+
+  Resource* script = GetDocument().Fetcher()->AllResources().at(
+      ToKURL("https://example.com/script.js"));
+
+  // Script is fetched at the low priority due to `fetchpriority="low"`.
+  ASSERT_TRUE(script);
+  EXPECT_EQ(ResourceLoadPriority::kLow,
+            script->GetResourceRequest().Priority());
+
+  main_request.Complete(R"HTML(
+    <script defer fetchpriority="low" blocking="render" src="script.js"></script>
+  )HTML");
+
+  // `blocking=render` promotes the priority to high.
+  EXPECT_EQ(ResourceLoadPriority::kHigh,
+            script->GetResourceRequest().Priority());
+
+  script_request.Complete();
+}
+
 }  // namespace blink
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 051a646..fcd6a99 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
@@ -1147,6 +1147,11 @@
   if (task_runner_state_->WaitingForStylesheets())
     task_runner_state_->SetWaitingForStylesheets(false);
 
+  if (IsStopping()) {
+    AttemptToRunDeferredScriptsAndEnd();
+    return;
+  }
+
   // Document only calls this when the Document owns the DocumentParser so this
   // will not be called in the DocumentFragment case.
   DCHECK(script_runner_);
diff --git a/third_party/blink/renderer/core/input/gesture_manager.cc b/third_party/blink/renderer/core/input/gesture_manager.cc
index 495935b..3a0b0747 100644
--- a/third_party/blink/renderer/core/input/gesture_manager.cc
+++ b/third_party/blink/renderer/core/input/gesture_manager.cc
@@ -371,7 +371,7 @@
         frame_->GetPage()->GetVisualViewport().RootFrameToViewport(
             tapped_position);
     ShowUnhandledTapUIIfNeeded(dom_tree_changed, style_changed, tapped_node,
-                               tapped_element, tapped_position_in_viewport);
+                               tapped_position_in_viewport);
   }
 
   return event_result;
@@ -557,11 +557,9 @@
     bool dom_tree_changed,
     bool style_changed,
     Node* tapped_node,
-    Element* tapped_element,
     const gfx::Point& tapped_position_in_viewport) {
 #if BUILDFLAG(ENABLE_UNHANDLED_TAP)
   WebNode web_node(tapped_node);
-  // TODO(donnd): roll in ML-identified signals for suppression once identified.
   bool should_trigger = !dom_tree_changed && !style_changed &&
                         tapped_node->IsTextNode() &&
                         !web_node.IsContentEditable() &&
@@ -574,22 +572,9 @@
     frame_->GetBrowserInterfaceBroker().GetInterface(
         provider.BindNewPipeAndPassReceiver());
 
-    // Extract text run-length.
-    int text_run_length = 0;
-    if (tapped_element)
-      text_run_length = tapped_element->textContent().length();
-
-    int font_size = 0;
-    // Extract text characteristics from the computed style of the tapped node.
-    if (const ComputedStyle* style = tapped_node->GetComputedStyle())
-      font_size = style->FontSize();
-
-    // TODO(donnd): get the text color and style and return,
-    // e.g. style->GetFontWeight() to return bold.  Need italic, color, etc.
-
     // Notify the Browser.
-    auto tapped_info = mojom::blink::UnhandledTapInfo::New(
-        tapped_position_in_viewport, font_size, text_run_length);
+    auto tapped_info =
+        mojom::blink::UnhandledTapInfo::New(tapped_position_in_viewport);
     provider->ShowUnhandledTapUIIfNeeded(std::move(tapped_info));
   }
 #endif  // BUILDFLAG(ENABLE_UNHANDLED_TAP)
diff --git a/third_party/blink/renderer/core/input/gesture_manager.h b/third_party/blink/renderer/core/input/gesture_manager.h
index 7a3ba769..0543c85 100644
--- a/third_party/blink/renderer/core/input/gesture_manager.h
+++ b/third_party/blink/renderer/core/input/gesture_manager.h
@@ -89,7 +89,6 @@
       bool dom_tree_changed,
       bool style_changed,
       Node* tapped_node,
-      Element* tapped_element,
       const gfx::Point& tapped_position_in_viewport);
   // Returns the pointerId associated with the pointerevent sequence
   // generated by the gesture sequence of which gesture_event
diff --git a/third_party/blink/renderer/core/script/document_write_intervention.cc b/third_party/blink/renderer/core/script/document_write_intervention.cc
index 48c0bb9..ffc02bb 100644
--- a/third_party/blink/renderer/core/script/document_write_intervention.cc
+++ b/third_party/blink/renderer/core/script/document_write_intervention.cc
@@ -210,6 +210,7 @@
   FetchParameters params(options.CreateFetchParameters(
       resource->Url(), context->GetSecurityOrigin(), context->GetCurrentWorld(),
       cross_origin, resource->Encoding(), FetchParameters::kIdleLoad));
+  params.SetRenderBlockingBehavior(RenderBlockingBehavior::kNonBlocking);
   AddHeader(&params);
   ScriptResource::Fetch(params, element_document.Fetcher(), nullptr,
                         ScriptResource::kNoStreaming);
diff --git a/third_party/blink/renderer/core/script/html_parser_script_runner.cc b/third_party/blink/renderer/core/script/html_parser_script_runner.cc
index fd07f2c..19efd275 100644
--- a/third_party/blink/renderer/core/script/html_parser_script_runner.cc
+++ b/third_party/blink/renderer/core/script/html_parser_script_runner.cc
@@ -420,14 +420,21 @@
   // of scripts that will execute when the document has finished parsing has
   // its "ready to be parser-executed" flag set and the parser's Document has
   // no style sheet that is blocking scripts.</spec>
-  //
-  // TODO(hiroshige): Add check for style sheet blocking defer scripts
-  // https://github.com/whatwg/html/issues/3890
+  if (!document_->IsScriptExecutionReady())
+    return nullptr;
   if (!waiting_scripts->front()->IsReady()) {
-    waiting_scripts->front()->WatchForLoad(this);
-    TraceParserBlockingScript(waiting_scripts->front().Get(),
-                              !document_->IsScriptExecutionReady());
-    waiting_scripts->front()->MarkParserBlockingLoadStartTime();
+    if (!waiting_scripts->front()->IsWatchingForLoad()) {
+      // First time when all the conditions except for
+      // `PendingScript::IsReady()` are satisfied. Note that
+      // `TryTakeReadyScriptWaitingForParsing()` can triggered by script and
+      // stylesheet load completions multiple times, so `IsWatchingForLoad()` is
+      // checked to avoid double execution of this code block. When
+      // `IsWatchingForLoad()` is true, its existing client is always `this`.
+      waiting_scripts->front()->WatchForLoad(this);
+      TraceParserBlockingScript(waiting_scripts->front().Get(),
+                                !document_->IsScriptExecutionReady());
+      waiting_scripts->front()->MarkParserBlockingLoadStartTime();
+    }
     return nullptr;
   }
   return waiting_scripts->TakeFirst();
diff --git a/third_party/blink/renderer/core/script/pending_script.h b/third_party/blink/renderer/core/script/pending_script.h
index 0196817..b4f58b2 100644
--- a/third_party/blink/renderer/core/script/pending_script.h
+++ b/third_party/blink/renderer/core/script/pending_script.h
@@ -133,13 +133,14 @@
 
   virtual bool IsEligibleForDelay() const { return false; }
 
+  bool IsWatchingForLoad() const { return client_; }
+
  protected:
   PendingScript(ScriptElementBase*, const TextPosition& starting_position);
 
   virtual void DisposeInternal() = 0;
 
   PendingScriptClient* Client() { return client_; }
-  bool IsWatchingForLoad() const { return client_; }
 
   virtual void CheckState() const = 0;
 
diff --git a/third_party/blink/renderer/core/testing/data/show_unhandled_tap.html b/third_party/blink/renderer/core/testing/data/show_unhandled_tap.html
index 6955c2a..820629d 100644
--- a/third_party/blink/renderer/core/testing/data/show_unhandled_tap.html
+++ b/third_party/blink/renderer/core/testing/data/show_unhandled_tap.html
@@ -16,12 +16,6 @@
 :indeterminate + span {
   background-color: blue;
 }
-#large {
-  font-size: 20px;
-}
-#small {
-  font-size: 10px;
-}
 </style>
 </head>
 <body>
@@ -33,8 +27,6 @@
 <img id="image" width="10" height="10" src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="><br>
 <span id="editable" contenteditable="true">editable</span><br>
 <span id="focusable" tabindex="1">focusable</span><br>
-<span id="large">large</span><br>
-<span id="small">small</span><br>
 </div>
 
 <p style="position: absolute; left: 8px; top: 400px; width: 400px; height: 30px;"><span id="bottom">Bottom.</span></p>
diff --git a/third_party/blink/renderer/modules/buckets/storage_bucket.cc b/third_party/blink/renderer/modules/buckets/storage_bucket.cc
index 4f4eb5a2..d55f5bd5 100644
--- a/third_party/blink/renderer/modules/buckets/storage_bucket.cc
+++ b/third_party/blink/renderer/modules/buckets/storage_bucket.cc
@@ -24,6 +24,15 @@
 ScriptPromise StorageBucket::persist(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->Persist(WTF::Bind(&StorageBucket::DidRequestPersist,
                              WrapPersistent(this), WrapPersistent(resolver)));
   return promise;
@@ -32,6 +41,15 @@
 ScriptPromise StorageBucket::persisted(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->Persisted(WTF::Bind(&StorageBucket::DidGetPersisted,
                                WrapPersistent(this), WrapPersistent(resolver)));
   return promise;
@@ -40,6 +58,15 @@
 ScriptPromise StorageBucket::estimate(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->Estimate(WTF::Bind(&StorageBucket::DidGetEstimate,
                               WrapPersistent(this), WrapPersistent(resolver)));
   return promise;
@@ -48,6 +75,15 @@
 ScriptPromise StorageBucket::durability(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->Durability(WTF::Bind(&StorageBucket::DidGetDurability,
                                 WrapPersistent(this),
                                 WrapPersistent(resolver)));
@@ -58,6 +94,15 @@
                                         const DOMTimeStamp& expires) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->SetExpires(
       base::Time::FromJavaTime(expires),
       WTF::Bind(&StorageBucket::DidSetExpires, WrapPersistent(this),
@@ -68,6 +113,15 @@
 ScriptPromise StorageBucket::expires(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
+
+  // The context may be destroyed and the mojo connection unbound. However the
+  // object may live on, reject any requests after the context is destroyed.
+  if (!remote_.is_bound()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
+    return promise;
+  }
+
   remote_->Expires(WTF::Bind(&StorageBucket::DidGetExpires,
                              WrapPersistent(this), WrapPersistent(resolver)));
   return promise;
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 8bef4c5d..0e87bee 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -715,8 +715,6 @@
   if (allow_vea_encoder &&
       CanUseAcceleratedEncoder(codec_profile.codec_id, input_size.width(),
                                input_size.height())) {
-    // TODO(b/227350897): remove once codec histogram is verified working
-    UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", true);
     UmaHistogramForCodec(true, codec_profile.codec_id);
 
     const auto vea_profile =
@@ -735,8 +733,6 @@
         bits_per_second, vea_profile, codec_profile.level, input_size,
         use_import_mode, main_task_runner_);
   } else {
-    // TODO(b/227350897): remove once codec histogram is verified working
-    UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", false);
     UmaHistogramForCodec(false, codec_profile.codec_id);
     switch (codec_profile.codec_id) {
 #if BUILDFLAG(RTC_USE_H264)
diff --git a/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc b/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc
index b4b5a14b..9cbc5b98 100644
--- a/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc
+++ b/third_party/blink/renderer/modules/webaudio/async_audio_decoder.cc
@@ -83,8 +83,8 @@
       audio_data->Data(), audio_data->ByteLength(), false, sample_rate);
 
   // Decoding is finished, but we need to do the callbacks on the main thread.
-  // A reference to |*bus| is retained by base::OnceCallback and will be removed
-  // after notifyComplete() is done.
+  // A reference to `bus` is retained by base::OnceCallback and will be removed
+  // after `NotifyComplete()` is done.
   //
   // We also want to avoid notifying the main thread if AudioContext does not
   // exist any more.
diff --git a/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h b/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h
index 711c9306..f7e0c4f 100644
--- a/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h
+++ b/third_party/blink/renderer/modules/webaudio/async_audio_decoder.h
@@ -59,8 +59,8 @@
 
   ~AsyncAudioDecoder() = default;
 
-  // Must be called on the main thread.  |decodeAsync| and callees must not
-  // modify any of the parameters except |audioData|.  They are used to
+  // Must be called on the main thread.  `DecodeAsync` and callees must not
+  // modify any of the parameters except `audio_data`.  They are used to
   // associate this decoding instance with the caller to process the decoding
   // appropriately when finished.
   void DecodeAsync(DOMArrayBuffer* audio_data,
diff --git a/third_party/blink/renderer/modules/webaudio/audio_buffer.h b/third_party/blink/renderer/modules/webaudio/audio_buffer.h
index 09e2f49f..ce75d7a 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_buffer.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_buffer.h
@@ -61,7 +61,7 @@
   // Creates an AudioBuffer with uninitialized contents.  This should
   // only be used where we are guaranteed to initialize the contents
   // with valid data and where JS cannot access until initializations
-  // is done.  |OfflineAudioContext::startRendering()| is one such
+  // is done.  `OfflineAudioContext::StartRendering()` is one such
   // place.
   static AudioBuffer* CreateUninitialized(unsigned number_of_channels,
                                           uint32_t number_of_frames,
@@ -71,8 +71,8 @@
 
   explicit AudioBuffer(AudioBus*);
   // How to initialize the contents of an AudioBuffer.  Default is to
-  // zero-initialize (|kZeroInitialize|).  Otherwise, leave the array
-  // uninitialized (|kDontInitialize|).
+  // zero-initialize (`kZeroInitialize`).  Otherwise, leave the array
+  // uninitialized (`kDontInitialize`).
   enum InitializationPolicy { kZeroInitialize, kDontInitialize };
   AudioBuffer(unsigned number_of_channels,
               uint32_t number_of_frames,
diff --git a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc
index cc446b9..e7a6f94 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.cc
@@ -557,8 +557,9 @@
   grain_offset_ = grain_offset;
   grain_duration_ = grain_duration;
 
-  // If |when| < currentTime, the source must start now according to the spec.
-  // So just set startTime to currentTime in this case to start the source now.
+  // If `when` < `currentTime()`, the source must start now according to the
+  // spec.  So just set `start_time_` to `currentTime()` in this case to start
+  // the source now.
   start_time_ = std::max(when, Context()->currentTime());
 
   if (Buffer()) {
@@ -571,7 +572,7 @@
 void AudioBufferSourceHandler::SetLoop(bool looping) {
   DCHECK(IsMainThread());
 
-  // This synchronizes with |Process()|.
+  // This synchronizes with `Process()`.
   MutexLocker process_locker(process_lock_);
 
   is_looping_ = looping;
@@ -581,7 +582,7 @@
 void AudioBufferSourceHandler::SetLoopStart(double loop_start) {
   DCHECK(IsMainThread());
 
-  // This synchronizes with |Process()|.
+  // This synchronizes with `Process()`.
   MutexLocker process_locker(process_lock_);
 
   loop_start_ = loop_start;
@@ -590,7 +591,7 @@
 void AudioBufferSourceHandler::SetLoopEnd(double loop_end) {
   DCHECK(IsMainThread());
 
-  // This synchronizes with |Process()|.
+  // This synchronizes with `Process()`.
   MutexLocker process_locker(process_lock_);
 
   loop_end_ = loop_end;
@@ -643,13 +644,13 @@
     return true;
   }
 
-  // Protect |shared_buffer_| with tryLock because it can be accessed by the
+  // Protect `shared_buffer_` with tryLock because it can be accessed by the
   // main thread.
   MutexTryLocker try_locker(process_lock_);
   if (try_locker.Locked()) {
     return !shared_buffer_.get();
   } else {
-    // Can't get lock. Assume |shared_buffer_| exists, so return false to
+    // Can't get lock. Assume `shared_buffer_` exists, so return false to
     // indicate this node is (or might be) outputting non-zero samples.
     return false;
   }
diff --git a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h
index ca4b9352..75ad026 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_buffer_source_handler.h
@@ -51,9 +51,9 @@
              double grain_duration,
              ExceptionState&);
 
-  // Note: the attribute was originally exposed as |.looping|, but to be more
+  // Note: the attribute was originally exposed as `.looping`, but to be more
   // consistent in naming with <audio> and with how it's described in the
-  // specification, the proper attribute name is |.loop|. The old attribute is
+  // specification, the proper attribute name is `.loop`. The old attribute is
   // kept for backwards compatibility.
   bool Loop() const { return is_looping_; }
   void SetLoop(bool looping);
@@ -92,9 +92,9 @@
   //     Maximum number of frames to process; this can be less that a render
   //     quantum.
   //   start_time_offset -
-  //     Actual start time relative to the |destination_frame_offset|.  This
-  //     should be the \sart_time_offset| value returned by
-  //     |UpdateSchedulingInfo|.
+  //     Actual start time relative to the `destination_frame_offset`.  This
+  //     should be the `start_time_offset` value returned by
+  //     `UpdateSchedulingInfo`.
   bool RenderFromBuffer(AudioBus* output_bus,
                         unsigned destination_frame_offset,
                         uint32_t number_of_frames,
@@ -138,8 +138,8 @@
   // A process lock must be used to protect access.
   bool did_set_looping_ = false;
 
-  // A process lock must be used to protect access to both |loop_start_| and
-  // |loop_end_|.
+  // A process lock must be used to protect access to both `loop_start_` and
+  // `loop_end_`.
   double loop_start_ = 0;
   double loop_end_ = 0;
 
@@ -164,7 +164,7 @@
   // The minimum playbackRate value ever used for this source.
   double min_playback_rate_ = 1.0;
 
-  // True if the |buffer| attribute has ever been set to a non-null
+  // True if the `buffer` attribute has ever been set to a non-null
   // value.  Defaults to false.
   bool buffer_has_been_set_ = false;
 };
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index cab42ae..ed77971 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -230,7 +230,7 @@
   //
   // TODO(hongchan): Due to the incompatible constructor between
   // AudioDestinationNode and RealtimeAudioDestinationNode, casting directly
-  // from |destination()| is impossible. This is a temporary workaround until
+  // from `destination()` is impossible. This is a temporary workaround until
   // the refactoring is completed.
   RealtimeAudioDestinationHandler& destination_handler =
       static_cast<RealtimeAudioDestinationHandler&>(
@@ -267,7 +267,7 @@
 AudioContext::~AudioContext() {
   // TODO(crbug.com/945379) Disable this DCHECK for now.  It's not terrible if
   // the autoplay metrics aren't recorded in some odd situations.  haraken@ said
-  // that we shouldn't get here without also calling |Uninitialize()|, but it
+  // that we shouldn't get here without also calling `Uninitialize()`, but it
   // can happen.  Until that is fixed, disable this DCHECK.
 
   // DCHECK(!autoplay_status_.has_value());
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.h b/third_party/blink/renderer/modules/webaudio/audio_context.h
index 18d733c..620a168 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -200,7 +200,7 @@
   // Records if start() was ever called for any source node in this context.
   bool source_node_started_ = false;
 
-  // Represents whether a context is suspended by explicit |context.suspend()|.
+  // Represents whether a context is suspended by explicit `context.suspend()`.
   bool suspended_by_user_ = false;
 
   // baseLatency for this context
diff --git a/third_party/blink/renderer/modules/webaudio/audio_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_handler.cc
index a48430a1..26cda28 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_handler.cc
@@ -347,8 +347,8 @@
     }
 
     if (!silent_inputs) {
-      // Update |last_non_silent_time| AFTER processing this block.
-      // Doing it before causes |PropagateSilence()| to be one render
+      // Update `last_non_silent_time_` AFTER processing this block.
+      // Doing it before causes `PropagateSilence()` to be one render
       // quantum longer than necessary.
       last_non_silent_time_ =
           (Context()->CurrentSampleFrame() + frames_to_process) /
diff --git a/third_party/blink/renderer/modules/webaudio/audio_handler.h b/third_party/blink/renderer/modules/webaudio/audio_handler.h
index bd8fb71..39c6fc6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_handler.h
@@ -241,7 +241,7 @@
   // See http://crbug.com/404527 for the detail.
   UntracedMember<BaseAudioContext> context_;
 
-  // Legal to access even when |context_| may be gone, such as during the
+  // Legal to access even when `context_` may be gone, such as during the
   // destructor.
   const scoped_refptr<DeferredTaskHandler> deferred_task_handler_;
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_node.cc b/third_party/blink/renderer/modules/webaudio/audio_node.cc
index 2e18bd7e..778ac59 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_node.cc
@@ -50,7 +50,7 @@
 
 AudioNode::~AudioNode() {
   // The graph lock is required to destroy the handler. And we can't use
-  // |context_| to touch it, since that object may also be a dead heap object.
+  // `context_` to touch it, since that object may also be a dead heap object.
   {
     DeferredTaskHandler::GraphAutoLocker locker(*deferred_task_handler_);
     handler_ = nullptr;
@@ -493,7 +493,7 @@
   unsigned number_of_disconnections = 0;
 
   // Check if the node output is connected the destination AudioParam.
-  // Disconnect if connected and increase |numberOfDisconnectios| by 1.
+  // Disconnect if connected and increase `number_of_disconnections` by 1.
   for (unsigned output_index = 0; output_index < Handler().NumberOfOutputs();
        ++output_index) {
     if (DisconnectFromOutputIfConnected(output_index, *destination_param)) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_node.h b/third_party/blink/renderer/modules/webaudio/audio_node.h
index 31bf74d..b332de2 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_node.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_node.h
@@ -135,10 +135,7 @@
   void SendLogMessage(const String& message);
 
   Member<BaseAudioContext> context_;
-
-  // Needed in the destructor, where |context_| is not guaranteed to be alive.
   scoped_refptr<DeferredTaskHandler> deferred_task_handler_;
-
   scoped_refptr<AudioHandler> handler_;
 
   // Represents audio node graph with Oilpan references. N-th HeapHashSet
diff --git a/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc b/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc
index 2cc2ca28b..ef81c45f 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_node_wiring.cc
@@ -221,7 +221,7 @@
   // changes to its connections.
   //
   // What does matter, however, is ensuring that no AudioNodeOutput holds a
-  // dangling pointer to |input|.
+  // dangling pointer to `input`.
 
   input.GetDeferredTaskHandler().AssertGraphOwner();
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
index 5b1c2a42f..8c7b9d0 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -81,7 +81,7 @@
 
 AudioParam::~AudioParam() {
   // The graph lock is required to destroy the handler. And we can't use
-  // |context_| to touch it, since that object may also be a dead heap object.
+  // `context_` to touch it, since that object may also be a dead heap object.
   {
     DeferredTaskHandler::GraphAutoLocker locker(*deferred_task_handler_);
     handler_ = nullptr;
@@ -217,9 +217,6 @@
   WarnIfOutsideRange("setTargetAtTime value", target);
   Handler().Timeline().SetTargetAtTime(target, time, time_constant,
                                        exception_state);
-
-  // Don't update the histogram here.  It's not clear in normal usage if the
-  // parameter value will actually reach |target|.
   return this;
 }
 
@@ -242,11 +239,6 @@
 
   Handler().Timeline().SetValueCurveAtTime(curve, time, duration,
                                            exception_state);
-
-  // We could update the histogram with every value in the curve, due to
-  // interpolation, we'll probably be missing many values.  So we don't update
-  // the histogram.  setValueCurveAtTime is probably a fairly rare method
-  // anyway.
   return this;
 }
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.h b/third_party/blink/renderer/modules/webaudio/audio_param.h
index 0ec7c06a..7a84fabd 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.h
@@ -75,9 +75,9 @@
   ~AudioParam() override;
 
   void Trace(Visitor*) const override;
-  // |handler| always returns a valid object.
+  // `Handler()` always returns a valid object.
   AudioParamHandler& Handler() const { return *handler_; }
-  // |context| always returns a valid object.
+  // `Context()` always returns a valid object.
   BaseAudioContext* Context() const { return context_; }
 
   AudioParamHandler::AudioParamType GetParamType() const {
@@ -127,8 +127,6 @@
 
   scoped_refptr<AudioParamHandler> handler_;
   Member<BaseAudioContext> context_;
-
-  // Needed in the destructor, where |context_| is not guaranteed to be alive.
   scoped_refptr<DeferredTaskHandler> deferred_task_handler_;
 };
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_descriptor.idl b/third_party/blink/renderer/modules/webaudio/audio_param_descriptor.idl
index 085557d..e1f59a04 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_descriptor.idl
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_descriptor.idl
@@ -6,11 +6,7 @@
 dictionary AudioParamDescriptor {
     required DOMString name;
     float defaultValue = 0;
-
-    // TODO(hongchan): These numbers are minimum/maximum number possible for 
-    // |float| type. Remove this comment when the spec is fixed.
     float minValue = -3.4028235e38;
     float maxValue = 3.4028235e38;
-
     AutomationRate automationRate = "a-rate";
 };
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
index 59b9d1d..e594510 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_handler.cc
@@ -224,7 +224,7 @@
   CalculateFinalValues(values, number_of_values, IsAudioRate());
 }
 
-// Replace NaN values in |values| with |default_value|.
+// Replace NaN values in `values` with `default_value`.
 static void HandleNaNValues(float* values,
                             unsigned number_of_values,
                             float default_value) {
@@ -323,7 +323,7 @@
       summing_bus_->SumFrom(*connection_bus);
     }
 
-    // If we're not sample accurate, duplicate the first element of |values| to
+    // If we're not sample accurate, duplicate the first element of `values` to
     // all of the elements.
     if (!sample_accurate) {
       for (unsigned k = 0; k < number_of_values; ++k) {
@@ -354,7 +354,7 @@
 void AudioParamHandler::CalculateTimelineValues(float* values,
                                                 unsigned number_of_values) {
   // Calculate values for this render quantum.  Normally
-  // |numberOfValues| will equal to
+  // `number_of_values` will equal to
   // GetDeferredTaskHandler().RenderQuantumFrames() (the render quantum size).
   double sample_rate = DestinationHandler().SampleRate();
   size_t start_frame = DestinationHandler().CurrentSampleFrame();
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_handler.h b/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
index 046946c..a866fc6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_handler.h
@@ -200,7 +200,7 @@
   AudioParamType param_type_;
   // Name of the AudioParam. This is only used for printing out more informative
   // warnings, and only used for AudioWorklets.  All others have a name derived
-  // from the |param_type_|.  Worklets need custom names because they're defined
+  // from the `param_type_`.  Worklets need custom names because they're defined
   // by the user.
   String custom_param_name_;
 
@@ -212,7 +212,7 @@
 
   // The automation rate of the AudioParam (k-rate or a-rate)
   AutomationRate automation_rate_;
-  // |rate_mode_| determines if the user can change the automation rate to a
+  // `rate_mode_` determines if the user can change the automation rate to a
   // different value.
   const AutomationRateMode rate_mode_;
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
index b8604c0..a6a4c6c9 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -49,8 +49,8 @@
 
 // For a SetTarget event, we want the event to terminate eventually so that
 // we can stop using the timeline to compute the values.  See
-// |HasSetTargetConverged()| for the algorithm.  |kSetTargetThreshold| is
-// exp(-kTimeConstantsToConverge).
+// `HasSetTargetConverged()` for the algorithm.  `kSetTargetThreshold` is
+// exp(-`kTimeConstantsToConverge`).
 const float kTimeConstantsToConverge = 10;
 const float kSetTargetThreshold = 4.539992976248485e-05;
 
@@ -111,7 +111,7 @@
     case ParamEvent::kCancelValues:
     case ParamEvent::kSetValueCurveEnd:
     // Fall through; we should never have to print out the internal
-    // |kCancelValues| or |kSetValueCurveEnd| event.
+    // `kCancelValues` or `kSetValueCurveEnd` event.
     case ParamEvent::kLastType:
       NOTREACHED();
       break;
@@ -583,7 +583,7 @@
     double end_time = event->Time() + event->Duration();
     for (int i = ub; i >= 0; i--) {
       ParamEvent::Type test_type = events_[i]->GetType();
-      // Events of type |kSetValueCurveEnd| or |kCancelValues| never conflict.
+      // Events of type `kSetValueCurveEnd` or `kCancelValues` never conflict.
       if (test_type == ParamEvent::kSetValueCurveEnd ||
           test_type == ParamEvent::kCancelValues) {
         continue;
@@ -608,7 +608,7 @@
         }
       } else {
         // Here we handle existing events of types other than
-        // |kSetValueCurveEnd|, |kCancelValues| and |kSetValueCurve|.
+        // `kSetValueCurveEnd`, `kCancelValues` and `kSetValueCurve`.
         // Throw an error if an existing event starts in the middle of this
         // SetValueCurve event.
         if (events_[i]->Time() > event->Time() &&
@@ -621,22 +621,22 @@
         }
       }
       if (events_[i]->Time() < insert_time) {
-        // We found an existing event, E, of type other than |kSetValueCurveEnd|
-        // or |kCancelValues| that starts before the new event of type
-        // |kSetValueCurve| that we want to insert. No earlier existing event
-        // can overlap with the new event. An overlapping |kSetValueCurve| would
+        // We found an existing event, E, of type other than `kSetValueCurveEnd`
+        // or `kCancelValues` that starts before the new event of type
+        // `kSetValueCurve` that we want to insert. No earlier existing event
+        // can overlap with the new event. An overlapping `kSetValueCurve` would
         // have ovelapped with E too, so one of them would not be inserted.
-        // Other event types overlap with the new |kSetValueCurve| event only if
+        // Other event types overlap with the new `kSetValueCurve` event only if
         // they start in the middle of the new event, which is not the case.
         break;
       }
     }
   } else {
-    // Not a |SetValueCurve| new event. Make sure this new event doesn't overlap
-    // any existing |SetValueCurve| event.
+    // Not a `SetValueCurve` new event. Make sure this new event doesn't overlap
+    // any existing `SetValueCurve` event.
     for (int i = ub; i >= 0; i--) {
       ParamEvent::Type test_type = events_[i]->GetType();
-      // Events of type |kSetValueCurveEnd| or |kCancelValues| never conflict.
+      // Events of type `kSetValueCurveEnd` or `kCancelValues` never conflict.
       if (test_type == ParamEvent::kSetValueCurveEnd ||
           test_type == ParamEvent::kCancelValues) {
         continue;
@@ -653,9 +653,9 @@
         }
       }
       if (events_[i]->Time() < insert_time) {
-        // We found an existing event, E, of type other than |kSetValueCurveEnd|
-        // or |kCancelValues| that starts before the new event that we want to
-        // insert. No earlier event of type |kSetValueCurve| can overlap with
+        // We found an existing event, E, of type other than `kSetValueCurveEnd`
+        // or `kCancelValues` that starts before the new event that we want to
+        // insert. No earlier event of type `kSetValueCurve` can overlap with
         // the new event, because it would have overlapped with E too.
         break;
       }
@@ -700,7 +700,7 @@
 
     // If there are at least 2 events in the timeline, assume there are timeline
     // values.  This could be optimized to be more careful, but checking is
-    // complicated and keeping this consistent with |ValuesForFrameRangeImpl()|
+    // complicated and keeping this consistent with `ValuesForFrameRangeImpl()`
     // will be hard, so it's probably best to let the general timeline handle
     // this until the events are in the past.
     if (n_events >= 2) {
@@ -796,7 +796,7 @@
   MutexLocker locker(events_lock_);
 
   wtf_size_t i;
-  // Find the first event at or just past cancelTime.
+  // Find the first event at or just past `cancel_time`.
   for (i = 0; i < events_.size(); ++i) {
     if (events_[i]->Time() > cancel_time) {
       break;
@@ -804,16 +804,16 @@
   }
 
   // The event that is being cancelled.  This is the event just past
-  // cancelTime, if any.
+  // `cancel_time`, if any.
   wtf_size_t cancelled_event_index = i;
 
-  // If the event just before cancelTime is a SetTarget or SetValueCurve
+  // If the event just before `cancel_time` is a SetTarget or SetValueCurve
   // event, we need to handle that event specially instead of the event after.
   if (i > 0 && ((events_[i - 1]->GetType() == ParamEvent::kSetTarget) ||
                 (events_[i - 1]->GetType() == ParamEvent::kSetValueCurve))) {
     cancelled_event_index = i - 1;
   } else if (i >= events_.size()) {
-    // If there were no events occurring after |cancelTime| (and the
+    // If there were no events occurring after `cancel_time` (and the
     // previous event is not SetTarget or SetValueCurve, we're done.
     return;
   }
@@ -993,12 +993,12 @@
 
   int number_of_events = events_.size();
 
-  // MUST clamp event before |events_| is possibly mutated because
-  // |new_events_| has raw pointers to objects in |events_|.  Clamping
-  // will clear out all of these pointers before |events_| is
+  // MUST clamp event before `events_` is possibly mutated because
+  // `new_events_` has raw pointers to objects in `events_`.  Clamping
+  // will clear out all of these pointers before `events_` is
   // potentially modified.
   //
-  // TODO(rtoy): Consider making |events_| be scoped_refptr instead of
+  // TODO(rtoy): Consider making `events_` be scoped_refptr instead of
   // unique_ptr.
   if (new_events_.size() > 0) {
     ClampNewEventsToCurrentTime(start_frame / sample_rate);
@@ -1060,17 +1060,18 @@
     DCHECK(!std::isnan(value2));
     DCHECK_GE(time2, time1);
 
-    // |fillToEndFrame| is the exclusive upper bound of the last frame to be
-    // computed for this event.  It's either the last desired frame (|endFrame|)
-    // or derived from the end time of the next event (time2). We compute
-    // ceil(time2*sampleRate) because fillToEndFrame is the exclusive upper
-    // bound.  Consider the case where |startFrame| = 128 and time2 = 128.1
-    // (assuming sampleRate = 1).  Since time2 is greater than 128, we want to
-    // output a value for frame 128.  This requires that fillToEndFrame be at
-    // least 129.  This is achieved by ceil(time2).
+    // `fill_to_end_frame` is the exclusive upper bound of the last frame to be
+    // computed for this event.  It's either the last desired frame
+    // (`end_frame`) or derived from the end time of the next event
+    // (`time2`). We compute ceil(`time2`*`sample_rate`) because
+    // `fill_to_end_frame` is the exclusive upper bound.  Consider the case
+    // where `start_frame` = 128 and `time2` = 128.1 (assuming `sample_rate` =
+    // 1).  Since `time2` is greater than 128, we want to output a value for
+    // frame 128.  This requires that `fill_to_end_frame` be at least 129.  This
+    // is achieved by ceil(`time2`).
     //
-    // However, time2 can be very large, so compute this carefully in the case
-    // where time2 exceeds the size of a size_t.
+    // However, `time2` can be very large, so compute this carefully in the case
+    // where `time2` exceeds the size of a size_t.
 
     size_t fill_to_end_frame = end_frame;
     if (end_frame > time2 * sample_rate) {
@@ -1163,8 +1164,8 @@
   // running with the m_events lock so we can safely modify the m_events
   // array.)
   if (last_skipped_event_index > 0) {
-    // |new_events_| should be empty here so we don't have to
-    // do any updates due to this mutation of |events_|.
+    // `new_events_` should be empty here so we don't have to
+    // do any updates due to this mutation of `events_`.
     DCHECK_EQ(new_events_.size(), 0u);
     RemoveOldEvents(last_skipped_event_index - 1);
   }
@@ -1173,7 +1174,7 @@
   // propagate the last value to the end of the values buffer.
   write_index = FillWithDefault(values, value, number_of_values, write_index);
 
-  // This value is used to set the .value attribute of the AudioParam.  it
+  // This value is used to set the `.value` attribute of the AudioParam.  it
   // should be the last computed value.
   return values[number_of_values - 1];
 }
@@ -1189,8 +1190,8 @@
     unsigned write_index) {
   double first_event_time = events_[0]->Time();
   if (first_event_time > start_frame / sample_rate) {
-    // |fillToFrame| is an exclusive upper bound, so use ceil() to compute the
-    // bound from the firstEventTime.
+    // `fill_to_frame` is an exclusive upper bound, so use ceil() to compute the
+    // bound from the `first_event_time`.
     size_t fill_to_end_frame = end_frame;
     double first_event_frame = ceil(first_event_time * sample_rate);
     if (end_frame > first_event_frame) {
@@ -1214,17 +1215,17 @@
                                         const ParamEvent* next_event,
                                         size_t current_frame,
                                         double sample_rate) const {
-  // WARNING: due to round-off it might happen that nextEvent->time() is
-  // just larger than currentFrame/sampleRate.  This means that we will end
-  // up running the |event| again.  The code below had better be prepared
-  // for this case!  What should happen is the fillToFrame should be 0 so
-  // that while the event is actually run again, nothing actually gets
-  // computed, and we move on to the next event.
+  // WARNING: due to round-off it might happen that `next_event->Time()` is just
+  // larger than `current_frame`/`sample_rate`.  This means that we will end up
+  // running the `event` again.  The code below had better be prepared for this
+  // case!  What should happen is the fillToFrame should be 0 so that while the
+  // event is actually run again, nothing actually gets computed, and we move on
+  // to the next event.
   //
-  // An example of this case is setValueCurveAtTime.  The time at which
-  // setValueCurveAtTime ends (and the setValueAtTime begins) might be
-  // just past currentTime/sampleRate.  Then setValueCurveAtTime will be
-  // processed again before advancing to setValueAtTime.  The number of
+  // An example of this case is `SetValueCurveAtTime()`.  The time at which
+  // `SetValueCurveAtTime()` ends (and the `SetValueAtTime()` begins) might be
+  // just past `current_time`/`sample_rate`.  Then `SetValueCurveAtTime()` will
+  // be processed again before advancing to `SetValueAtTime()`.  The number of
   // frames to be processed should be zero in this case.
   if (next_event && next_event->Time() < current_frame / sample_rate) {
     // But if the current event is a SetValue event and the event time is
@@ -1278,20 +1279,21 @@
                                   double current_time,
                                   double start_time,
                                   double time_constant) {
-  // Converged if enough time constants (|kTimeConstantsToConverge|) have passed
+  // Converged if enough time constants (`kTimeConstantsToConverge`) have passed
   // since the start of the event.
   if (current_time > start_time + kTimeConstantsToConverge * time_constant) {
     return true;
   }
 
-  // If |target| is 0, converged if |value| is less than |kSetTargetThreshold|.
+  // If `target` is 0, converged if |`value`| is less than
+  // `kSetTargetThreshold`.
   if (target == 0 && fabs(value) < kSetTargetThreshold) {
     return true;
   }
 
-  // If |target| is not zero, converged if relative difference betwenn |value|
-  // and |target| is small.  That is |target-value|/|target| <
-  // |kSetTargetThreshold|.
+  // If `target` is not zero, converged if relative difference betwenn `value`
+  // and `target` is small.  That is |`target`-`value`|/|`value`| <
+  // `kSetTargetThreshold`.
   if (target != 0 && fabs(target - value) < kSetTargetThreshold * fabs(value)) {
     return true;
   }
@@ -1333,12 +1335,12 @@
       }
     }
 
-    // |events_| is being mutated.  |new_events_| better be empty because there
+    // `events_` is being mutated.  `new_events_` better be empty because there
     // are raw pointers there.
     DCHECK_EQ(new_events_.size(), 0U);
     // The event has finished, so just copy the default value out.
     // Since all events are now also in the past, we can just remove all
-    // timeline events too because |defaultValue| has the expected
+    // timeline events too because `default_value` has the expected
     // value.
     FillWithDefault(values, default_value, number_of_values, 0);
     smoothed_value_ = default_value;
@@ -1366,7 +1368,7 @@
       (next_event_type == ParamEvent::kLinearRampToValue ||
        next_event_type == ParamEvent::kExponentialRampToValue)) {
     // Replace the SetTarget with a SetValue to set the starting time and
-    // value for the ramp using the current frame.  We need to update |value|
+    // value for the ramp using the current frame.  We need to update `value`
     // appropriately depending on whether the ramp has started or not.
     //
     // If SetTarget starts somewhere between currentFrame - 1 and
@@ -1393,7 +1395,7 @@
                   fdlibm::exp(-(current_frame / sample_rate - event->Time()) /
                               event->TimeConstant());
     } else {
-      // SetTarget has already started.  Update |value| one frame because it's
+      // SetTarget has already started.  Update `value` one frame because it's
       // the value from the previous frame.
       float discrete_time_constant =
           static_cast<float>(audio_utilities::DiscreteTimeConstantForSampleRate(
@@ -1559,8 +1561,8 @@
       v_value = _mm_add_ps(v_value, v_inc);
     }
   }
-  // Update |value| with the last value computed so that the
-  // .value attribute of the AudioParam gets the correct linear
+  // Update `value` with the last value computed so that the
+  // `.value` attribute of the AudioParam gets the correct linear
   // ramp value, in case the following loop doesn't execute.
   if (write_index >= 1) {
     value = values[write_index - 1];
@@ -1637,7 +1639,7 @@
       value *= multiplier;
       ++current_frame;
     }
-    // |value| got updated one extra time in the above loop.  Restore it to
+    // `value` got updated one extra time in the above loop.  Restore it to
     // the last computed value.
     if (write_index >= 1) {
       value /= multiplier;
@@ -1696,7 +1698,7 @@
                            fdlibm::exp(-(current_frame / sample_rate - time1) /
                                        time_constant);
     } else {
-      // Otherwise, need to compute a new value bacause |value| is the
+      // Otherwise, need to compute a new value because `value` is the
       // last computed value of SetTarget.  Time has progressed by one
       // frame, so we need to update the value for the new frame.
       value += (target - value) * discrete_time_constant;
@@ -1755,7 +1757,7 @@
       values[write_index] = value;
       value += (target - value) * discrete_time_constant;
     }
-    // The previous loops may have updated |value| one extra time.
+    // The previous loops may have updated `value` one extra time.
     // Reset it to the last computed value.
     if (write_index >= 1) {
       value = values[write_index - 1];
@@ -1820,10 +1822,10 @@
     }
   }
 
-  // |fillToFrame| can be less than |startFrame| when the end of the
+  // `fill_to_frame` can be less than `start_frame` when the end of the
   // setValueCurve automation has been reached, but the next automation
-  // has not yet started. In this case, |fillToFrame| is clipped to
-  // |time1|+|duration| above, but |startFrame| will keep increasing
+  // has not yet started. In this case, `fill_to_frame` is clipped to
+  // `time1`+`duration` above, but `start_frame` will keep increasing
   // (because the current time is increasing).
   fill_to_frame = (fill_to_end_frame < start_frame)
                       ? 0
@@ -1882,8 +1884,8 @@
                                       v_number_of_curve_points_m1));
 
       // Linearly interpolate between the two nearest curve points.
-      // |delta| is clamped to 1 because currentVirtualIndex can exceed
-      // curveIndex0 by more than one.  This can happen when we reached
+      // `delta` is clamped to 1 because `current_virtual_index` can exceed
+      // `curve_index0` by more than one.  This can happen when we reached
       // the end of the curve but still need values to fill out the
       // current rendering quantum.
       _mm_storeu_si128(reinterpret_cast<__m128i*>(a_curve_index0),
@@ -1929,11 +1931,10 @@
     unsigned curve_index1 =
         std::min(curve_index0 + 1, number_of_curve_points - 1);
 
-    // Linearly interpolate between the two nearest curve points.
-    // |delta| is clamped to 1 because currentVirtualIndex can exceed
-    // curveIndex0 by more than one.  This can happen when we reached
-    // the end of the curve but still need values to fill out the
-    // current rendering quantum.
+    // Linearly interpolate between the two nearest curve points.  `delta` is
+    // clamped to 1 because `current_virtual_index` can exceed `curve_index0` by
+    // more than one.  This can happen when we reached the end of the curve but
+    // still need values to fill out the current rendering quantum.
     DCHECK_LT(curve_index0, number_of_curve_points);
     DCHECK_LT(curve_index1, number_of_curve_points);
     float c0 = curve_data[curve_index0];
@@ -1947,7 +1948,7 @@
 
   // If there's any time left after the duration of this event and the
   // start of the next, then just propagate the last value of the
-  // curveData. Don't modify |value| unless there is time left.
+  // `curve_data`. Don't modify `value` unless there is time left.
   if (write_index < next_event_fill_to_frame) {
     value = curve_end_value;
     for (; write_index < next_event_fill_to_frame; ++write_index) {
@@ -2023,7 +2024,7 @@
 void AudioParamTimeline::RemoveCancelledEvents(
     wtf_size_t first_event_to_remove) {
   // For all the events that are being removed, also remove that event
-  // from |new_events_|.
+  // from `new_events_`.
   if (new_events_.size() > 0) {
     for (wtf_size_t k = first_event_to_remove; k < events_.size(); ++k) {
       new_events_.erase(events_[k].get());
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
index 9a83db6..6025f24 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
@@ -73,8 +73,8 @@
   //
   //   bool has_value - to indicate if the value could be computed from the
   //                    timeline
-  //   float value    - the timeline value if |has_value| is true; otherwise
-  //                    |default_value| is returned.
+  //   float value    - the timeline value if `has_value` is true; otherwise
+  //                    `default_value` is returned.
   std::tuple<bool, float> ValueForContextTime(AudioDestinationHandler&,
                                               float default_value,
                                               float min_value,
@@ -120,7 +120,7 @@
       kSetValueCurve,
       // For cancelValuesAndHold
       kCancelValues,
-      // Special marker for the end of a |kSetValueCurve| event.
+      // Special marker for the end of a `kSetValueCurve` event.
       kSetValueCurveEnd,
       kLastType
     };
@@ -340,8 +340,8 @@
                          unsigned curve_length);
 
   // Handles the special case where the first event in the timeline
-  // starts after |startFrame|.  These initial values are filled using
-  // |defaultValue|.  The updated |currentFrame| and |writeIndex| is
+  // starts after `start_frame`.  These initial values are filled using
+  // `default_value`.  The updated `current_frame` and `write_index` is
   // returned.
   std::tuple<size_t, unsigned> HandleFirstEvent(float* values,
                                                 float default_value,
@@ -352,22 +352,22 @@
                                                 size_t current_frame,
                                                 unsigned write_index);
 
-  // Return true if |currentEvent| starts after |currentFrame|, but
-  // also takes into account the |nextEvent| if any.
+  // Return true if `current_event` starts after `current_frame`, but
+  // also takes into account the `next_event` if any.
   bool IsEventCurrent(const ParamEvent* current_event,
                       const ParamEvent* next_event,
                       size_t current_frame,
                       double sample_rate) const;
 
   // Clamp times to current time, if needed for any new events.  Note,
-  // this method can mutate |events_|, so do call this only in safe
+  // this method can mutate `events_`, so do call this only in safe
   // places.
   void ClampNewEventsToCurrentTime(double current_time);
 
   // Handle the case where the last event in the timeline is in the
   // past.  Returns false if any event is not in the past. Otherwise,
-  // return true and also fill in |values| with |defaultValue|.
-  // |defaultValue| may be updated with a new value.
+  // return true and also fill in `values` with `default_value`.
+  // `default_value` may be updated with a new value.
   bool HandleAllEventsInThePast(double current_time,
                                 double sample_rate,
                                 float& default_value,
@@ -377,7 +377,7 @@
 
   // Handle processing of CancelValue event. If cancellation happens, value2,
   // time2, and nextEventType will be updated with the new value due to
-  // cancellation.  Note that |next_event| or its member can be null.
+  // cancellation.  Note that `next_event` or its member can be null.
   std::tuple<float, double, ParamEvent::Type> HandleCancelValues(
       const ParamEvent* current_event,
       ParamEvent* next_event,
@@ -397,9 +397,9 @@
                                       double control_rate,
                                       float& value);
 
-  // Handle processing of linearRampEvent, writing the appropriate
-  // values to |values|.  Returns the updated |currentFrame|, last
-  // computed |value|, and the updated |writeIndex|.
+  // Handle processing of LinearRampEvent, writing the appropriate
+  // values to `values`.  Returns the updated `current_frame`, last
+  // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessLinearRamp(
       const AutomationState& current_state,
       float* values,
@@ -407,9 +407,9 @@
       float value,
       unsigned write_index);
 
-  // Handle processing of exponentialRampEvent, writing the appropriate
-  // values to |values|.  Returns the updated |currentFrame|, last
-  // computed |value|, and the updated |writeIndex|.
+  // Handle processing of ExponentialRampEvent, writing the appropriate
+  // values to `values`.  Returns the updated `current_frame`, last
+  // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessExponentialRamp(
       const AutomationState& current_state,
       float* values,
@@ -418,8 +418,8 @@
       unsigned write_index);
 
   // Handle processing of SetTargetEvent, writing the appropriate
-  // values to |values|.  Returns the updated |currentFrame|, last
-  // computed |value|, and the updated |writeIndex|.
+  // values to `values`.  Returns the updated `current_frame`, last
+  // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessSetTarget(
       const AutomationState& current_state,
       float* values,
@@ -428,8 +428,8 @@
       unsigned write_index);
 
   // Handle processing of SetValueCurveEvent, writing the appropriate
-  // values to |values|.  Returns the updated |currentFrame|, last
-  // computed |value|, and the updated |writeIndex|.
+  // values to `values`.  Returns the updated `current_frame`, last
+  // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessSetValueCurve(
       const AutomationState& current_state,
       float* values,
@@ -438,8 +438,8 @@
       unsigned write_index);
 
   // Handle processing of CancelValuesEvent, writing the appropriate
-  // values to |values|.  Returns the updated |currentFrame|, last
-  // computed |value|, and the updated |writeIndex|.
+  // values to `values`.  Returns the updated `current_frame`, last
+  // computed `value`, and the updated `write_index`.
   std::tuple<size_t, float, unsigned> ProcessCancelValues(
       const AutomationState& current_state,
       float* values,
@@ -447,16 +447,16 @@
       float value,
       unsigned write_index);
 
-  // Fill the output vector |values| with the value |defaultValue|,
-  // starting at |writeIndex| and continuing up to |endFrame|
-  // (exclusive).  |writeIndex| is updated with the new index.
+  // Fill the output vector `values` with the value `default_value`,
+  // starting at `write_index` and continuing up to `end_frame`
+  // (exclusive).  `write_index` is updated with the new index.
   uint32_t FillWithDefault(float* values,
                            float default_value,
                            uint32_t end_frame,
                            uint32_t write_index);
 
-  // When cancelling events, remove the items from |events_| starting
-  // at the given index.  Update |new_events_| too.
+  // When cancelling events, remove the items from `events_` starting
+  // at the given index.  Update `new_events_` too.
   void RemoveCancelledEvents(wtf_size_t first_event_to_remove);
 
   // Remove old events, but always leave at least one event in the timeline.
@@ -469,11 +469,11 @@
   Vector<std::unique_ptr<ParamEvent>> events_;
 
   // Vector of raw pointers to the actual ParamEvent that was
-  // inserted.  As new events are added, |new_events_| is updated with
+  // inserted.  As new events are added, `new_events_` is updated with
   // tne new event.  When the timline is processed, these events are
-  // clamped to current time by |ClampNewEventsToCurrentTime|. Access
-  // must be locked via |events_lock_|.  Must be maintained together
-  // with |events_|.
+  // clamped to current time by `ClampNewEventsToCurrentTime`. Access
+  // must be locked via `events_lock_`.  Must be maintained together
+  // with `events_`.
   HashSet<ParamEvent*> new_events_;
 
   mutable Mutex events_lock_;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.cc
index d2846df..11214f7f 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.cc
@@ -96,7 +96,7 @@
     SetPlaybackState(PLAYING_STATE);
     // Determine the offset of the true start time from the starting frame.
     // NOTE: start_frame_offset is usually negative, but may not be because of
-    // the rounding that may happen in computing |start_frame| above.
+    // the rounding that may happen in computing `start_frame` above.
     start_frame_offset = start_time_ * sample_rate - start_frame;
   } else {
     start_frame_offset = 0;
@@ -189,8 +189,9 @@
   // the variables being set here.
   MutexLocker process_locker(process_lock_);
 
-  // If |when| < currentTime, the source must start now according to the spec.
-  // So just set startTime to currentTime in this case to start the source now.
+  // If `when` < `currentTime()`, the source must start now according to the
+  // spec. So just set `start_time_` to `currentTime()` in this case to start
+  // the source now.
   start_time_ = std::max(when, Context()->currentTime());
 
   SetPlaybackState(SCHEDULED_STATE);
diff --git a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.h b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.h
index 0056456b..710b4e1 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_scheduled_source_handler.h
@@ -136,7 +136,7 @@
   // Number of extra frames to use when determining if a source node can be
   // stopped.  This should be at least one rendering quantum, but we add one
   // more quantum for good measure.  This doesn't need to be extra precise, just
-  // more than one rendering quantum.  See |handleStoppableSourceNode()|.
+  // more than one rendering quantum.  See `HandleStoppableSourceNode()`.
   // FIXME: Expose the rendering quantum somehow instead of hardwiring a value
   // here.
   static const int kExtraStopFrames = 256;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_summing_junction.cc b/third_party/blink/renderer/modules/webaudio/audio_summing_junction.cc
index 01accbb..5d4e129c0 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_summing_junction.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_summing_junction.cc
@@ -49,7 +49,7 @@
   DCHECK(GetDeferredTaskHandler().IsAudioThread());
   GetDeferredTaskHandler().AssertGraphOwner();
   if (rendering_state_need_updating_) {
-    // Copy from m_outputs to m_renderingOutputs.
+    // Copy from `outputs_` to `rendering_outputs_`.
     rendering_outputs_.resize(outputs_.size());
     unsigned j = 0;
     for (AudioNodeOutput* output : outputs_) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_summing_junction.h b/third_party/blink/renderer/modules/webaudio/audio_summing_junction.h
index 5fd7beb..aa18165d 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_summing_junction.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_summing_junction.h
@@ -47,12 +47,12 @@
     return *deferred_task_handler_;
   }
 
-  // This must be called whenever we modify m_outputs.
+  // This must be called whenever we modify `outputs_`.
   void ChangedOutputs();
 
-  // This copies m_outputs to m_renderingOutputs. Please see comments for these
-  // lists below.  This must be called when we own the context's graph lock in
-  // the audio thread at the very start or end of the render quantum.
+  // This copies `outputs_` to `rendering_outputs_`. Please see comments for
+  // these lists below.  This must be called when we own the context's graph
+  // lock in the audio thread at the very start or end of the render quantum.
   void UpdateRenderingState();
 
   // Rendering code accesses its version of the current connections here.
@@ -69,25 +69,25 @@
 
   scoped_refptr<DeferredTaskHandler> deferred_task_handler_;
 
-  // m_outputs contains the AudioNodeOutputs representing current connections
+  // `outputs_` contains the AudioNodeOutputs representing current connections
   // which are not disabled.  The rendering code should never use this
-  // directly, but instead uses m_renderingOutputs.
+  // directly, but instead uses `rendering_outputs_`.
   // These raw pointers are safe. Owner AudioNodes of these AudioNodeOutputs
   // manage their lifetime, and AudioNode::dispose() disconnects all of
   // connections.
   HashSet<AudioNodeOutput*> outputs_;
 
-  // m_renderingOutputs is a copy of m_outputs which will never be modified
+  // `rendering_outputs_` is a copy of `outputs_` which will never be modified
   // during the graph rendering on the audio thread.  This is the list which
   // is used by the rendering code.
-  // Whenever m_outputs is modified, the context is told so it can later
-  // update m_renderingOutputs from m_outputs at a safe time.  Most of the
-  // time, m_renderingOutputs is identical to m_outputs.
+  // Whenever `outputs_` is modified, the context is told so it can later
+  // update `rendering_outputs_` from `outputs_` at a safe time.  Most of the
+  // time, `rendering_outputs_` is identical to `outputs_`.
   // These raw pointers are safe. Owner of this AudioSummingJunction has
   // strong references to owners of these AudioNodeOutput.
   Vector<AudioNodeOutput*> rendering_outputs_;
 
-  // m_renderingStateNeedUpdating keeps track if m_outputs is modified.
+  // `rendering_state_need_updating_` keeps track if `outputs_` is modified.
   bool rendering_state_need_updating_ = false;
 };
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
index 581f659..4f92f3f 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet.cc
@@ -66,8 +66,8 @@
 }
 
 bool AudioWorklet::NeedsToCreateGlobalScope() {
-  // This is a callback from |Worklet::FetchAndInvokeScript| call, which only
-  // can be triggered by Worklet.addModule() call.
+  // This is a callback from `Worklet::FetchAndInvokeScript()` call, which only
+  // can be triggered by `Worklet.addModule()` call.
   UseCounter::Count(GetExecutionContext(), WebFeature::kAudioWorkletAddModule);
 
   return GetNumberOfGlobalScopes() == 0;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet.h b/third_party/blink/renderer/modules/webaudio/audio_worklet.h
index 7a738d0..e7c0eb1c 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet.h
@@ -33,7 +33,7 @@
                        MessagePortChannel,
                        scoped_refptr<SerializedScriptValue> node_options);
 
-  // Invoked by AudioWorkletMessagingProxy. Notifies |context_| when
+  // Invoked by AudioWorkletMessagingProxy. Notifies `context_` when
   // AudioWorkletGlobalScope finishes the first script evaluation and is ready
   // for the worklet operation. Can be used for other post-evaluation tasks
   // in AudioWorklet or BaseAudioContext.
@@ -41,7 +41,7 @@
 
   BaseAudioContext* GetBaseAudioContext() const;
 
-  // Returns |nullptr| if there is no active WorkletGlobalScope().
+  // Returns `nullptr` if there is no active `WorkletGlobalScope()`.
   AudioWorkletMessagingProxy* GetMessagingProxy();
 
   const Vector<CrossThreadAudioParamInfo> GetParamInfoListForProcessor(
@@ -49,7 +49,7 @@
 
   bool IsProcessorRegistered(const String& name);
 
-  // Returns |true| when a AudioWorkletMessagingProxy and a WorkletBackingThread
+  // Returns `true` when a AudioWorkletMessagingProxy and a WorkletBackingThread
   // are ready.
   bool IsReady();
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
index f43db78..35d5806 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
@@ -163,7 +163,7 @@
   // parameterDescriptorSequence to the node name to parameter descriptor map
   // of the associated BaseAudioContext.
   if (object_proxy_) {
-    // TODO(crbug.com/1223178): |object_proxy_| is designed to outlive the
+    // TODO(crbug.com/1223178): `object_proxy_` is designed to outlive the
     // global scope, so we don't need to null check but the unit test is not
     // able to replicate the cross-thread messaging logic yet, so we skip this
     // call in unit tests.
@@ -178,7 +178,7 @@
   DCHECK(IsContextThread());
 
   // The registered definition is already checked by AudioWorkletNode
-  // construction process, so the |definition| here must be valid.
+  // construction process, so the `definition` here must be valid.
   AudioWorkletProcessorDefinition* definition = FindDefinition(name);
   DCHECK(definition);
 
@@ -194,7 +194,7 @@
   DCHECK(!processor_creation_params_);
   // There is no way to pass additional constructor arguments that are not
   // described in Web IDL, the static constructor will look up
-  // |processor_creation_params_| in the global scope to perform the
+  // `processor_creation_params_` in the global scope to perform the
   // construction properly.
   base::AutoReset<std::unique_ptr<ProcessorCreationParams>>
       processor_creation_extra_param(
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
index ddd0c33..fc6f2d4 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
@@ -85,8 +85,8 @@
   std::unique_ptr<Vector<CrossThreadAudioWorkletProcessorInfo>>
   WorkletProcessorInfoListForSynchronization();
 
-  // Gets |processor_creation_params_| for the processor construction. If there
-  // is no on-going processor construction, this MUST return nullptr.
+  // Gets `processor_creation_params_` for the processor construction. If there
+  // is no on-going processor construction, this MUST return `nullptr`.
   ProcessorCreationParams* GetProcessorCreationParams();
 
   void SetCurrentFrame(size_t current_frame);
@@ -123,7 +123,7 @@
   ProcessorInstances processor_instances_;
 
   // Gets set when the processor construction is invoked, and cleared out after
-  // the construction. See the comment in |CreateProcessor()| method for the
+  // the construction. See the comment in `CreateProcessor()` method for the
   // detail.
   std::unique_ptr<ProcessorCreationParams> processor_creation_params_;
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
index b636b7e..c1e038d 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
@@ -330,7 +330,7 @@
     input_buses.push_back(input_bus.get());
     output_buses.push_back(output_bus.get());
 
-    // Fill |input_channel| with 1 and zero out |output_bus|.
+    // Fill `input_channel` with 1 and zero out `output_bus`.
     std::fill(input_channel->MutableData(),
               input_channel->MutableData() + input_channel->length(), 1);
     output_bus->Zero();
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
index 86cf5aa8..7b81e4d 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
@@ -61,7 +61,7 @@
   is_output_channel_count_given_ = options->hasOutputChannelCount();
 
   for (unsigned i = 0; i < options->numberOfOutputs(); ++i) {
-    // If |options->outputChannelCount| unspecified, all outputs are mono.
+    // If `options->outputChannelCount` unspecified, all outputs are mono.
     AddOutput(is_output_channel_count_given_ ? options->outputChannelCount()[i]
                                              : 1);
   }
@@ -152,8 +152,8 @@
   DCHECK(input);
 
   // Dynamic channel count only works when the node has 1 input, 1 output and
-  // |outputChannelCount| is not given. Otherwise the channel count(s) should
-  // not be dynamically changed.
+  // the output channel count is not given. Otherwise the channel count(s)
+  // should not be dynamically changed.
   if (NumberOfInputs() == 1 && NumberOfOutputs() == 1 &&
       !is_output_channel_count_given_) {
     DCHECK_EQ(input, &Input(0));
@@ -197,11 +197,12 @@
 void AudioWorkletHandler::SetProcessorOnRenderThread(
     AudioWorkletProcessor* processor) {
   // TODO(hongchan): unify the thread ID check. The thread ID for this call
-  // is different from |Context()->IsAudiothread()|.
+  // is different from `Context()->IsAudiothread()`.
   DCHECK(!IsMainThread());
 
-  // |processor| can be nullptr when the invocation of user-supplied constructor
-  // fails. That failure fires at the node's 'onprocessorerror' event handler.
+  // `processor` can be `nullptr` when the invocation of user-supplied
+  // constructor fails. That failure fires at the node's `.onprocessorerror`
+  // event handler.
   if (processor) {
     processor_ = processor;
   } else {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h
index 0d8958f9..9dc532b 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h
@@ -47,12 +47,12 @@
 
   String Name() const { return name_; }
 
-  // Sets |AudioWorkletProcessor| and changes the state of the processor.
+  // Sets `AudioWorkletProcessor` and changes the state of the processor.
   // MUST be called from the render thread.
   void SetProcessorOnRenderThread(AudioWorkletProcessor*);
 
-  // Finish |AudioWorkletProcessor| and set the tail time to zero, when
-  // the user-supplied |process()| method returns false.
+  // Finish `AudioWorkletProcessor` and set the tail time to zero, when
+  // the user-supplied `process()` method returns false.
   void FinishProcessorOnRenderThread();
 
   void NotifyProcessorError(AudioWorkletProcessorErrorState);
@@ -81,7 +81,7 @@
   HashMap<String, std::unique_ptr<AudioFloatArray>> param_value_map_;
 
   // TODO(): Adjust this if needed based on the result of the process
-  // method or the value of |tail_time_|.
+  // method or the value of `tail_time_`.
   bool RequiresTailProcessing() const override { return true; }
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
index 63406f7..2ad668d 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
@@ -176,14 +176,14 @@
               .ToLocalChecked(),
           serialize_options, exception_state);
 
-  // |serialized_node_options| can be nullptr if the option dictionary is not
+  // `serialized_node_options` can be nullptr if the option dictionary is not
   // valid.
   if (!serialized_node_options) {
     serialized_node_options = SerializedScriptValue::NullValue();
   }
   DCHECK(serialized_node_options);
 
-  // This is non-blocking async call. |node| still can be returned to user
+  // This is non-blocking async call. `node` still can be returned to user
   // before the scheduled async task is completed.
   context->audioWorklet()->CreateProcessor(node->GetWorkletHandler(),
                                            std::move(processor_port_channel),
@@ -191,7 +191,7 @@
 
   {
     // The node should be manually added to the automatic pull node list,
-    // even without a |connect()| call.
+    // even without a `connect()` call.
     BaseAudioContext::GraphAutoLocker locker(context);
     node->Handler().UpdatePullStatusIfNeeded();
   }
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
index 8ddec3c..b61e3d6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
@@ -58,7 +58,7 @@
   AudioWorkletProcessorDefinition* definition =
       global_scope_->FindDefinition(Name());
 
-  // 1st JS arg |inputs_|. Compare |inputs| and |inputs_|. Then allocates the
+  // 1st JS arg `inputs_`. Compare `inputs` and `inputs_`. Then allocates the
   // data container if necessary.
   if (!PortTopologyMatches(isolate, context, inputs, inputs_)) {
     bool inputs_cloned_successfully =
@@ -74,10 +74,10 @@
   DCHECK_EQ(inputs_.Get(isolate)->Length(), inputs.size());
   DCHECK_EQ(input_array_buffers_.size(), inputs.size());
 
-  // Copies |inputs| to the internal |input_array_buffers|.
+  // Copies `inputs` to the internal `input_array_buffers_`.
   CopyPortToArrayBuffers(isolate, inputs, input_array_buffers_);
 
-  // 2nd JS arg |outputs_|. Compare |outputs| and |outputs_|. Then allocates the
+  // 2nd JS arg `outputs_`. Compare `outputs` and `outputs_`. Then allocates the
   // data container if necessary.
   if (!PortTopologyMatches(isolate, context, outputs, outputs_)) {
     bool outputs_cloned_successfully =
@@ -97,7 +97,7 @@
   DCHECK_EQ(outputs_.Get(isolate)->Length(), outputs.size());
   DCHECK_EQ(output_array_buffers_.size(), outputs.size());
 
-  // 3rd JS arg |params_|. Compare |param_value_map| and |params_|. Then
+  // 3rd JS arg `params_`. Compare `param_value_map` and `params_`. Then
   // allocates the data container if necessary.
   if (!ParamValueMapMatchesToParamsObject(isolate, context, param_value_map,
                                           params_)) {
@@ -111,7 +111,7 @@
   DCHECK(!params_.IsEmpty());
   DCHECK(params_.Get(isolate)->IsObject());
 
-  // Copies |param_value_map| to the internal |params_| object. This operation
+  // Copies `param_value_map` to the internal `params_` object. This operation
   // could fail if the getter of parameterDescriptors is overridden by user code
   // and returns incompatible data. (crbug.com/1151069)
   if (!CopyParamValueMapToObject(isolate, context, param_value_map, params_)) {
@@ -138,10 +138,10 @@
   }
   DCHECK(!try_catch.HasCaught());
 
-  // Copies the resulting output from author script to |outputs|.
+  // Copies the resulting output from author script to `outputs`.
   CopyArrayBuffersToPort(isolate, output_array_buffers_, outputs);
 
-  // Return the value from the user-supplied |process()| function. It is
+  // Return the value from the user-supplied `.process()` function. It is
   // used to maintain the lifetime of the node and the processor.
   return result.V8Value()->IsTrue();
 }
@@ -408,8 +408,7 @@
     v8::Local<v8::String> v8_param_name = V8String(isolate, param_name);
 
     // TODO(crbug.com/1095113): Remove this check and move the logic to
-    // AudioWorkletHandler. |param_float_array| is always 128 frames, and this
-    // could be optimized as well.
+    // AudioWorkletHandler.
     unsigned array_size = 1;
     for (unsigned k = 1; k < param_float_array->size(); ++k) {
       if (param_float_array->Data()[k] != param_float_array->Data()[0]) {
@@ -418,7 +417,7 @@
       }
     }
 
-    // The |param_name| should exist in the |param| object.
+    // The `param_name` should exist in the `param` object.
     v8::Local<v8::Value> param_array_value;
     if (!params_object->Get(context, v8_param_name)
              .ToLocal(&param_array_value) ||
@@ -458,8 +457,7 @@
     v8::Local<v8::String> v8_param_name = V8String(isolate, param_name);
 
     // TODO(crbug.com/1095113): Remove this check and move the logic to
-    // AudioWorkletHandler. |param_float_array| is always 128 frames, and this
-    // could be optimized as well.
+    // AudioWorkletHandler.
     unsigned array_size = 1;
     for (unsigned k = 1; k < param_float_array->size(); ++k) {
       if (param_float_array->Data()[k] != param_float_array->Data()[0]) {
@@ -516,7 +514,7 @@
         param_array_value.As<v8::Float32Array>();
     size_t array_length = float32_array->Length();
 
-    // The |float32_array| is neither 1 nor 128 frames, or the array buffer is
+    // The `float32_array` is neither 1 nor 128 frames, or the array buffer is
     // trasnferred/detached, do not proceed.
     if ((array_length != 1 && array_length != param_array->size()) ||
         float32_array->Buffer()->ByteLength() == 0) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
index a252edb..2c9c3b5 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h
@@ -24,8 +24,8 @@
 class ExecutionContext;
 
 // AudioWorkletProcessor class represents the active instance created from
-// AudioWorkletProcessorDefinition. |AudioWorkletNodeHandler| invokes
-// process() method in this object upon graph rendering.
+// AudioWorkletProcessorDefinition. AudioWorkletNodeHandler invokes `.process()`
+// method in this object upon graph rendering.
 //
 // This is constructed and destroyed on a worker thread, and all methods also
 // must be called on the worker thread.
@@ -34,9 +34,9 @@
 
  public:
   // This static factory should be called after an instance of
-  // |AudioWorkletNode| gets created by user-supplied JS code in the main
+  // AudioWorkletNode gets created by user-supplied JS code in the main
   // thread. This factory must not be called by user in
-  // |AudioWorkletGlobalScope|.
+  // AudioWorkletGlobalScope.
   static AudioWorkletProcessor* Create(ExecutionContext*);
 
   AudioWorkletProcessor(AudioWorkletGlobalScope*,
@@ -44,7 +44,7 @@
                         MessagePort*);
   ~AudioWorkletProcessor() override = default;
 
-  // |AudioWorkletHandler| invokes this method to process audio.
+  // `AudioWorkletHandler` invokes this method to process audio.
   bool Process(
       const Vector<scoped_refptr<AudioBus>>& inputs,
       Vector<scoped_refptr<AudioBus>>& outputs,
@@ -85,11 +85,11 @@
   static bool FreezeAudioPort(v8::Isolate*, v8::Local<v8::Context>,
                               v8::Local<v8::Array>& audio_port_array);
 
-  // Clones the topology of |audio_port_1| and builds a new AudioPort to
-  // |audio_port_2|. This call makes memory allocation and it should be avoided
-  // in the hot audio stack as much as possible. If |array_buffers| is a valid
-  // pointer, fill in |array_buffers| with new backing ArrayBuffers of
-  // |audio_port_2|. Returns false only if any v8 operation throws an
+  // Clones the topology of `audio_port_1` and builds a new AudioPort to
+  // `audio_port_2`. This call makes memory allocation and it should be avoided
+  // in the hot audio stack as much as possible. If `array_buffers` is a valid
+  // pointer, fill in `array_buffers` with new backing ArrayBuffers of
+  // `audio_port_2`. Returns false only if any v8 operation throws an
   // exception.
   static bool ClonePortTopology(
       v8::Isolate*, v8::Local<v8::Context>,
@@ -115,21 +115,21 @@
   static void ZeroArrayBuffers(v8::Isolate*,
                                const BackingArrayBuffers& array_buffers);
 
-  // Returns true if the structure of |param_value_map| matches |params| object
+  // Returns true if the structure of `param_value_map` matches `params` object
   // and the underlying ArrayBuffers are not transferred.
   static bool ParamValueMapMatchesToParamsObject(
       v8::Isolate*, v8::Local<v8::Context>,
       const HashMap<String, std::unique_ptr<AudioFloatArray>>& param_value_map,
       const TraceWrapperV8Reference<v8::Object>& params);
 
-  // Clones the structure of |param_value_map| to a given v8::Object, which
+  // Clones the structure of `param_value_map` to a given v8::Object, which
   // is an associated array of Float32Arrays.
   static bool CloneParamValueMapToObject(
       v8::Isolate*, v8::Local<v8::Context>,
       const HashMap<String, std::unique_ptr<AudioFloatArray>>& param_value_map,
       TraceWrapperV8Reference<v8::Object>& params);
 
-  // Copies the content of float arrays from |param_value_map] to |params|
+  // Copies the content of float arrays from `param_value_map` to `params`
   // v8::Object.
   static bool CopyParamValueMapToObject(
       v8::Isolate*, v8::Local<v8::Context>,
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
index b79d781..b659c9e9 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
@@ -68,7 +68,7 @@
   bool is_synchronized_ = false;
 
   // The definition is per global scope. The active instance of
-  // |AudioProcessorWorklet| should be passed into these to perform JS function.
+  // AudioProcessorWorklet should be passed into these to perform JS function.
   Member<V8BlinkAudioWorkletProcessorConstructor> constructor_;
   Member<V8BlinkAudioWorkletProcessCallback> process_;
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
index fe29eee..46ea74e 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
@@ -73,7 +73,7 @@
     return thread;
   }
 
-  // Attempts to run some simple script for |thread|.
+  // Attempts to run some simple script for `thread`.
   void CheckWorkletCanExecuteScript(WorkerThread* thread) {
     base::WaitableEvent wait_event;
     PostCrossThreadTask(
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index df9f219d..db6963c 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -122,7 +122,7 @@
     destination_node_->Handler().Initialize();
     // TODO(crbug.com/863951).  The audio thread needs some things from the
     // destination handler like the currentTime.  But the audio thread
-    // shouldn't access the |destination_node_| since it's an Oilpan object.
+    // shouldn't access the `destination_node_` since it's an Oilpan object.
     // Thus, get the destination handler, a non-oilpan object, so we can get
     // the items directly from the handler instead of through the destination
     // node.
@@ -862,7 +862,7 @@
   DCHECK(audioWorklet()->IsReady());
 
   {
-    // |audio_worklet_thread_| is constantly peeked by the rendering thread,
+    // `audio_worklet_thread_` is constantly peeked by the rendering thread,
     // So we protect it with the graph lock.
     GraphAutoLocker locker(this);
 
@@ -885,7 +885,7 @@
   DCHECK(!IsMainThread());
 
   if (TryLock()) {
-    // Even when |audio_worklet_thread_| is successfully assigned, the current
+    // Even when `audio_worklet_thread_` is successfully assigned, the current
     // render thread could still be a thread of AudioOutputDevice.  Updates the
     // the global scope only when the thread affinity is correct.
     if (audio_worklet_thread_ && audio_worklet_thread_->IsCurrentThread()) {
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
index 6b418c39..da56dc7f 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -164,7 +164,7 @@
                                 V8DecodeSuccessCallback*,
                                 ExceptionState&);
 
-  // Handles the promise and callbacks when |decodeAudioData| is finished
+  // Handles the promise and callbacks when `.decodeAudioData()` is finished
   // decoding.
   void HandleDecodeAudioData(AudioBuffer*,
                              ScriptPromiseResolver*,
@@ -237,11 +237,11 @@
   // Called at the start of each render quantum.
   //
   // For an AudioContext:
-  //   - |output_position| must be a valid pointer to an AudioIOPosition
+  //   - `output_position` must be a valid pointer to an AudioIOPosition
   //   - The return value is ignored.
   //
   // For an OfflineAudioContext, we have the following conditions:
-  //   - |output_position| must be nullptr because there is no defined
+  //   - `output_position` must be nullptr because there is no defined
   //   AudioIOPosition.
   //   - The return value indicates whether the context needs to be suspended or
   //   not after rendering.
@@ -370,9 +370,9 @@
   // Returns the Document wich wich the instance is associated.
   Document* GetDocument() const;
 
-  // The audio thread relies on the main thread to perform some operations
-  // over the objects that it owns and controls; |ScheduleMainThreadCleanup()|
-  // posts the task to initiate those.
+  // The audio thread relies on the main thread to perform some operations over
+  // the objects that it owns and controls; this method posts the task to
+  // initiate those.
   void ScheduleMainThreadCleanup();
 
   // Handles promise resolving, stopping and finishing up of audio source nodes
@@ -398,7 +398,7 @@
   // Listener for the PannerNodes
   Member<AudioListener> listener_;
 
-  // Set to |true| by the audio thread when it posts a main-thread task to
+  // Set to `true` by the audio thread when it posts a main-thread task to
   // perform delayed state sync'ing updates that needs to be done on the main
   // thread. Cleared by the main thread task once it has run.
   bool has_posted_cleanup_task_ = false;
@@ -428,7 +428,7 @@
   // It is somewhat arbitrary and could be increased if necessary.
   enum { kMaxNumberOfChannels = 32 };
 
-  // The handler associated with the above |destination_node_|.
+  // The handler associated with the above `destination_node_`.
   scoped_refptr<AudioDestinationHandler> destination_handler_;
 
   Member<AudioWorklet> audio_worklet_;
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.idl b/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
index ffd2965c..d043085 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.idl
@@ -35,7 +35,7 @@
     [RaisesException] AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long numberOfFrames, float sampleRate);
 
     // Asynchronous audio file data decoding.
-    // TODO(crbug.com/841185): |successCallback| and |errorCallback| are not
+    // TODO(crbug.com/841185): `successCallback` and `errorCallback` are not
     // nullable in the spec.
     [RaisesException, MeasureAs=AudioContextDecodeAudioData, CallWith=ScriptState] Promise<AudioBuffer> decodeAudioData(ArrayBuffer audioData, optional DecodeSuccessCallback? successCallback, optional DecodeErrorCallback? errorCallback);
 
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
index 0b0419f..b0995f47f 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
+++ b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
@@ -194,7 +194,7 @@
                                            float* mag_response,
                                            float* phase_response) {
   // Only allow on the main thread because we don't want the audio thread to be
-  // updating |kernel| while we're computing the response.
+  // updating `kernel` while we're computing the response.
   DCHECK(IsMainThread());
 
   DCHECK_GE(n_frequencies, 0);
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.h b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.h
index 9122b59f..e760639 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.h
+++ b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.h
@@ -81,7 +81,7 @@
 
  private:
   // Compute the tail time using the BiquadFilter coefficients at
-  // index |coef_index|.
+  // index `coef_index`.
   void UpdateTailTime(int coef_index);
 
   // Synchronize process() with getting and setting the filter coefficients.
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_processor.cc b/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
index 85f6c976..8853a6c 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
+++ b/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
@@ -93,9 +93,9 @@
       // these methods.  We need to implement another way of noticing if one of
       // the parameters has changed.  We do this as an optimization because
       // computing the filter coefficients from these parameters is fairly
-      // expensive.  NB: The calls to Smooth() don't actually cause the
+      // expensive.  NOTE: The calls to Smooth() don't actually cause the
       // coefficients to be dezippered.  This is just a way to notice that the
-      // coefficient values have changed.  |UpdateCoefficientsIfNecessary()|
+      // coefficient values have changed.  `UpdateCoefficientsIfNecessary()`
       // checks to see if the filter coefficients are dirty and sets the filter
       // to the new value, without smoothing.
       //
@@ -177,8 +177,8 @@
 
   {
     // Get a copy of the current biquad filter coefficients so we can update
-    // |response_kernel| with these values.  We need to synchronize with
-    // |Process()| to prevent process() from updating the filter coefficients
+    // `response_kernel` with these values.  We need to synchronize with
+    // `Process()` to prevent process() from updating the filter coefficients
     // while we're trying to access them.  Since this is on the main thread, we
     // can wait.  The audio thread will update the coefficients the next time
     // around, it it were blocked.
diff --git a/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc b/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
index 75850eb3..17995111 100644
--- a/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
+++ b/third_party/blink/renderer/modules/webaudio/cpu/x86/oscillator_kernel_sse2.cc
@@ -13,13 +13,13 @@
 static __m128 WrapVirtualIndexVector(__m128 x,
                                      __m128 wave_size,
                                      __m128 inv_wave_size) {
-  // Wrap the virtual index |x| to the range 0 to wave_size - 1.  This is done
-  // by computing x - floor(x/wave_size)*wave_size.
+  // Wrap the virtual index `x` to the range 0 to wave_size - 1.  This is done
+  // by computing `x` - floor(`x`/`wave_size`)*`wave_size`.
   //
   // But there's no SSE2 SIMD instruction for this, so we do it the following
   // way.
 
-  // f = truncate(x/wave_size), truncating towards 0.
+  // `f` = truncate(`x`/`wave_size`), truncating towards 0.
   const __m128 r = _mm_mul_ps(x, inv_wave_size);
   __m128i f = _mm_cvttps_epi32(r);
 
@@ -158,13 +158,13 @@
 static __m128d WrapVirtualIndexVectorPd(__m128d x,
                                         __m128d wave_size,
                                         __m128d inv_wave_size) {
-  // Wrap the virtual index |x| to the range 0 to wave_size - 1.  This is done
-  // by computing x - floor(x/wave_size)*wave_size.
+  // Wrap the virtual index `x` to the range 0 to wave_size - 1.  This is done
+  // by computing `x` - floor(`x`/`wave_size`)*`wave_size`.
   //
   // But there's no SSE2 SIMD instruction for this, so we do it the following
   // way.
 
-  // f = truncate(x/wave_size), truncating towards 0.
+  // `f` = truncate(`x`/`wave_size`), truncating towards 0.
   const __m128d r = _mm_mul_pd(x, inv_wave_size);
   __m128i f = _mm_cvttpd_epi32(r);
 
diff --git a/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h b/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h
index e24bcff..f0b147b 100644
--- a/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h
+++ b/third_party/blink/renderer/modules/webaudio/cross_thread_audio_worklet_processor_info.h
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-// A class for shallow repackage of |AudioParamDescriptor|. This is created only
+// A class for shallow repackage of AudioParamDescriptor. This is created only
 // when requested when the synchronization between AudioWorkletMessagingProxy
 // and AudioWorkletGlobalScope.
 class CrossThreadAudioParamInfo {
@@ -39,7 +39,7 @@
   const String name_;
 };
 
-// A class for shallow repackage of |AudioWorkletProcessorDefinition|. This is
+// A class for shallow repackage of AudioWorkletProcessorDefinition. This is
 // created only when requested when the synchronization between
 // AudioWorkletMessagingProxy and AudioWorkletGlobalScope.
 class CrossThreadAudioWorkletProcessorInfo {
diff --git a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
index 0926026..597ff80 100644
--- a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
@@ -343,8 +343,8 @@
   AssertGraphOwner();
 
   // Quick exit if there are no handlers that need to be deleted so that we
-  // don't unecessarily post a task.  Be consistent with
-  // |DeleteHandlersOnMainThread()| so we don't accidentally return early when
+  // don't unnecessarily post a task.  Be consistent with
+  // `DeleteHandlersOnMainThread()` so we don't accidentally return early when
   // there are handlers that could be deleted.
   if (rendering_orphan_handlers_.IsEmpty() &&
       finished_tail_processing_handlers_.size() == 0) {
@@ -386,7 +386,7 @@
 void DeferredTaskHandler::ClearContextFromOrphanHandlers() {
   DCHECK(IsMainThread());
 
-  // |rendering_orphan_handlers_| and |deletable_orphan_handlers_| can
+  // `rendering_orphan_handlers_` and `deletable_orphan_handlers_` can
   // be modified on the audio thread.
   GraphAutoLocker locker(*this);
 
@@ -427,16 +427,16 @@
 
   // TODO(crbug.com/832200): Simplify this!
 
-  // |DisableOutputs()| can cause new handlers to start tail processing, which
+  // `DisableOutputs()` can cause new handlers to start tail processing, which
   // in turn can cause hte handler to want to disable outputs.  For the former
-  // case, the handler is added to |tail_processing_handlers_|.  In the latter
-  // case, the handler is added to |finished_tail_processing_handlers_|.  So, we
+  // case, the handler is added to `tail_processing_handlers_`.  In the latter
+  // case, the handler is added to `finished_tail_processing_handlers_`.  So, we
   // need to loop around until these vectors are completely empty.
   do {
     while (tail_processing_handlers_.size() > 0) {
-      // |DisableOutputs()| can modify |tail_processing_handlers_|, so
+      // `DisableOutputs()` can modify `tail_processing_handlers_`, so
       // swap it out before processing it.  And keep running this until
-      // nothing gets added to |tail_processing_handlers_|.
+      // nothing gets added to `tail_processing_handlers_`.
       Vector<scoped_refptr<AudioHandler>> handlers_to_be_disabled;
 
       handlers_to_be_disabled.swap(tail_processing_handlers_);
diff --git a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
index 81d0f7c..f147d020 100644
--- a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.h
@@ -119,14 +119,14 @@
   bool AcceptsTailProcessing() const { return accepts_tail_processing_; }
   void StopAcceptingTailProcessing() { accepts_tail_processing_ = false; }
 
-  // If |node| requires tail processing, add it to the list of tail
+  // If `node` requires tail processing, add it to the list of tail
   // nodes so the tail is processed.
   void AddTailProcessingHandler(scoped_refptr<AudioHandler>);
 
-  // Remove |node| from the list of tail nodes (because the tail processing is
-  // complete).  Set |disable_outputs| to true if the outputs of the handler
+  // Remove `node` from the list of tail nodes (because the tail processing is
+  // complete).  Set `disable_outputs` to true if the outputs of the handler
   // should also be disabled.  This should be true if the tail is done.  But if
-  // we're reconnected or re-enabled, then |disable_outputs| should be false.
+  // we're reconnected or re-enabled, then `disable_outputs` should be false.
   void RemoveTailProcessingHandler(AudioHandler*, bool disable_outputs);
 
   // Remove all tail processing nodes.  Should be called only when the
@@ -221,13 +221,13 @@
 
   // For the sake of thread safety, we maintain a seperate Vector of
   // AudioHandlers for "automatic-pull nodes":
-  // |rendering_automatic_pull_handlers|. This storage will be copied from
-  // |automatic_pull_handlers| by |UpdateAutomaticPullNodes()| at the beginning
+  // `rendering_automatic_pull_handlers_`. This storage will be copied from
+  // `automatic_pull_handlers` by `UpdateAutomaticPullNodes()` at the beginning
   // or end of the render quantum.
   HashSet<scoped_refptr<AudioHandler>> automatic_pull_handlers_;
   Vector<scoped_refptr<AudioHandler>> rendering_automatic_pull_handlers_;
 
-  // Keeps track if the |automatic_pull_handlers| storage is touched.
+  // Keeps track if the `automatic_pull_handlers` storage is touched.
   bool automatic_pull_handlers_need_updating_ = false;
 
   // Number of frames to use when rendering the graph.  This is the frames to
@@ -272,7 +272,7 @@
 
   // When source nodes are finished, the handler is placed here to make a note
   // of it.  At a render quantum boundary, these are used to break the
-  // connection and elements here are removed from |active_source_handlers_|.
+  // connection and elements here are removed from `active_source_handlers_`.
   //
   // This must be accessed only from the audio thread.
   Vector<scoped_refptr<AudioHandler>> finished_source_handlers_;
@@ -282,8 +282,8 @@
   // Graph locking.
   RecursiveMutex context_graph_mutex_;
 
-  // Protects |rendering_automatic_pull_handlers| when updating, processing, and
-  // clearing. (See crbug.com/1061018)
+  // Protects `rendering_automatic_pull_handlers_` when updating, processing,
+  // and clearing. (See crbug.com/1061018)
   mutable Mutex automatic_pull_handlers_lock_;
 
   std::atomic<base::PlatformThreadId> audio_thread_;
diff --git a/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc b/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
index 57eeb2c..25857bf 100644
--- a/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/iir_filter_node.cc
@@ -76,8 +76,8 @@
                                       is_filter_stable));
 
   // Histogram of the IIRFilter order.  createIIRFilter ensures that the length
-  // of |feedbackCoef| is in the range [1, IIRFilter::kMaxOrder + 1].  The order
-  // is one less than the length of this vector.
+  // of `feedback_coef` is in the range [1, IIRFilter::kMaxOrder + 1].  The
+  // order is one less than the length of this vector.
   base::UmaHistogramSparse("WebAudio.IIRFilterNode.Order",
                            feedback_coef.size() - 1);
 }
@@ -192,7 +192,7 @@
   size_t frequency_hz_length = frequency_hz->length();
 
   // All the arrays must have the same length.  Just verify that all
-  // the arrays have the same length as the |frequency_hz| array.
+  // the arrays have the same length as the `frequency_hz` array.
   if (mag_response->length() != frequency_hz_length) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidAccessError,
diff --git a/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc b/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
index 53beec6e..d9977d3 100644
--- a/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
+++ b/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
@@ -45,7 +45,7 @@
 }
 
 // Strips out the prefix and returns the actual parameter name. If the name
-// does not match |NodeName.ParamName| pattern, returns "Unknown" instead.
+// does not match `NodeName.ParamName` pattern, returns "Unknown" instead.
 String StripParamPrefix(const String& paramName) {
   Vector<String> name_tokens;
   paramName.Split('.', name_tokens);
diff --git a/third_party/blink/renderer/modules/webaudio/media_element_audio_source_handler.cc b/third_party/blink/renderer/modules/webaudio/media_element_audio_source_handler.cc
index 66367fd..da584573 100644
--- a/third_party/blink/renderer/modules/webaudio/media_element_audio_source_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/media_element_audio_source_handler.cc
@@ -93,8 +93,8 @@
   }
 
   {
-    // Make sure |is_origin_tainted_| matches |is_tainted|.  But need to
-    // synchronize with process() to set this.
+    // Make sure `is_origin_tainted_` matches `is_tainted`.  But need to
+    // synchronize with `Process()` to set this.
     MediaElementAudioSourceHandlerLocker locker(*this);
     is_origin_tainted_ = is_tainted;
   }
@@ -104,18 +104,18 @@
     if (!number_of_channels ||
         number_of_channels > BaseAudioContext::MaxNumberOfChannels() ||
         !audio_utilities::IsValidAudioBufferSampleRate(source_sample_rate)) {
-      // process() will generate silence for these uninitialized values.
+      // `Process()` will generate silence for these uninitialized values.
       DLOG(ERROR) << "setFormat(" << number_of_channels << ", "
                   << source_sample_rate << ") - unhandled format change";
-      // Synchronize with process().
+      // Synchronize with `Process()`.
       MediaElementAudioSourceHandlerLocker locker(*this);
       source_number_of_channels_ = 0;
       source_sample_rate_ = 0;
       return;
     }
 
-    // Synchronize with process() to protect |source_number_of_channels_|,
-    // |source_sample_rate_|, |multi_channel_resampler_|.
+    // Synchronize with `Process()` to protect `source_number_of_channels_`,
+    // `source_sample_rate_`, `multi_channel_resampler_`.
     MediaElementAudioSourceHandlerLocker locker(*this);
 
     source_number_of_channels_ = number_of_channels;
diff --git a/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
index 5cd91ffb..ca6c4f4 100644
--- a/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
@@ -127,7 +127,7 @@
   if (!context->CheckExecutionContextAndThrowIfNecessary(exception_state)) {
     return nullptr;
   }
-  // Default to stereo; |options| will update it appropriately if needed.
+  // Default to stereo; `options` will update it appropriately if needed.
   MediaStreamAudioDestinationNode* node =
       MakeGarbageCollected<MediaStreamAudioDestinationNode>(*context, 2);
 
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
index 03e1426b..74dd3b2 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
@@ -388,7 +388,7 @@
 bool OfflineAudioContext::HandlePreRenderTasks(
     const AudioIOPosition* output_position,
     const AudioCallbackMetric* metric) {
-  // TODO(hongchan, rtoy): passing |nullptr| as an argument is not a good
+  // TODO(hongchan): passing `nullptr` as an argument is not a good
   // pattern. Consider rewriting this method/interface.
   DCHECK_EQ(output_position, nullptr);
   DCHECK_EQ(metric, nullptr);
@@ -410,7 +410,7 @@
   DCHECK(IsAudioThread());
 
   // OfflineGraphAutoLocker here locks the audio graph for the same reason
-  // above in |handlePreOfflineRenderTasks|.
+  // above in `HandlePreRenderTasks()`.
   {
     OfflineGraphAutoLocker locker(this);
 
@@ -444,7 +444,7 @@
     // If the context is going away, m_scheduledSuspends could have had all its
     // entries removed.  Check for that here.
     if (scheduled_suspends_.size()) {
-      // |frame| must exist in the map.
+      // `frame` must exist in the map.
       DCHECK(scheduled_suspends_.Contains(frame));
 
       SuspendMap::iterator it = scheduled_suspends_.find(frame);
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context.h b/third_party/blink/renderer/modules/webaudio/offline_audio_context.h
index ad8f5f07..9fa0d7e 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context.h
@@ -91,7 +91,7 @@
   // OfflineAudioContext is not affected by Autoplay, so this MUST do nothing.
   void NotifySourceNodeStart() final {}
 
-  // The HashMap with 'zero' key is needed because |currentSampleFrame| can be
+  // The HashMap with 'zero' key is needed because `CurrentSampleFrame()` can be
   // zero.
   using SuspendMap = HeapHashMap<size_t,
                                  Member<ScriptPromiseResolver>,
@@ -115,17 +115,17 @@
   // main thread and accessed by the audio thread with the graph lock.
   //
   // The map consists of key-value pairs of:
-  // { size_t quantizedFrame: ScriptPromiseResolver resolver }
+  // { size_t quantized_frame: ScriptPromiseResolver resolver }
   //
-  // Note that |quantizedFrame| is a unique key, since you can have only one
+  // Note that `quantized_frame` is a unique key, since you can have only one
   // suspend scheduled for a certain frame. Accessing to this must be
   // protected by the offline context lock.
   SuspendMap scheduled_suspends_;
 
-  // Protects |scheduled_suspend_frames_|.
+  // Protects `scheduled_suspend_frames_`.
   Mutex suspend_frames_lock_;
 
-  // Holds copies of |quantizedFrame| in |schedueld_suspends_| to ensure
+  // Holds copies of `quantized_frame` in `schedueld_suspends_` to ensure
   // a safe access from the audio thread.
   HashSet<size_t,
           WTF::DefaultHash<size_t>::Hash,
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc
index 24446af..15bd65b2 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.cc
@@ -107,7 +107,7 @@
   }
 
   // Rendering is already started, which implicitly means we resume the
-  // rendering by calling |doOfflineRendering| on the render thread.
+  // rendering by calling `DoOfflineRendering()` on the render thread.
   PostCrossThreadTask(
       *render_thread_task_runner_, FROM_HERE,
       CrossThreadBindOnce(&OfflineAudioDestinationHandler::DoOfflineRendering,
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h
index 21f6884..b2afe1b 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_handler.h
@@ -52,7 +52,7 @@
   double SampleRate() const override { return sample_rate_; }
 
   // This is called when rendering of the offline context is started
-  // which will save the rendered audio data in |render_target|.  This
+  // which will save the rendered audio data in `render_target`.  This
   // allows creation of the AudioBuffer when startRendering is called
   // instead of when the OfflineAudioContext is created.
   void InitializeOfflineRenderThread(AudioBuffer* render_target);
@@ -68,7 +68,7 @@
                                  float sample_rate);
 
   // Set up the rendering and start. After setting the context up, it will
-  // eventually call |doOfflineRendering|.
+  // eventually call `DoOfflineRendering()`.
   void StartOfflineRendering();
 
   // Suspend the rendering loop and notify the main thread to resolve the
@@ -106,8 +106,8 @@
   //    When the main thread starts deleting this object, a task posted with
   //    a WeakPtr from the rendering thread will be cancelled.
   // 2. main thread -> rendering thread: scoped_refptr
-  //    |render_thread_| is owned by this object, so it is safe to target with
-  //    WrapRefCounted() instead of GetWeakPtr().
+  //    `render_thread_` is owned by this object, so it is safe to target with
+  //    `WrapRefCounted()` instead of `GetWeakPtr()`.
   base::WeakPtr<OfflineAudioDestinationHandler> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
diff --git a/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc b/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc
index 58455c6..b294624 100644
--- a/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/oscillator_handler.cc
@@ -250,11 +250,11 @@
   unsigned read_index_0 = static_cast<unsigned>(virtual_read_index);
 
   // Consider a typical sample rate of 44100 Hz and max periodic wave
-  // size of 4096.  The relationship between |incr| and the frequency
-  // of the oscillator is |incr| = freq * 4096/44100. Or freq =
-  // |incr|*44100/4096 = 10.8*|incr|.
+  // size of 4096.  The relationship between `incr` and the frequency
+  // of the oscillator is `incr` = freq * 4096/44100. Or freq =
+  // `incr`*44100/4096 = 10.8*`incr`.
   //
-  // For the |incr| thresholds below, this means that we use linear
+  // For the `incr` thresholds below, this means that we use linear
   // interpolation for all freq >= 3.2 Hz, 3-point Lagrange
   // for freq >= 1.7 Hz and 5-point Lagrange for every thing else.
   //
diff --git a/third_party/blink/renderer/modules/webaudio/periodic_wave.cc b/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
index 2f7f86f6b..84619e6 100644
--- a/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
+++ b/third_party/blink/renderer/modules/webaudio/periodic_wave.cc
@@ -113,11 +113,11 @@
       imag_coef.resize(real_coef.size());
     }
   } else if (options->hasImag()) {
-    // |real| not given, but we have |imag|.
+    // `real()` not given, but we have `imag()`.
     imag_coef = options->imag();
     real_coef.resize(imag_coef.size());
   } else {
-    // Neither |real| nor |imag| given.  Return an object that would
+    // Neither `real()` nor `imag()` given.  Return an object that would
     // generate a sine wave, which means real = [0,0], and imag = [0, 1]
     real_coef.resize(2);
     imag_coef.resize(2);
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_analyser.h b/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
index dc78c60..4d385793 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
+++ b/third_party/blink/renderer/modules/webaudio/realtime_analyser.h
@@ -96,11 +96,11 @@
   std::unique_ptr<FFTFrame> analysis_frame_;
   void DoFFTAnalysis();
 
-  // Convert the contents of magnitudeBuffer to byte values, saving the result
-  // in |destination|.
+  // Convert the contents of `magnitude_buffer_` to byte values, saving the
+  // result in `destination`.
   void ConvertToByteData(DOMUint8Array* destination);
 
-  // Convert magnidue buffer to dB, saving the result in |destination|
+  // Convert `magnitude_buffer_` to dB, saving the result in `destination`
   void ConvertFloatToDb(DOMFloat32Array* destination);
 
   // doFFTAnalysis() stores the floating-point magnitude analysis data here.
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
index 69bfdf1..25862bbd 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
@@ -151,7 +151,7 @@
 
 double RealtimeAudioDestinationHandler::SampleRate() const {
   // This can be accessed from both threads (main and audio), so it is
-  // possible that |platform_destination_| is not fully functional when it
+  // possible that `platform_destination_` is not fully functional when it
   // is accssed by the audio thread.
   return platform_destination_ ? platform_destination_->SampleRate() : 0;
 }
@@ -171,7 +171,7 @@
 
   // A sanity check for the associated context, but this does not guarantee the
   // safe execution of the subsequence operations because the handler holds
-  // the context as |UntracedMember| and it can go away anytime.
+  // the context as UntracedMember and it can go away anytime.
   DCHECK(context);
   if (!context) {
     return;
@@ -205,7 +205,7 @@
       destination_bus->Zero();
     } else if (rendered_bus != destination_bus) {
       // In-place processing was not possible. Copy the rendered result to the
-      // given |destination_bus| buffer.
+      // given `destination_bus` buffer.
       destination_bus->CopyFrom(*rendered_bus);
     }
   } else {
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.h b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.h
index 6d18faf..a90d942 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.h
@@ -51,8 +51,8 @@
   double SampleRate() const override;
 
   // For AudioIOCallback. This is invoked by the platform audio destination to
-  // get the next render quantum into |destination_bus| and update
-  // |output_position|.
+  // get the next render quantum into `destination_bus` and update
+  // `output_position`.
   void Render(AudioBus* destination_bus,
               uint32_t number_of_frames,
               const AudioIOPosition& output_position,
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_handler.cc b/third_party/blink/renderer/modules/webaudio/script_processor_handler.cc
index 041cb1f..3c1ad9b 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_handler.cc
@@ -109,12 +109,12 @@
                      "ScriptProcessorHandler::Process");
 
   // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
-  // and output (i.e. |input_bus| and |output_bus|). Additionally, there is a
+  // and output (i.e. `input_bus` and `output_bus`). Additionally, there is a
   // double-buffering for input and output that are exposed directly to
-  // JavaScript (i.e. |inputBuffer| and |outputBuffer| in
-  // |AudioProcessingEvent|). This node is the producer for |inputBuffer| and
-  // the consumer for |outputBuffer|. The |AudioProcessingEvent| is the
-  // consumer of |inputBuffer| and the producer for |outputBuffer|.
+  // JavaScript (i.e. `.inputBuffer` and `.outputBuffer` in
+  // AudioProcessingEvent). This node is the producer for `.inputBuffer` and the
+  // consumer for `.outputBuffer`. The AudioProcessingEvent is the consumer of
+  // `.inputBuffer` and the producer for `.outputBuffer`.
 
   scoped_refptr<AudioBus> input_bus = Input(0).Bus();
   AudioBus* output_bus = Output(0).Bus();
@@ -134,15 +134,15 @@
       buffer_read_write_index_ + frames_to_process <= BufferSize();
 
   if (internal_input_bus_->NumberOfChannels()) {
-    // If the number of input channels is zero, the zero length |inputBuffer|
-    // is fine.
+    // If the number of input channels is zero, the zero length input buffer is
+    // fine.
     buffers_are_good = buffers_are_good && shared_input_buffer &&
                        BufferSize() == shared_input_buffer->length();
   }
 
   DCHECK(buffers_are_good);
 
-  // |BufferSize()| should be evenly divisible by |frames_to_process|.
+  // `BufferSize()` should be evenly divisible by `frames_to_process`.
   DCHECK_GT(frames_to_process, 0u);
   DCHECK_GE(BufferSize(), frames_to_process);
   DCHECK_EQ(BufferSize() % frames_to_process, 0u);
@@ -170,8 +170,8 @@
                  "ScriptProcessorHandler::Process - data copy under lock",
                  "double_buffer_index", double_buffer_index);
 
-    // It is possible that the length of |internal_input_bus_| and
-    // |input_bus| can be different. See crbug.com/1189528.
+    // It is possible that the length of `internal_input_bus_` and
+    // `input_bus` can be different. See crbug.com/1189528.
     for (uint32_t i = 0; i < number_of_input_channels; ++i) {
       internal_input_bus_->SetChannelMemory(
           i,
@@ -201,7 +201,7 @@
                        TRACE_EVENT_SCOPE_THREAD, "buffer_read_write_index_",
                        buffer_read_write_index_);
 
-  // Fire an event and swap buffers when |buffer_read_write_index_| wraps back
+  // Fire an event and swap buffers when `buffer_read_write_index_` wraps back
   // around to 0. It means the current input and output buffers are full.
   if (!buffer_read_write_index_) {
     if (Context()->HasRealtimeConstraint()) {
@@ -243,8 +243,8 @@
   // Avoid firing the event if the document has already gone away.
   if (GetNode()) {
     // Calculate a playbackTime with the buffersize which needs to be processed
-    // each time onaudioprocess is called.  The outputBuffer being passed to JS
-    // will be played after exhuasting previous outputBuffer by
+    // each time onaudioprocess is called.  The `.outputBuffer` being passed to
+    // JS will be played after exhuasting previous `.outputBuffer` by
     // double-buffering.
     double playback_time = (Context()->CurrentSampleFrame() + buffer_size_) /
                            static_cast<double>(Context()->sampleRate());
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_handler.h b/third_party/blink/renderer/modules/webaudio/script_processor_handler.h
index 08fd4f8..ea2ff66 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_handler.h
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_handler.h
@@ -77,7 +77,7 @@
   void SwapBuffers() { double_buffer_index_ = 1 - double_buffer_index_; }
   uint32_t double_buffer_index_ = 0;
 
-  // Protects |shared_input_buffers| and |shared_output_buffers_|.
+  // Protects `shared_input_buffers_` and `shared_output_buffers_`.
   mutable Mutex buffer_lock_;
   WTF::Vector<std::unique_ptr<SharedAudioBuffer>> shared_input_buffers_;
   WTF::Vector<std::unique_ptr<SharedAudioBuffer>> shared_output_buffers_;
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index 77155b1..6cafa88 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -264,10 +264,10 @@
     AudioBuffer* backing_input_buffer =
         input_buffers_.at(double_buffer_index).Get();
 
-    // The backing buffer can be |nullptr|, when the number of input channels
+    // The backing buffer can be `nullptr`, when the number of input channels
     // is 0.
     if (backing_input_buffer) {
-      // Also the author code might have transferred |external_input_buffer| to
+      // Also the author code might have transferred `external_input_buffer_` to
       // other threads or replaced it with a different AudioBuffer object. Then
       // re-create a new buffer instance.
       if (IsAudioBufferDetached(external_input_buffer_) ||
@@ -341,7 +341,7 @@
     return false;
   }
 
-  // If |onaudioprocess| event handler is defined, the node should not be
+  // If `.onaudioprocess` event handler is defined, the node should not be
   // GCed even if it is out of scope.
   if (HasEventListeners(event_type_names::kAudioprocess)) {
     return true;
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 99c913e..fd695ce2 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -194,11 +194,12 @@
   return map;
 }
 
-ResourceLoadPriority AdjustPriorityWithPriorityHint(
+ResourceLoadPriority AdjustPriorityWithPriorityHintAndRenderBlocking(
     ResourceLoadPriority priority_so_far,
     ResourceType type,
     const ResourceRequestHead& resource_request,
     FetchParameters::DeferOption defer_option,
+    RenderBlockingBehavior render_blocking_behavior,
     bool is_link_preload) {
   mojom::blink::FetchPriorityHint fetch_priority_hint =
       resource_request.GetFetchPriorityHint();
@@ -233,6 +234,13 @@
       break;
   }
 
+  // Render-blocking is a signal that the resource is important, so we bump it
+  // to at least kHigh.
+  if (render_blocking_behavior == RenderBlockingBehavior::kBlocking &&
+      new_priority < ResourceLoadPriority::kHigh) {
+    new_priority = ResourceLoadPriority::kHigh;
+  }
+
   return new_priority;
 }
 
@@ -400,6 +408,7 @@
     ResourcePriority::VisibilityStatus visibility,
     FetchParameters::DeferOption defer_option,
     FetchParameters::SpeculativePreloadType speculative_preload_type,
+    RenderBlockingBehavior render_blocking_behavior,
     bool is_link_preload) {
   DCHECK(!resource_request.PriorityHasBeenSet() ||
          type == ResourceType::kImage);
@@ -470,8 +479,9 @@
     }
   }
 
-  priority = AdjustPriorityWithPriorityHint(priority, type, resource_request,
-                                            defer_option, is_link_preload);
+  priority = AdjustPriorityWithPriorityHintAndRenderBlocking(
+      priority, type, resource_request, defer_option, render_blocking_behavior,
+      is_link_preload);
 
   if (properties_->IsSubframeDeprioritizationEnabled()) {
     if (properties_->IsOutermostMainFrame()) {
@@ -873,7 +883,8 @@
     computed_load_priority = ComputeLoadPriority(
         resource_type, params.GetResourceRequest(),
         ResourcePriority::kNotVisible, params.Defer(),
-        params.GetSpeculativePreloadType(), params.IsLinkPreload());
+        params.GetSpeculativePreloadType(), params.GetRenderBlockingBehavior(),
+        params.IsLinkPreload());
   }
 
   DCHECK_NE(computed_load_priority, ResourceLoadPriority::kUnresolved);
@@ -2229,10 +2240,7 @@
   resource_request.SetRequestDestination(request_destination);
   if (!resource_request.PriorityHasBeenSet()) {
     resource_request.SetPriority(ComputeLoadPriority(
-        resource->GetType(), resource_request, ResourcePriority::kNotVisible,
-        FetchParameters::DeferOption::kNoDefer,
-        FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */));
+        resource->GetType(), resource_request, ResourcePriority::kNotVisible));
   }
   resource_request.SetReferrerString(Referrer::NoReferrer());
   resource_request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
index 86450480..c8f24b7 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -294,9 +294,11 @@
       ResourcePriority::VisibilityStatus visibility_statue,
       FetchParameters::DeferOption defer_option,
       FetchParameters::SpeculativePreloadType speculative_preload_type,
+      RenderBlockingBehavior render_blocking_behavior,
       bool is_link_preload) {
     return ComputeLoadPriority(type, request, visibility_statue, defer_option,
-                               speculative_preload_type, is_link_preload);
+                               speculative_preload_type,
+                               render_blocking_behavior, is_link_preload);
   }
 
   void SetThrottleOptionOverride(
@@ -339,6 +341,7 @@
       FetchParameters::DeferOption = FetchParameters::DeferOption::kNoDefer,
       FetchParameters::SpeculativePreloadType =
           FetchParameters::SpeculativePreloadType::kNotSpeculative,
+      RenderBlockingBehavior = RenderBlockingBehavior::kNonBlocking,
       bool is_link_preload = false);
 
   // |virtual_time_pauser| is an output parameter. PrepareRequest may
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 695bf719..3fe4c19 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -1289,7 +1289,7 @@
         ResourceType::kScript, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kHigh);
   }
 
@@ -1301,7 +1301,7 @@
         ResourceType::kScript, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kHigh);
   }
 
@@ -1313,7 +1313,7 @@
         ResourceType::kScript, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kHigh);
   }
 
@@ -1325,7 +1325,7 @@
         ResourceType::kScript, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kLow);
   }
   {
@@ -1336,7 +1336,7 @@
         ResourceType::kMock, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kMedium);
   }
 
@@ -1349,7 +1349,7 @@
         ResourceType::kMock, request, ResourcePriority::kNotVisible,
         FetchParameters::DeferOption::kNoDefer,
         FetchParameters::SpeculativePreloadType::kNotSpeculative,
-        false /* is_link_preload */);
+        RenderBlockingBehavior::kNonBlocking, false /* is_link_preload */);
     EXPECT_EQ(priority, ResourceLoadPriority::kLowest);
   }
 }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory_test.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory_test.cc
index 7cda073..2a036683 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder_factory_test.cc
@@ -45,9 +45,11 @@
   GetVideoEncodeAcceleratorSupportedProfiles() override {
     media::VideoEncodeAccelerator::SupportedProfiles profiles = {
         {media::VP8PROFILE_ANY, kMaxResolution, kMaxFramerateNumerator,
-         kMaxFramerateDenominator, kScalabilityModes},
+         kMaxFramerateDenominator, media::VideoEncodeAccelerator::kConstantMode,
+         kScalabilityModes},
         {media::VP9PROFILE_PROFILE0, kMaxResolution, kMaxFramerateNumerator,
-         kMaxFramerateDenominator, kScalabilityModes}};
+         kMaxFramerateDenominator, media::VideoEncodeAccelerator::kConstantMode,
+         kScalabilityModes}};
     return profiles;
   }
 };
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index e43d331..f047a35 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3882,8 +3882,10 @@
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-004.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-003.html [ Failure ]
 crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-columns-001.html [ Failure ]
+crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-columns-composition.html [ Failure ]
 crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-columns-interpolation.html [ Failure ]
 crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-rows-001.html [ Failure ]
+crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-rows-composition.html [ Failure ]
 crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-rows-interpolation.html [ Failure ]
 crbug.com/1045599 external/wpt/css/css-grid/grid-definition/grid-repeat-max-width-001.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-composition.html b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-composition.html
new file mode 100644
index 0000000..2db49bc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-composition.html
@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>grid-template-columns composition</title>
+    <link rel="help" href="https://drafts.csswg.org/css-grid/#track-sizing">
+    <meta name="assert" content="grid-template-columns supports composition.">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/css/support/interpolation-testcommon.js"></script>
+  </head>
+  <body>
+    <script>
+      'use strict';
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '50px 10%',
+        addFrom: '100px 100px',
+        addTo: '200px 20%',
+      }, [
+        {at: -0.3, expect: '120px calc(130px + 4%)'},
+        {at: 0, expect: '150px calc(100px + 10%)'},
+        {at: 0.5, expect: '200px calc(50px + 20%)'},
+        {at: 1, expect: '250px 30%'},
+        {at: 1.5, expect: '300px calc(-50px + 40%)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 2fr',
+        addTo: '2fr 1fr',
+      }, [
+        {at: -0.5, expect: '1.5fr 3.5fr'},
+        {at: 0, expect: '2fr 3fr'},
+        {at: 0.5, expect: '2.5fr 2.5fr'},
+        {at: 1, expect: '3fr 2fr'},
+        {at: 1.5, expect: '3.5fr 1.5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '50px',
+        addFrom: '100px',
+        replaceTo: '200px',
+      }, [
+        {at: -0.3, expect: '135px'},
+        {at: 0, expect: '150px'},
+        {at: 0.5, expect: '175px'},
+        {at: 1, expect: '200px'},
+        {at: 1.5, expect: '225px'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr',
+        addFrom: '1fr',
+        replaceTo: '3fr',
+      }, [
+        {at: -0.5, expect: '1.5fr'},
+        {at: 0, expect: '2fr'},
+        {at: 0.5, expect: '2.5fr'},
+        {at: 1, expect: '3fr'},
+        {at: 1.5, expect: '3.5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 1fr',
+        addTo: '3fr auto',
+      }, [
+        {at: -0.5, expect: '1fr 2fr'},
+        {at: 0, expect: '2fr 2fr'},
+        {at: 0.5, expect: '3fr auto'},
+        {at: 1, expect: '4fr auto'},
+        {at: 1.5, expect: '5fr auto'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: '1fr auto',
+        addTo: '3fr 3fr',
+      }, [
+        {at: -0.5, expect: '1fr auto'},
+        {at: 0, expect: '2fr auto'},
+        {at: 0.5, expect: '3fr 4fr'},
+        {at: 1, expect: '4fr 4fr'},
+        {at: 1.5, expect: '5fr 4fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr auto',
+        addFrom: '1fr 1fr',
+        addTo: '3fr 3fr',
+      }, [
+        {at: -0.5, expect: '1fr 0fr'},
+        {at: 0, expect: '2fr 1fr'},
+        {at: 0.5, expect: '3fr 2fr'},
+        {at: 1, expect: '4fr 3fr'},
+        {at: 1.5, expect: '5fr 4fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '0fr repeat(2, 0fr 10px) 1fr',
+        addFrom: "1fr repeat(2, 1fr 20px) 1fr",
+        addTo: "2fr repeat(2, 3fr 40px) 3fr"
+      }, [
+        {at: -0.3, expect: "0.7fr repeat(2, 0.4fr 24px) 1.4fr"},
+        {at: 0, expect: "1fr repeat(2, 1fr 30px) 2fr"},
+        {at: 0.5, expect: "1.5fr repeat(2, 2fr 40px) 3fr"},
+        {at: 1, expect: "2fr repeat(2, 3fr 50px) 4fr"},
+        {at: 1.5, expect: "2.5fr repeat(2, 4fr 60px) 5fr"}
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: '1fr [a b] 1fr [d]',
+        addTo: '3fr [c] 3fr',
+      }, [
+        {at: -0.5, expect: '1fr [ a b ] 1fr [d]'},
+        {at: 0, expect: '2fr [ a b ] 2fr [d]'},
+        {at: 0.5, expect: '3fr [c] 3fr'},
+        {at: 1, expect: '4fr [c] 4fr'},
+        {at: 1.5, expect: '5fr [c] 5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: 'fit-content(5px) fit-content(20px)',
+        addFrom: 'fit-content(5px) fit-content(20px)',
+        addTo: 'fit-content(15px) max-content',
+      }, [
+        {at: -0.5, expect: 'fit-content(5px) fit-content(40px)'},
+        {at: 0, expect: 'fit-content(10px) fit-content(40px)'},
+        {at: 0.5, expect: 'fit-content(15px) max-content'},
+        {at: 1, expect: 'fit-content(20px) max-content'},
+        {at: 1.5, expect: 'fit-content(25px) max-content'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: 'minmax(5px, 1fr) minmax(10px, 2fr)',
+        addFrom: 'minmax(5px, 1fr) minmax(10px, 2fr)',
+        addTo: 'minmax(15px, 3fr) minmax(30px, auto)',
+      }, [
+        {at: -0.5, expect: 'minmax(5px, 1fr) minmax(10px, 4fr)'},
+        {at: 0, expect: 'minmax(10px, 2fr) minmax(20px, 4fr)'},
+        {at: 0.5, expect: 'minmax(15px, 3fr) minmax(30px, auto)'},
+        {at: 1, expect: 'minmax(20px, 4fr) minmax(40px, auto)'},
+        {at: 1.5, expect: 'minmax(25px, 5fr) minmax(50px, auto)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: 'none',
+        addTo: '1fr 1fr',
+      }, [
+        {at: -0.5, expect: 'none'},
+        {at: 0, expect: 'none'},
+        {at: 0.3, expect: 'none'},
+        {at: 0.5, expect: '2fr 2fr'},
+        {at: 0.7, expect: '2fr 2fr'},
+        {at: 1, expect: '2fr 2fr'},
+        {at: 1.5, expect: '2fr 2fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 1fr',
+        addTo: 'none',
+      }, [
+        {at: -0.5, expect: '2fr 2fr'},
+        {at: 0, expect: '2fr 2fr'},
+        {at: 0.3, expect: '2fr 2fr'},
+        {at: 0.5, expect: 'none'},
+        {at: 0.7, expect: 'none'},
+        {at: 1, expect: 'none'},
+        {at: 1.5, expect: 'none'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '1fr 1fr 1fr',
+        addFrom: '1fr 1fr 1fr',
+        addTo: '2fr 2fr',
+      }, [
+        {at: -0.5, expect: '2fr 2fr 2fr'},
+        {at: 0, expect: '2fr 2fr 2fr'},
+        {at: 0.3, expect: '2fr 2fr 2fr'},
+        {at: 0.5, expect: '2fr 2fr'},
+        {at: 0.7, expect: '2fr 2fr'},
+        {at: 1, expect: '2fr 2fr'},
+        {at: 1.5, expect: '2fr 2fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        underlying: '10px 20px 30px',
+        addFrom: '15px 4px',
+        addTo: '30px 3px',
+      }, [
+        {at: -0.5, expect: '7.5px 4.5px'},
+        {at: 0, expect: '15px 4px'},
+        {at: 0.5, expect: '22.5px 3.5px'},
+        {at: 1, expect: '30px 3px'},
+        {at: 1.5, expect: '37.5px 2.5px'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        addFrom: "repeat(2, 2fr 30px)",
+        addTo: "repeat(3, 3fr 50px)"
+      }, [
+        {at: -0.5, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.3, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.5, expect: 'repeat(3, 3fr 50px)'},
+        {at: 0.7, expect: 'repeat(3, 3fr 50px)'},
+        {at: 1, expect: 'repeat(3, 3fr 50px)'},
+        {at: 1.5, expect: 'repeat(3, 3fr 50px)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-columns',
+        addFrom: "repeat(2, 2fr 30px)",
+        addTo: "repeat(2, 3fr)"
+      }, [
+        {at: -0.5, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.3, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.5, expect: 'repeat(2, 3fr)'},
+        {at: 0.7, expect: 'repeat(2, 3fr)'},
+        {at: 1, expect: 'repeat(2, 3fr)'},
+        {at: 1.5, expect: 'repeat(2, 3fr)'},
+      ]);
+
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation.html
index 5da3dea..55df24f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-columns-interpolation.html
@@ -8,6 +8,11 @@
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="/css/support/interpolation-testcommon.js"></script>
+    <style>
+      .parent {
+        grid-template-columns: 10px 20px 30px;
+      }
+    </style>
   </head>
   <body>
     <script>
@@ -117,6 +122,58 @@
         {at: 2, expect: "minmax(30px, 3fr) minmax(40px, auto)"}
       ]);
 
+      test_interpolation({
+        property: 'grid-template-columns',
+        from: "10px 10px 10px",
+        to: "1fr fit-content(20px) minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "10px 10px 10px"},
+        {at: 0, expect: "10px 10px 10px"},
+        {at: 0.4, expect: "10px 10px 10px"},
+        {at: 0.6, expect: "1fr fit-content(20px) minmax(20px, 2fr)"},
+        {at: 1, expect: "1fr fit-content(20px) minmax(20px, 2fr)"},
+        {at: 2, expect: "1fr fit-content(20px) minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-columns',
+        from: "1fr 1fr 1fr",
+        to: "20px fit-content(20px) minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "1fr 1fr 1fr"},
+        {at: 0, expect: "1fr 1fr 1fr"},
+        {at: 0.4, expect: "1fr 1fr 1fr"},
+        {at: 0.6, expect: "20px fit-content(20px) minmax(20px, 2fr)"},
+        {at: 1, expect: "20px fit-content(20px) minmax(20px, 2fr)"},
+        {at: 2, expect: "20px fit-content(20px) minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-columns',
+        from: "fit-content(10px)",
+        to: "minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "fit-content(10px)"},
+        {at: 0, expect: "fit-content(10px)"},
+        {at: 0.4, expect: "fit-content(10px)"},
+        {at: 0.6, expect: "minmax(20px, 2fr)"},
+        {at: 1, expect: "minmax(20px, 2fr)"},
+        {at: 2, expect: "minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-columns',
+        from: "inherit",
+        to: "20px 30px 40px"
+      }, [
+        {at: -1, expect: "0px 10px 20px"},
+        {at: 0, expect: "10px 20px 30px"},
+        {at: 0.4, expect: "14px 24px 34px"},
+        {at: 0.6, expect: "16px 26px 36px"},
+        {at: 1, expect: "20px 30px 40px"},
+        {at: 2, expect: "30px 40px 50px"}
+      ]);
+
       // Exercise <track-list> (with <track-repeat>)
       // https://drafts.csswg.org/css-grid/#repeat-interpolation
       test_no_interpolation({
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-composition.html b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-composition.html
new file mode 100644
index 0000000..42f9c92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-composition.html
@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>grid-template-rows composition</title>
+    <link rel="help" href="https://drafts.csswg.org/css-grid/#track-sizing">
+    <meta name="assert" content="grid-template-rows supports composition.">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/css/support/interpolation-testcommon.js"></script>
+  </head>
+  <body>
+    <script>
+      'use strict';
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '50px 10%',
+        addFrom: '100px 100px',
+        addTo: '200px 20%',
+      }, [
+        {at: -0.3, expect: '120px calc(130px + 4%)'},
+        {at: 0, expect: '150px calc(100px + 10%)'},
+        {at: 0.5, expect: '200px calc(50px + 20%)'},
+        {at: 1, expect: '250px 30%'},
+        {at: 1.5, expect: '300px calc(-50px + 40%)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 2fr',
+        addTo: '2fr 1fr',
+      }, [
+        {at: -0.5, expect: '1.5fr 3.5fr'},
+        {at: 0, expect: '2fr 3fr'},
+        {at: 0.5, expect: '2.5fr 2.5fr'},
+        {at: 1, expect: '3fr 2fr'},
+        {at: 1.5, expect: '3.5fr 1.5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '50px',
+        addFrom: '100px',
+        replaceTo: '200px',
+      }, [
+        {at: -0.3, expect: '135px'},
+        {at: 0, expect: '150px'},
+        {at: 0.5, expect: '175px'},
+        {at: 1, expect: '200px'},
+        {at: 1.5, expect: '225px'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr',
+        addFrom: '1fr',
+        replaceTo: '3fr',
+      }, [
+        {at: -0.5, expect: '1.5fr'},
+        {at: 0, expect: '2fr'},
+        {at: 0.5, expect: '2.5fr'},
+        {at: 1, expect: '3fr'},
+        {at: 1.5, expect: '3.5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 1fr',
+        addTo: '3fr auto',
+      }, [
+        {at: -0.5, expect: '1fr 2fr'},
+        {at: 0, expect: '2fr 2fr'},
+        {at: 0.5, expect: '3fr auto'},
+        {at: 1, expect: '4fr auto'},
+        {at: 1.5, expect: '5fr auto'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: '1fr auto',
+        addTo: '3fr 3fr',
+      }, [
+        {at: -0.5, expect: '1fr auto'},
+        {at: 0, expect: '2fr auto'},
+        {at: 0.5, expect: '3fr 4fr'},
+        {at: 1, expect: '4fr 4fr'},
+        {at: 1.5, expect: '5fr 4fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr auto',
+        addFrom: '1fr 1fr',
+        addTo: '3fr 3fr',
+      }, [
+        {at: -0.5, expect: '1fr 0fr'},
+        {at: 0, expect: '2fr 1fr'},
+        {at: 0.5, expect: '3fr 2fr'},
+        {at: 1, expect: '4fr 3fr'},
+        {at: 1.5, expect: '5fr 4fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '0fr repeat(2, 0fr 10px) 1fr',
+        addFrom: "1fr repeat(2, 1fr 20px) 1fr",
+        addTo: "2fr repeat(2, 3fr 40px) 3fr"
+      }, [
+        {at: -0.3, expect: "0.7fr repeat(2, 0.4fr 24px) 1.4fr"},
+        {at: 0, expect: "1fr repeat(2, 1fr 30px) 2fr"},
+        {at: 0.5, expect: "1.5fr repeat(2, 2fr 40px) 3fr"},
+        {at: 1, expect: "2fr repeat(2, 3fr 50px) 4fr"},
+        {at: 1.5, expect: "2.5fr repeat(2, 4fr 60px) 5fr"}
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: '1fr [a b] 1fr [d]',
+        addTo: '3fr [c] 3fr',
+      }, [
+        {at: -0.5, expect: '1fr [ a b ] 1fr [d]'},
+        {at: 0, expect: '2fr [ a b ] 2fr [d]'},
+        {at: 0.5, expect: '3fr [c] 3fr'},
+        {at: 1, expect: '4fr [c] 4fr'},
+        {at: 1.5, expect: '5fr [c] 5fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: 'fit-content(5px) fit-content(20px)',
+        addFrom: 'fit-content(5px) fit-content(20px)',
+        addTo: 'fit-content(15px) max-content',
+      }, [
+        {at: -0.5, expect: 'fit-content(5px) fit-content(40px)'},
+        {at: 0, expect: 'fit-content(10px) fit-content(40px)'},
+        {at: 0.5, expect: 'fit-content(15px) max-content'},
+        {at: 1, expect: 'fit-content(20px) max-content'},
+        {at: 1.5, expect: 'fit-content(25px) max-content'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: 'minmax(5px, 1fr) minmax(10px, 2fr)',
+        addFrom: 'minmax(5px, 1fr) minmax(10px, 2fr)',
+        addTo: 'minmax(15px, 3fr) minmax(30px, auto)',
+      }, [
+        {at: -0.5, expect: 'minmax(5px, 1fr) minmax(10px, 4fr)'},
+        {at: 0, expect: 'minmax(10px, 2fr) minmax(20px, 4fr)'},
+        {at: 0.5, expect: 'minmax(15px, 3fr) minmax(30px, auto)'},
+        {at: 1, expect: 'minmax(20px, 4fr) minmax(40px, auto)'},
+        {at: 1.5, expect: 'minmax(25px, 5fr) minmax(50px, auto)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: 'none',
+        addTo: '1fr 1fr',
+      }, [
+        {at: -0.5, expect: 'none'},
+        {at: 0, expect: 'none'},
+        {at: 0.3, expect: 'none'},
+        {at: 0.5, expect: '2fr 2fr'},
+        {at: 0.7, expect: '2fr 2fr'},
+        {at: 1, expect: '2fr 2fr'},
+        {at: 1.5, expect: '2fr 2fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr',
+        addFrom: '1fr 1fr',
+        addTo: 'none',
+      }, [
+        {at: -0.5, expect: '2fr 2fr'},
+        {at: 0, expect: '2fr 2fr'},
+        {at: 0.3, expect: '2fr 2fr'},
+        {at: 0.5, expect: 'none'},
+        {at: 0.7, expect: 'none'},
+        {at: 1, expect: 'none'},
+        {at: 1.5, expect: 'none'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '1fr 1fr 1fr',
+        addFrom: '1fr 1fr 1fr',
+        addTo: '2fr 2fr',
+      }, [
+        {at: -0.5, expect: '2fr 2fr 2fr'},
+        {at: 0, expect: '2fr 2fr 2fr'},
+        {at: 0.3, expect: '2fr 2fr 2fr'},
+        {at: 0.5, expect: '2fr 2fr'},
+        {at: 0.7, expect: '2fr 2fr'},
+        {at: 1, expect: '2fr 2fr'},
+        {at: 1.5, expect: '2fr 2fr'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        underlying: '10px 20px 30px',
+        addFrom: '15px 4px',
+        addTo: '30px 3px',
+      }, [
+        {at: -0.5, expect: '7.5px 4.5px'},
+        {at: 0, expect: '15px 4px'},
+        {at: 0.5, expect: '22.5px 3.5px'},
+        {at: 1, expect: '30px 3px'},
+        {at: 1.5, expect: '37.5px 2.5px'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        addFrom: "repeat(2, 2fr 30px)",
+        addTo: "repeat(3, 3fr 50px)"
+      }, [
+        {at: -0.5, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.3, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.5, expect: 'repeat(3, 3fr 50px)'},
+        {at: 0.7, expect: 'repeat(3, 3fr 50px)'},
+        {at: 1, expect: 'repeat(3, 3fr 50px)'},
+        {at: 1.5, expect: 'repeat(3, 3fr 50px)'},
+      ]);
+
+      test_composition({
+        property: 'grid-template-rows',
+        addFrom: "repeat(2, 2fr 30px)",
+        addTo: "repeat(2, 3fr)"
+      }, [
+        {at: -0.5, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.3, expect: 'repeat(2, 2fr 30px)'},
+        {at: 0.5, expect: 'repeat(2, 3fr)'},
+        {at: 0.7, expect: 'repeat(2, 3fr)'},
+        {at: 1, expect: 'repeat(2, 3fr)'},
+        {at: 1.5, expect: 'repeat(2, 3fr)'},
+      ]);
+
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation.html
index c1ff70c4..f749cbd8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/animation/grid-template-rows-interpolation.html
@@ -8,6 +8,11 @@
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="/css/support/interpolation-testcommon.js"></script>
+    <style>
+      .parent {
+        grid-template-rows: 10px 20px 30px;
+      }
+    </style>
   </head>
   <body>
     <script>
@@ -117,6 +122,58 @@
         {at: 2, expect: "minmax(30px, 3fr) minmax(40px, auto)"}
       ]);
 
+      test_interpolation({
+        property: 'grid-template-rows',
+        from: "10px 10px 10px",
+        to: "1fr fit-content(20px) minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "10px 10px 10px"},
+        {at: 0, expect: "10px 10px 10px"},
+        {at: 0.4, expect: "10px 10px 10px"},
+        {at: 0.6, expect: "1fr fit-content(20px) minmax(20px, 2fr)"},
+        {at: 1, expect: "1fr fit-content(20px) minmax(20px, 2fr)"},
+        {at: 2, expect: "1fr fit-content(20px) minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-rows',
+        from: "1fr 1fr 1fr",
+        to: "20px fit-content(20px) minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "1fr 1fr 1fr"},
+        {at: 0, expect: "1fr 1fr 1fr"},
+        {at: 0.4, expect: "1fr 1fr 1fr"},
+        {at: 0.6, expect: "20px fit-content(20px) minmax(20px, 2fr)"},
+        {at: 1, expect: "20px fit-content(20px) minmax(20px, 2fr)"},
+        {at: 2, expect: "20px fit-content(20px) minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-rows',
+        from: "fit-content(10px)",
+        to: "minmax(20px, 2fr)"
+      }, [
+        {at: -1, expect: "fit-content(10px)"},
+        {at: 0, expect: "fit-content(10px)"},
+        {at: 0.4, expect: "fit-content(10px)"},
+        {at: 0.6, expect: "minmax(20px, 2fr)"},
+        {at: 1, expect: "minmax(20px, 2fr)"},
+        {at: 2, expect: "minmax(20px, 2fr)"}
+      ]);
+
+      test_interpolation({
+        property: 'grid-template-rows',
+        from: "inherit",
+        to: "20px 30px 40px"
+      }, [
+        {at: -1, expect: "0px 10px 20px"},
+        {at: 0, expect: "10px 20px 30px"},
+        {at: 0.4, expect: "14px 24px 34px"},
+        {at: 0.6, expect: "16px 26px 36px"},
+        {at: 1, expect: "20px 30px 40px"},
+        {at: 2, expect: "30px 40px 50px"}
+      ]);
+
       // Exercise <track-list> (with <track-repeat>)
       // https://drafts.csswg.org/css-grid/#repeat-interpolation
       test_no_interpolation({
diff --git a/third_party/blink/web_tests/http/tests/priority-hints/script-async-initial-load.html b/third_party/blink/web_tests/http/tests/priority-hints/script-async-initial-load.html
index 64c9d6b..cfd2d91 100644
--- a/third_party/blink/web_tests/http/tests/priority-hints/script-async-initial-load.html
+++ b/third_party/blink/web_tests/http/tests/priority-hints/script-async-initial-load.html
@@ -28,7 +28,12 @@
     promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?4', location), document),
     expected_priority: kLow,
     description: 'missing fetchpriority on async <script> has no effect'
-  }
+  },
+  {
+    promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?5', location), document),
+    expected_priority: kHigh,
+    description: 'blocking=render on async <script> raises the priority to kHigh'
+  },
 ];
 
 </script>
@@ -38,6 +43,7 @@
 <script id=script3 async fetchpriority=auto src=../resources/dummy.js?2></script>
 <script id=script4 async fetchpriority=xyz src=../resources/dummy.js?3></script>
 <script id=script5 async src=../resources/dummy.js?4></script>
+<script id=script6 async fetchpriority=low blocking=render src=../resources/dummy.js?5></script>
 
 <script>
   promise_test(async (t) => {
@@ -51,6 +57,7 @@
     assert_true(internals.isPreloaded(script3.src), script3.src + base_msg);
     assert_true(internals.isPreloaded(script4.src), script4.src + base_msg);
     assert_true(internals.isPreloaded(script5.src), script5.src + base_msg);
+    assert_true(internals.isPreloaded(script6.src), script6.src + base_msg);
   }, 'all scripts were fetched by the preload scanner');
 
   // Setup the tests described by |priority_tests|.
diff --git a/third_party/blink/web_tests/http/tests/priority-hints/script-initial-load.html b/third_party/blink/web_tests/http/tests/priority-hints/script-initial-load.html
index 81fc219..52e7ed94 100644
--- a/third_party/blink/web_tests/http/tests/priority-hints/script-initial-load.html
+++ b/third_party/blink/web_tests/http/tests/priority-hints/script-initial-load.html
@@ -14,8 +14,8 @@
   },
   {
     promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?2', location), document),
-    expected_priority: kLow,
-    description: 'low fetchpriority on <script> lowers priority to kLow'
+    expected_priority: kHigh,
+    description: 'low fetchpriority on <script> has no effect'
   },
   {
     promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?3', location), document),
@@ -101,4 +101,4 @@
 <script id=script10 src=../resources/dummy.js?10></script>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/http/tests/priority-hints/script-module-initial-load.html b/third_party/blink/web_tests/http/tests/priority-hints/script-module-initial-load.html
index 49b39b81..fb2dc6e 100644
--- a/third_party/blink/web_tests/http/tests/priority-hints/script-module-initial-load.html
+++ b/third_party/blink/web_tests/http/tests/priority-hints/script-module-initial-load.html
@@ -28,7 +28,12 @@
     promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?4', location), document),
     expected_priority: kHigh,
     description: 'missing fetchpriority on module <script> has no effect'
-  }
+  },
+  {
+    promise: internals.getInitialResourcePriority(new URL('../resources/dummy.js?5', location), document),
+    expected_priority: kHigh,
+    description: 'blocking=render on module <script> raises the priority to kHigh'
+  },
 ];
 
 </script>
@@ -38,6 +43,7 @@
 <script id=script3 type=module fetchpriority=auto src=../resources/dummy.js?2></script>
 <script id=script4 type=module fetchpriority=xyz src=../resources/dummy.js?3></script>
 <script id=script5 type=module src=../resources/dummy.js?4></script>
+<script id=script6 type=module fetchpriority=low blocking=render src=../resources/dummy.js?5></script>
 
 <script>
   promise_test(async (t) => {
@@ -51,6 +57,7 @@
     assert_true(internals.isPreloaded(script3.src), script3.src + base_msg);
     assert_true(internals.isPreloaded(script4.src), script4.src + base_msg);
     assert_true(internals.isPreloaded(script5.src), script5.src + base_msg);
+    assert_true(internals.isPreloaded(script6.src), script6.src + base_msg);
   }, 'all scripts were fetched by the preload scanner');
 
   // Setup the tests described by |priority_tests|.
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-import-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-import-expected.txt
deleted file mode 100644
index 693f97f..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-import-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking defer scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-noimport-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-noimport-expected.txt
deleted file mode 100644
index 693f97f..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-defer-noimport-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking defer scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-import-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-import-expected.txt
deleted file mode 100644
index 1196188..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-import-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking external module scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-noimport-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-noimport-expected.txt
deleted file mode 100644
index 1196188..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-external-module-noimport-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking external module scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-import-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-import-expected.txt
deleted file mode 100644
index 850d797f..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-import-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking module scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-noimport-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-noimport-expected.txt
deleted file mode 100644
index 850d797f..0000000
--- a/third_party/blink/web_tests/platform/generic/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/106-module-noimport-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL  scheduler: stylesheets blocking module scripts assert_equals: expected "fixed" but got "static"
-Harness: the test ran to completion.
-
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium
index a59aba8c..c7ce63ec 100644
--- a/third_party/metrics_proto/README.chromium
+++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@
 Name: Metrics Protos
 Short Name: metrics_proto
 URL: This is the canonical public repository
-Version: 449569319
-Date: 2022/05/18 UTC
+Version: 450727410
+Date: 2022/05/24 UTC
 License: BSD
 Security Critical: Yes
 
diff --git a/third_party/metrics_proto/perf_data.proto b/third_party/metrics_proto/perf_data.proto
index 31586ab..66026c8 100644
--- a/third_party/metrics_proto/perf_data.proto
+++ b/third_party/metrics_proto/perf_data.proto
@@ -390,6 +390,18 @@
     optional uint64 filename_md5_prefix = 5;
   }
 
+  message PerfPMUMappingsMetadata {
+    // Mapping type.
+    // It is a number the kernel uses to map to PMU devices when initializing
+    // them. It is used to reconstruct the event type across different machines.
+    optional uint32 type = 1;
+
+    // The mapping name, field 2, has been intentionally left out.
+
+    // Mapping name's md5 prefix.
+    optional uint64 name_md5_prefix = 3;
+  }
+
   repeated PerfFileAttr file_attrs = 1;
   repeated PerfEvent events = 2;
 
@@ -403,6 +415,7 @@
   optional PerfEventStats stats = 4;
 
   // Not added from original: repeated uint64 metadata_mask = 5;
+  // Not added from original: optional PerfTracingMetadata tracing_data = 14;
 
   // Build ID metadata.
   repeated PerfBuildID build_ids = 7;
@@ -414,6 +427,10 @@
   // Not added from original:
   //     repeated PerfNodeTopologyMetadata numa_topology = 12;
 
+  repeated PerfPMUMappingsMetadata pmu_mappings = 15;
+
+  // Not added from original: repeated PerfGroupDescMetadata group_desc = 16;
+
   message StringMetadata {
     message StringAndMd5sumPrefix {
       // The string value was field 1 and has been intentionally left out.
diff --git a/third_party/metrics_proto/system_profile.proto b/third_party/metrics_proto/system_profile.proto
index b5653a4..00e492eb 100644
--- a/third_party/metrics_proto/system_profile.proto
+++ b/third_party/metrics_proto/system_profile.proto
@@ -229,7 +229,7 @@
   optional OS os = 5;
 
   // Information on the user's hardware.
-  // Next tag: 25
+  // Next tag: 26
   message Hardware {
     // OS CPU architecture. Taken from uname -m and modified in Chromium logic.
     // Common options are: x86, x86_64, armv7l, armv8l, aarch64.
@@ -323,6 +323,29 @@
     }
     optional CPU cpu = 13;
 
+    // Type of BIOS (can change at each boot).
+    enum BiosType {
+      BIOS_TYPE_UNKNOWN = 0;
+      // Legacy BIOS or UEFI with CSM mode.
+      BIOS_TYPE_LEGACY = 1;
+      // BIOS is UEFI and booted into UEFI mode.
+      BIOS_TYPE_UEFI = 2;
+    }
+    // Motherboard information.
+    message Motherboard {
+      // Manufacturer for the motherboard.
+      optional string manufacturer = 1;
+      // Model for the motherboard.
+      optional string model = 2;
+      // Manufacturer for the BIOS.
+      optional string bios_manufacturer = 3;
+      // Version of the BIOS currently installed.
+      optional string bios_version = 4;
+      // What mode of BIOS is booted.
+      optional BiosType bios_type = 5;
+    }
+    optional Motherboard motherboard = 25;
+
     // Information on the GPU
     message Graphics {
       // The GPU manufacturer's vendor id.
diff --git a/tools/android/build_speed/benchmark.py b/tools/android/build_speed/benchmark.py
index 8fc83fef..f6fb48a 100755
--- a/tools/android/build_speed/benchmark.py
+++ b/tools/android/build_speed/benchmark.py
@@ -446,11 +446,13 @@
     parser = argparse.ArgumentParser(
         description=__doc__ + _list_benchmarks(),
         formatter_class=argparse.RawDescriptionHelpFormatter)
-    parser.add_argument('benchmark',
-                        nargs='+',
-                        metavar='BENCHMARK',
-                        choices=list(_all_benchmark_and_suite_names()),
-                        help='Names of benchmark(s) or suites(s) to run.')
+    parser.add_argument(
+        'benchmark',
+        nargs='*',
+        metavar='BENCHMARK',
+        # Allow empty to just test `gn gen` speed.
+        choices=list(_all_benchmark_and_suite_names()) + [[]],
+        help='Names of benchmark(s) or suites(s) to run.')
     parser.add_argument('--bundle',
                         action='store_true',
                         help='Switch the default target from apk to bundle.')
diff --git a/tools/browserbench-webdriver/browserbench.py b/tools/browserbench-webdriver/browserbench.py
index a616c6b..265fc14f 100644
--- a/tools/browserbench-webdriver/browserbench.py
+++ b/tools/browserbench-webdriver/browserbench.py
@@ -7,11 +7,17 @@
 
 import json
 import selenium
+import subprocess
 import sys
 import time
+import traceback
 
 DEFAULT_STP_DRIVER_PATH = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver'
 
+# Maximum number of times the benchmark will be run before giving up.
+MAX_ATTEMPTS = 6
+
+
 class BrowserBench(object):
   def __init__(self, name, version):
     self._name = name
@@ -60,7 +66,8 @@
         try:
           return BrowserBench._CreateSafariDriver(optargs)
         except selenium.common.exceptions.SessionNotCreatedException as e:
-          print('Connecting to Safari failed, will try again ', e)
+          traceback.print_exc(e)
+          print('Connecting to Safari failed, will try again')
           time.sleep(5)
       print('Failed to connect to Safari, this likely means Safari is running '
             ' something else')
@@ -68,6 +75,30 @@
     else:
       return None
 
+  @staticmethod
+  def _KillBrowser(optargs):
+    if optargs.browser == 'safari' or optargs.browser == 'stp':
+      print('Killing browser')
+      subprocess.run([
+          'killall', 'Safari'
+          if optargs.browser == 'safari' else 'Safari Technology Preview'
+      ])
+      # Sleep for a little bit to ensure the kill happened.
+      time.sleep(5)
+      print('Continuing after kill')
+      return
+    # This logic is primarily for Safari, which seems to occasionally hang. Will
+    # implement for Chrome if necessary.
+    print('Not handling kill of chrome, if this is hit and test fails, '
+          'implement it')
+
+  def _CreateDriverAndRun(self, optargs):
+    driver = BrowserBench._CreateDriver(optargs)
+    if not driver:
+      raise Exception('failed to create driver')
+    driver.set_window_size(900, 780)
+    return self.RunAndExtractMeasurements(driver, optargs)
+
   def _ConvertMeasurementsToSkiaFormat(self, measurements):
     '''
     Processes the results from RunAndExtractMeasurements() into the format used
@@ -174,13 +205,27 @@
 
     self.UpdateParseArgs(optargs)
 
-    driver = BrowserBench._CreateDriver(optargs)
-    if not driver:
-      sys.stderr.write('Could not create a driver. Aborting.\n')
-      sys.exit(1)
-    driver.set_window_size(900, 780)
+    run_count = 0
+    measurements = False
+    # Try running the benchmark a number of times. For whatever reason either
+    # Safari or safaridriver does not always complete (based on exceptions it
+    # seems the http connection to safari is prematurely closing).
+    while not measurements and run_count < MAX_ATTEMPTS:
+      run_count += 1
+      try:
+        measurements = self._CreateDriverAndRun(optargs)
+      except Exception as e:
+        if run_count < MAX_ATTEMPTS:
+          sys.stderr.write('Got exception running, will try again')
+          traceback.print_exc()
+        else:
+          sys.stderr.write(
+              'Got exception running, retried too many times, giving up')
+          raise e
+      # When rerunning, first try killing the browser in hopes of state
+      # resetting.
+      BrowserBench._KillBrowser(optargs)
 
-    measurements = self.RunAndExtractMeasurements(driver, optargs)
     self._ProduceOutput(measurements, extra_key_values)
 
   def AddExtraParserOptions(self, parser):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 90622293..fb517c51 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15407,6 +15407,7 @@
   <int value="195" label="Fastboot mode requested by user-mode"/>
   <int value="196"
       label="User requested recovery for training memory and rebooting."/>
+  <int value="200" label="User requested network based recovery"/>
   <int value="255" label="Unspecified/unknown error in user-mode"/>
 </enum>
 
@@ -63274,11 +63275,6 @@
   <int value="6" label="H264_hw"/>
 </enum>
 
-<enum name="MediaRecorderVEAUsed">
-  <int value="0" label="Not used"/>
-  <int value="1" label="Used"/>
-</enum>
-
 <enum name="MediaRendererType">
   <int value="0" label="kDefault"/>
   <int value="1" label="kMojo"/>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 53088d8..b56e4c6e 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -328,15 +328,25 @@
 </histogram>
 
 <histogram
-    name="Compositing.Display.OverlayProcessorOzone.MaxOverlaysSupported"
-    units="units" expires_after="2022-11-30">
+    name="Compositing.Display.OverlayProcessorOzone.HardwareCapabilitiesIsValid"
+    enum="Boolean" expires_after="2022-11-30">
   <owner>khaslett@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <summary>
     This is logged every time a new HardwareCapabilities is received from DRM
+    when display configuration may have changed. True iff the response received
+    is valid.
+  </summary>
+</histogram>
+
+<histogram name="Compositing.Display.OverlayProcessorOzone.MaxPlanesSupported"
+    units="units" expires_after="2022-11-30">
+  <owner>khaslett@chromium.org</owner>
+  <owner>kylechar@chromium.org</owner>
+  <summary>
+    This is logged every time a valid HardwareCapabilities is received from DRM
     when display configuration may have changed. It records the number of
-    overlay planes we have available in addition to the primary plane on this
-    device.
+    overlay planes we have available on this device including the primary plane.
   </summary>
 </histogram>
 
@@ -377,21 +387,30 @@
 
 <histogram
     name="Compositing.Display.OverlayProcessorUsingStrategy.NumOverlays{Counted}"
+    units="overlay candidates" expires_after="2022-11-30">
+  <owner>khaslett@chromium.org</owner>
+  <owner>kylechar@chromium.org</owner>
+  <summary>Logged once per frame, the number of overlays {Counted}</summary>
+  <token key="Counted">
+    <variant name="Attempted"
+        summary="attempted. This is only logged when using the
+                 AttemptMultipleOverlays path."/>
+    <variant name="Failed"
+        summary="failed. This is only logged when using the
+                 AttemptMultipleOverlays path."/>
+    <variant name="Promoted" summary="promoted."/>
+  </token>
+</histogram>
+
+<histogram
+    name="Compositing.Display.OverlayProcessorUsingStrategy.NumQuadsConsidered"
     units="units" expires_after="2022-11-30">
   <owner>khaslett@chromium.org</owner>
   <owner>kylechar@chromium.org</owner>
   <summary>
-    Logged zero or one times per frame, the number of overlays {Counted} when
-    using the AttemptMultipleOverlays codepath.
-
-    Note: NumOverlaysFailed and NumOverlaysPromoted are only logged when
-    NumOverlaysAttempted &gt; 0.
+    Logged once per frame, the number of quads considered for promotion to
+    overlay.
   </summary>
-  <token key="Counted">
-    <variant name="Attempted" summary="attempted"/>
-    <variant name="Failed" summary="failed"/>
-    <variant name="Promoted" summary="promoted"/>
-  </token>
 </histogram>
 
 <histogram
@@ -1018,7 +1037,7 @@
   </summary>
 </histogram>
 
-<histogram name="Graphics.Smoothness.Jank" units="%" expires_after="2022-10-09">
+<histogram name="Graphics.Smoothness.Jank" units="%" expires_after="2023-06-01">
   <owner>sadrul@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
@@ -1039,7 +1058,7 @@
 </histogram>
 
 <histogram name="Graphics.Smoothness.Jank.All{Type}" units="%"
-    expires_after="2022-06-01">
+    expires_after="2023-06-01">
   <owner>sadrul@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index 0326a70..3fe63c9 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -1746,12 +1746,13 @@
 </histogram>
 
 <histogram name="Viz.DisplayCompositor.OverlayStrategy"
-    enum="OverlayStrategies" expires_after="2022-11-20">
-  <owner>dcastagna@chromium.org</owner>
-  <owner>hoegsberg@chromium.org</owner>
+    enum="OverlayStrategies" expires_after="2022-11-30">
+  <owner>khaslett@chromium.org</owner>
+  <owner>kylechar@chromium.org</owner>
   <summary>
-    Overlay strategies used to promote Hardware Overlays, per frame. Recorded
-    every time a frame is rendered by the display compositor.
+    Overlay strategies used to promote Hardware Overlays, once or more per
+    frame. Recorded every time a frame is rendered by the display compositor, or
+    once per overlay promoted if multiple were promoted.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 44fc427..15691e8 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3188,13 +3188,6 @@
   <summary>The errors HW video encode encounters in MediaRecorder.</summary>
 </histogram>
 
-<histogram name="Media.MediaRecorder.VEAUsed" enum="MediaRecorderVEAUsed"
-    expires_after="M95">
-  <owner>mcasas@chromium.org</owner>
-  <owner>wtlee@chromium.org</owner>
-  <summary>Whether HW video encode is used in MediaRecorder.</summary>
-</histogram>
-
 <histogram name="Media.MediaStreamManager.DesktopVideoDeviceUpdate"
     enum="MediaStreamRequestResult2" expires_after="2022-12-01">
   <owner>eladalon@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index 527e3c0..d55618f 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -56,7 +56,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundService.Collections.RequestLatency"
-    units="ms" expires_after="2022-07-01">
+    units="ms" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -68,7 +68,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundService.Images.RequestLatency" units="ms"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -105,7 +105,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Carts.ClickCart" units="index"
-    expires_after="2022-06-30">
+    expires_after="2022-11-20">
   <owner>wychen@chromium.org</owner>
   <owner>yuezhanggg@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
@@ -785,7 +785,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizeChromeBackgroundAction"
-    enum="NTPCustomizeChromeBackgroundAction" expires_after="2022-07-01">
+    enum="NTPCustomizeChromeBackgroundAction" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -821,7 +821,7 @@
 </histogram>
 
 <histogram name="NewTabPage.CustomizeLocalImageBackgroundAction"
-    enum="NTPCustomizeLocalImageBackgroundAction" expires_after="2022-07-01">
+    enum="NTPCustomizeLocalImageBackgroundAction" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -856,7 +856,7 @@
 </histogram>
 
 <histogram name="NewTabPage.HasCredentials" enum="BooleanYesNo"
-    expires_after="2022-09-11">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -869,7 +869,7 @@
   </summary>
 </histogram>
 
-<histogram name="NewTabPage.Height" units="pixels" expires_after="2022-06-01">
+<histogram name="NewTabPage.Height" units="pixels" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -918,7 +918,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoDownloadOutcome"
-    enum="NewTabPageLogoDownloadOutcome" expires_after="2022-07-01">
+    enum="NewTabPageLogoDownloadOutcome" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -930,7 +930,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoDownloadTime" units="ms"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -944,7 +944,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoImageDownloaded" enum="BooleanFromHTTPCache"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -956,7 +956,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoShown" enum="NewTabPageLogoShown"
-    expires_after="2022-09-11">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -969,7 +969,7 @@
 </histogram>
 
 <histogram name="NewTabPage.LogoShownTime2" units="ms"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1016,7 +1016,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Disabled{Interaction}" enum="NtpModules"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1062,7 +1062,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Enabled{Interaction}" enum="NtpModules"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1240,7 +1240,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.LoadedWith.{NtpModule}" enum="NtpModules"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1373,7 +1373,7 @@
 </histogram>
 
 <histogram name="NewTabPage.OneGoogleBar.RequestLatency" units="ms"
-    expires_after="2022-09-11">
+    expires_after="2022-11-20">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1384,7 +1384,7 @@
 </histogram>
 
 <histogram name="NewTabPage.OneGoogleBar.ShownTime" units="ms"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1479,7 +1479,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Promos.PromoBrowserCommand"
-    enum="PromoBrowserCommandEnum" expires_after="2022-06-05">
+    enum="PromoBrowserCommandEnum" expires_after="2022-11-20">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
   <summary>
@@ -1490,7 +1490,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Promos.RequestLatency2" units="ms"
-    expires_after="2022-09-11">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1502,7 +1502,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Promos.ShownTime" units="ms"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1530,7 +1530,7 @@
 </histogram>
 
 <histogram name="NewTabPage.RecipeTasks.RecipeClick" units="index"
-    expires_after="2022-09-18">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1542,7 +1542,7 @@
 </histogram>
 
 <histogram name="NewTabPage.RecipeTasks.RecipeDownloadCount" units="recipes"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1556,7 +1556,7 @@
 </histogram>
 
 <histogram name="NewTabPage.RecipeTasks.RelatedSearchClick" units="index"
-    expires_after="2022-09-18">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1647,7 +1647,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.ProductClick" units="index"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1659,7 +1659,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.ProductDownloadCount"
-    units="products" expires_after="2022-07-01">
+    units="products" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1673,7 +1673,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.RelatedSearchClick" units="index"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1685,7 +1685,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ShoppingTasks.RelatedSearchDownloadCount"
-    units="count" expires_after="2022-07-01">
+    units="count" expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1869,7 +1869,7 @@
 </histogram>
 
 <histogram name="NewTabPage.URLState" enum="NewTabURLState"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
@@ -1928,7 +1928,7 @@
 </histogram>
 
 <histogram name="NewTabPage.VoiceErrors" enum="NewTabPageVoiceError"
-    expires_after="2022-07-01">
+    expires_after="2022-11-20">
   <owner>danpeng@google.com</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 8741bf1..4eae625 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -1250,7 +1250,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.Win.{Capturer}CapturerFrameTime"
-    units="ms" expires_after="2022-07-03">
+    units="ms" expires_after="2022-10-09">
   <owner>jamiewalch@chromium.org</owner>
   <owner>auorion@microsoft.com</owner>
   <owner>edgecapabilitiesdev@microsoft.com</owner>
diff --git a/tools/metrics/structured/structured.xml b/tools/metrics/structured/structured.xml
index c54c470..fa3303f 100644
--- a/tools/metrics/structured/structured.xml
+++ b/tools/metrics/structured/structured.xml
@@ -5,6 +5,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for recording CrOSActions.
   </summary>
@@ -194,6 +195,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     See event summary.
   </summary>
@@ -258,6 +260,7 @@
   <owner>pdyson@chromium.org</owner>
   <id>per-project</id>
   <scope>device</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for recording events to monitor the creation of Neutrino Devices.
   </summary>
@@ -383,6 +386,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>device</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Structured Metrics is a logging framework for events. This project is used
     for monitoring the framework itself.
@@ -407,6 +411,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for unit testing, do not use.
   </summary>
@@ -432,6 +437,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for unit testing, do not use.
   </summary>
@@ -463,6 +469,7 @@
   <owner>tby@chromium.org</owner>
   <id>uma</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for unit testing, do not use.
   </summary>
@@ -483,6 +490,7 @@
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <scope>device</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for unit testing, do not use.
   </summary>
@@ -503,6 +511,7 @@
   <owner>tby@chromium.org</owner>
   <id>none</id>
   <scope>profile</scope>
+  <key-rotation>90</key-rotation>
   <summary>
     Project for unit testing, do not use.
   </summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 7948591..d21923ed 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,16 +5,16 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "win": {
-            "hash": "0c4444f5c08b752ebdbebdc0bcbf49882abe25e8",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/03376e559abfc2e993526197d9bd2198ca356959/trace_processor_shell.exe"
+            "hash": "19b13d514c8032c3b3979754d4a8a07722e06d67",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/d099a600a3410a602cee37a19e875f1a974d493a/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "ec3bf68a4b46e95ab00042be24d8d6da15f4ccfb",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/b146e432cba8ac3c886a671169f1677519389ab2/trace_processor_shell"
+            "hash": "a5e11ebae9efeb4d5243e81efe1a3ec4027a1874",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d099a600a3410a602cee37a19e875f1a974d493a/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "250caa942a98af360830b5bdb732736e5d2a0614",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d099a600a3410a602cee37a19e875f1a974d493a/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/2ca7a20f3978e16c4e29e0f615ad89e7ee3410a4/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 3e9ce15b..c411a351 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -134,7 +134,7 @@
 
 def _determine_data_format(json_file):
   if json_file not in _data_format_cache:
-    with open(json_file) as f:
+    with open(json_file, 'rb') as f:
       data = json.load(f)
       if isinstance(data, list):
         _data_format_cache[json_file] = DATA_FORMAT_HISTOGRAMS
diff --git a/tools/polymer/generate_gn_v3.py b/tools/polymer/generate_gn_v3.py
index 75204f3d..61f4fc4 100755
--- a/tools/polymer/generate_gn_v3.py
+++ b/tools/polymer/generate_gn_v3.py
@@ -5,7 +5,6 @@
 
 from __future__ import print_function
 
-from datetime import date
 import json
 import os.path as path
 import sys
@@ -71,7 +70,7 @@
   targets = targets.strip()
 
   if targets:
-    current_year = date.today().year
+    current_year = 2021
     print(_COMPILED_RESOURCES_TEMPLATE %
           (current_year, created_by, _COMPILE_JS, targets))
 
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc
index 8fcc022..19dc007 100644
--- a/ui/compositor/layer_animator.cc
+++ b/ui/compositor/layer_animator.cc
@@ -450,6 +450,7 @@
 }
 
 void LayerAnimator::AddToCollection(LayerAnimatorCollection* collection) {
+  DCHECK_EQ(collection, GetLayerAnimatorCollection());
   if (is_animating() && !is_started_) {
     collection->StartAnimator(this);
     is_started_ = true;
@@ -457,10 +458,13 @@
 }
 
 void LayerAnimator::RemoveFromCollection(LayerAnimatorCollection* collection) {
+  DCHECK_EQ(collection, GetLayerAnimatorCollection());
   if (is_started_) {
     collection->StopAnimator(this);
     is_started_ = false;
   }
+  DCHECK(!animation_->element_animations() ||
+         !animation_->element_animations()->HasTickingKeyframeEffect());
 }
 
 // LayerAnimator protected -----------------------------------------------------
diff --git a/ui/message_center/views/notification_view_base.cc b/ui/message_center/views/notification_view_base.cc
index 41052a0..0b38859 100644
--- a/ui/message_center/views/notification_view_base.cc
+++ b/ui/message_center/views/notification_view_base.cc
@@ -58,7 +58,6 @@
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/box_layout_view.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index 1b423cc..db852e8 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -357,9 +357,7 @@
       device_manager_->GetDrmDevice(widget)->plane_manager();
 
   if (!hdc || !plane_manager) {
-    // Assume only the primary plane exists.
-    ui::HardwareCapabilities hardware_capabilities;
-    hardware_capabilities.num_overlay_capable_planes = 1;
+    ui::HardwareCapabilities hardware_capabilities{.is_valid = false};
     std::move(receive_callback).Run(hardware_capabilities);
     return;
   }
@@ -372,10 +370,9 @@
         .Run(plane_manager->GetHardwareCapabilities(
             crtc_controllers[0]->crtc()));
   } else {
-    // If there are multiple CRTCs for this widget, we shouldn't rely on
-    // overlays working, so we'll say only the primary plane exists.
-    ui::HardwareCapabilities hardware_capabilities;
-    hardware_capabilities.num_overlay_capable_planes = 1;
+    // If there are multiple CRTCs for this widget we shouldn't rely on overlays
+    // working.
+    ui::HardwareCapabilities hardware_capabilities{.is_valid = false};
     std::move(receive_callback).Run(hardware_capabilities);
   }
 }
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index 689f636..ec1dfb5f 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -523,6 +523,7 @@
 ui::HardwareCapabilities HardwareDisplayPlaneManager::GetHardwareCapabilities(
     uint32_t crtc_id) {
   ui::HardwareCapabilities hc;
+  hc.is_valid = true;
   hc.num_overlay_capable_planes = std::count_if(
       planes_.begin(), planes_.end(),
       [crtc_id](const std::unique_ptr<HardwareDisplayPlane>& plane) {
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 2b12979..281ebfa 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -1186,12 +1186,12 @@
                              plane_properties_, property_names_, use_atomic_);
 
   for (int i = 0; i < 4; ++i) {
+    auto hc =
+        fake_drm_->plane_manager()->GetHardwareCapabilities(kCrtcIdBase + i);
+    EXPECT_TRUE(hc.is_valid);
     // Legacy doesn't support OVERLAY planes.
     int expected_planes = use_atomic_ ? 7 : 1;
-    EXPECT_EQ(fake_drm_->plane_manager()
-                  ->GetHardwareCapabilities(kCrtcIdBase + i)
-                  .num_overlay_capable_planes,
-              expected_planes);
+    EXPECT_EQ(hc.num_overlay_capable_planes, expected_planes);
   }
 
   {
@@ -1212,16 +1212,17 @@
   }
 
   for (int i = 0; i < 4; ++i) {
+    auto hc =
+        fake_drm_->plane_manager()->GetHardwareCapabilities(kCrtcIdBase + i);
+
+    EXPECT_TRUE(hc.is_valid);
     // Legacy doesn't support OVERLAY planes.
     int expected_planes = use_atomic_ ? 7 : 1;
     // First two CRTCs have the newly added plane available.
     if (i == 0 || i == 1) {
       expected_planes++;
     }
-    EXPECT_EQ(fake_drm_->plane_manager()
-                  ->GetHardwareCapabilities(kCrtcIdBase + i)
-                  .num_overlay_capable_planes,
-              expected_planes);
+    EXPECT_EQ(hc.num_overlay_capable_planes, expected_planes);
   }
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index 851a5cd..95dd8f5 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -624,6 +624,16 @@
   return now + base::Microseconds(delta_us);
 }
 
+const gfx::PointF WaylandConnection::MaybeConvertLocation(
+    const gfx::PointF& location,
+    const WaylandWindow* window) const {
+  if (!surface_submission_in_pixel_coordinates_)
+    return location;
+  gfx::PointF converted(location);
+  converted.Scale(1.0f / window->window_scale());
+  return converted;
+}
+
 // static
 void WaylandConnection::GlobalRemove(void* data,
                                      wl_registry* registry,
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index 9f4fc6c..5918af2 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -291,6 +291,9 @@
            tablet_layout_state_ == display::TabletState::kEnteringTabletMode;
   }
 
+  const gfx::PointF MaybeConvertLocation(const gfx::PointF& location,
+                                         const WaylandWindow* window) const;
+
  private:
   friend class WaylandConnectionTestApi;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.cc b/ui/ozone/platform/wayland/host/wayland_data_device.cc
index 728b64c..0153978 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -136,7 +136,8 @@
   DCHECK(self->new_offer_);
   self->drag_delegate_->OnDragOffer(std::move(self->new_offer_));
 
-  gfx::PointF point(wl_fixed_to_double(x), wl_fixed_to_double(y));
+  gfx::PointF point = self->connection()->MaybeConvertLocation(
+      gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), window);
   self->drag_delegate_->OnDragEnter(window, point, serial);
 
   self->connection()->ScheduleFlush();
@@ -149,7 +150,9 @@
                                  wl_fixed_t y) {
   auto* self = static_cast<WaylandDataDevice*>(data);
   if (self->drag_delegate_) {
-    gfx::PointF point(wl_fixed_to_double(x), wl_fixed_to_double(y));
+    gfx::PointF point = self->connection()->MaybeConvertLocation(
+        gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)),
+        self->drag_delegate_->GetDragTarget());
     self->drag_delegate_->OnDragMotion(point);
   }
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.h b/ui/ozone/platform/wayland/host/wayland_data_device.h
index 9c0328ae..5f32a76 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -46,6 +46,8 @@
     virtual void OnDragLeave() = 0;
     virtual void OnDragDrop() = 0;
 
+    virtual const WaylandWindow* GetDragTarget() const = 0;
+
    protected:
     virtual ~DragDelegate() = default;
   };
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index ece1a64..dd10f20 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -292,16 +292,10 @@
     last_drag_location_ = location;
     return;
   }
-
-  gfx::PointF pointer_location(location);
-  if (connection_->surface_submission_in_pixel_coordinates())
-    pointer_location.Scale(1.0f / window_->window_scale());
-
   DCHECK(data_offer_);
   int available_operations =
       DndActionsToDragOperations(data_offer_->source_actions());
-  int client_operations =
-      window_->OnDragMotion(pointer_location, available_operations);
+  int client_operations = window_->OnDragMotion(location, available_operations);
 
   data_offer_->SetDndActions(DragOperationsToDndActions(client_operations));
 }
@@ -367,6 +361,10 @@
   state_ = State::kIdle;
 }
 
+const WaylandWindow* WaylandDataDragController::GetDragTarget() const {
+  return window_;
+}
+
 void WaylandDataDragController::OnDataSourceSend(const std::string& mime_type,
                                                  std::string* buffer) {
   DCHECK(data_source_);
@@ -474,12 +472,8 @@
     std::unique_ptr<OSExchangeData> data) {
   DCHECK(window_);
   {
-    gfx::PointF pointer_location(location);
-    if (connection_->surface_submission_in_pixel_coordinates())
-      pointer_location.Scale(1.0f / window_->window_scale());
-
     window_->OnDragEnter(
-        pointer_location, std::move(data),
+        location, std::move(data),
         DndActionsToDragOperations(data_offer_->source_actions()));
   }
   OnDragMotion(location);
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index f8f8266e..c0f8249 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -126,6 +126,7 @@
   void OnDragMotion(const gfx::PointF& location) override;
   void OnDragLeave() override;
   void OnDragDrop() override;
+  const WaylandWindow* GetDragTarget() const override;
 
   // WaylandDataSource::Delegate:
   void OnDataSourceFinish(bool completed) override;
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source.cc b/ui/ozone/platform/wayland/host/wayland_event_source.cc
index fd857aa7..1deef5fe 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -189,13 +189,10 @@
 
 void WaylandEventSource::OnPointerFocusChanged(WaylandWindow* window,
                                                const gfx::PointF& location) {
-  // Save new pointer location.
-  pointer_location_ = location;
-
   bool focused = !!window;
   if (focused) {
-    if (SurfaceSubmissionInPixelCoordinates())
-      pointer_location_.Scale(1.0f / window->window_scale());
+    // Save new pointer location.
+    pointer_location_ = location;
     window_manager_->SetPointerFocusedWindow(window);
   }
 
@@ -237,12 +234,6 @@
 void WaylandEventSource::OnPointerMotionEvent(const gfx::PointF& location) {
   pointer_location_ = location;
 
-  if (SurfaceSubmissionInPixelCoordinates()) {
-    if (WaylandWindow* window =
-            window_manager_->GetCurrentPointerFocusedWindow())
-      pointer_location_.Scale(1.0f / window->window_scale());
-  }
-
   int flags = pointer_flags_ | keyboard_modifiers_;
   MouseEvent event(ET_MOUSE_MOVED, pointer_location_, pointer_location_,
                    EventTimeForNow(), flags, 0, PointerDetailsForDispatching());
@@ -339,26 +330,24 @@
 }
 
 void WaylandEventSource::OnTouchPressEvent(WaylandWindow* window,
-                                           const gfx::PointF& location,
+                                           const gfx::PointF& orig_location,
                                            base::TimeTicks timestamp,
                                            PointerId id) {
+  auto location = connection_->MaybeConvertLocation(orig_location, window);
+
   DCHECK(window);
   HandleTouchFocusChange(window, true);
 
-  gfx::PointF loc =
-      SurfaceSubmissionInPixelCoordinates()
-          ? gfx::ScalePoint(location, 1.f / window->window_scale())
-          : location;
   // Make sure this touch point wasn't present before.
-  auto success =
-      touch_points_.try_emplace(id, std::make_unique<TouchPoint>(loc, window));
+  auto success = touch_points_.try_emplace(
+      id, std::make_unique<TouchPoint>(location, window));
   if (!success.second) {
     LOG(WARNING) << "Touch down fired with wrong id";
     return;
   }
 
   PointerDetails details(EventPointerType::kTouch, id);
-  TouchEvent event(ET_TOUCH_PRESSED, loc, loc, timestamp, details,
+  TouchEvent event(ET_TOUCH_PRESSED, location, location, timestamp, details,
                    keyboard_modifiers_);
   DispatchEvent(&event);
 }
@@ -406,14 +395,9 @@
     LOG(WARNING) << "Touch event fired with wrong id";
     return;
   }
-
-  gfx::PointF loc =
-      SurfaceSubmissionInPixelCoordinates()
-          ? gfx::ScalePoint(location, 1.f / it->second->window->window_scale())
-          : location;
-  it->second->last_known_location = loc;
+  it->second->last_known_location = location;
   PointerDetails details(EventPointerType::kTouch, id);
-  TouchEvent event(ET_TOUCH_MOVED, loc, loc, timestamp, details,
+  TouchEvent event(ET_TOUCH_MOVED, location, location, timestamp, details,
                    keyboard_modifiers_);
   DispatchEvent(&event);
 }
@@ -449,6 +433,11 @@
   return pointer_ids;
 }
 
+const WaylandWindow* WaylandEventSource::GetTouchTarget(PointerId id) const {
+  const auto it = touch_points_.find(id);
+  return it == touch_points_.end() ? nullptr : it->second->window;
+}
+
 void WaylandEventSource::OnPinchEvent(EventType event_type,
                                       const gfx::Vector2dF& delta,
                                       base::TimeTicks timestamp,
@@ -475,7 +464,8 @@
 
 void WaylandEventSource::OnRelativePointerMotion(const gfx::Vector2dF& delta) {
   DCHECK(relative_pointer_location_.has_value());
-
+  // TODO(oshima): Investigate if we need to scale the delta
+  // when surface_submission_in_pixel_coordinates is on.
   relative_pointer_location_ = *relative_pointer_location_ + delta;
   OnPointerMotionEvent(*relative_pointer_location_);
 }
@@ -490,6 +480,10 @@
   last_pointer_stylus_tool_ = pointer_type;
 }
 
+const WaylandWindow* WaylandEventSource::GetPointerTarget() const {
+  return window_manager_->GetCurrentPointerFocusedWindow();
+}
+
 void WaylandEventSource::ResetPointerFlags() {
   pointer_flags_ = 0;
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source.h b/ui/ozone/platform/wayland/host/wayland_event_source.h
index 3c1c40e..6fa56f0 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_source.h
+++ b/ui/ozone/platform/wayland/host/wayland_event_source.h
@@ -112,6 +112,7 @@
   const gfx::PointF& GetPointerLocation() const override;
   bool IsPointerButtonPressed(EventFlags button) const override;
   void OnPointerStylusToolChanged(EventPointerType pointer_type) override;
+  const WaylandWindow* GetPointerTarget() const override;
 
   // WaylandTouch::Delegate
   void OnTouchPressEvent(WaylandWindow* window,
@@ -125,6 +126,7 @@
   void OnTouchCancelEvent() override;
   void OnTouchFocusChanged(WaylandWindow* window) override;
   std::vector<PointerId> GetActiveTouchPointIds() override;
+  const WaylandWindow* GetTouchTarget(PointerId id) const override;
 
   // WaylandZwpPointerGesture::Delegate:
   void OnPinchEvent(EventType event_type,
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
index aa95fd3..d9504ae4 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -54,7 +54,9 @@
   WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
   gfx::PointF location{static_cast<float>(wl_fixed_to_double(surface_x)),
                        static_cast<float>(wl_fixed_to_double(surface_y))};
-  pointer->delegate_->OnPointerFocusChanged(window, location);
+
+  pointer->delegate_->OnPointerFocusChanged(
+      window, pointer->connection_->MaybeConvertLocation(location, window));
 }
 
 // static
@@ -80,7 +82,10 @@
   WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
   gfx::PointF location(wl_fixed_to_double(surface_x),
                        wl_fixed_to_double(surface_y));
-  pointer->delegate_->OnPointerMotionEvent(location);
+  const WaylandWindow* target = pointer->delegate_->GetPointerTarget();
+
+  pointer->delegate_->OnPointerMotionEvent(
+      pointer->connection_->MaybeConvertLocation(location, target));
 }
 
 // static
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.h b/ui/ozone/platform/wayland/host/wayland_pointer.h
index 2df105e..37a03735 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.h
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.h
@@ -121,6 +121,7 @@
   virtual const gfx::PointF& GetPointerLocation() const = 0;
   virtual bool IsPointerButtonPressed(EventFlags button) const = 0;
   virtual void OnPointerStylusToolChanged(EventPointerType pointer_type) = 0;
+  virtual const WaylandWindow* GetPointerTarget() const = 0;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.cc b/ui/ozone/platform/wayland/host/wayland_touch.cc
index 8b5c216..ccf7adb 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch.cc
+++ b/ui/ozone/platform/wayland/host/wayland_touch.cc
@@ -4,6 +4,7 @@
 
 #include "ui/ozone/platform/wayland/host/wayland_touch.h"
 
+#include "base/logging.h"
 #include "base/time/time.h"
 #include "ui/events/types/event_type.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -47,7 +48,8 @@
                                                     serial);
 
   WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
-  gfx::PointF location(wl_fixed_to_double(x), wl_fixed_to_double(y));
+  gfx::PointF location = touch->connection_->MaybeConvertLocation(
+      gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), window);
   base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time);
   touch->delegate_->OnTouchPressEvent(window, location, timestamp, id);
 }
@@ -72,8 +74,13 @@
                           wl_fixed_t y) {
   WaylandTouch* touch = static_cast<WaylandTouch*>(data);
   DCHECK(touch);
-
-  gfx::PointF location(wl_fixed_to_double(x), wl_fixed_to_double(y));
+  const WaylandWindow* target = touch->delegate_->GetTouchTarget(id);
+  if (!target) {
+    LOG(WARNING) << "Touch event fired with wrong id";
+    return;
+  }
+  gfx::PointF location = touch->connection_->MaybeConvertLocation(
+      gfx::PointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), target);
   base::TimeTicks timestamp = base::TimeTicks() + base::Milliseconds(time);
   touch->delegate_->OnTouchMotionEvent(location, timestamp, id);
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_touch.h b/ui/ozone/platform/wayland/host/wayland_touch.h
index 11405ee..a1cb7b3e 100644
--- a/ui/ozone/platform/wayland/host/wayland_touch.h
+++ b/ui/ozone/platform/wayland/host/wayland_touch.h
@@ -75,6 +75,7 @@
   virtual void OnTouchCancelEvent() = 0;
   virtual void OnTouchFocusChanged(WaylandWindow* window) = 0;
   virtual std::vector<PointerId> GetActiveTouchPointIds() = 0;
+  virtual const WaylandWindow* GetTouchTarget(PointerId id) const = 0;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 6dac660..5ca82aa 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -216,6 +216,8 @@
   DCHECK(data_source_);
   DCHECK(data_offer_);
 
+  drag_target_window_ = window;
+
   // Forward focus change event to the input delegate, so other components, such
   // as WaylandScreen, are able to properly retrieve focus related info during
   // window dragging sesstions.
@@ -243,6 +245,8 @@
 }
 
 void WaylandWindowDragController::OnDragMotion(const gfx::PointF& location) {
+  DCHECK(drag_target_window_);
+
   DCHECK_GE(state_, State::kAttached);
   DVLOG(2) << "OnMotion. location=" << location.ToString();
 
@@ -269,6 +273,8 @@
 void WaylandWindowDragController::OnDragLeave() {
   DCHECK_GE(state_, State::kAttached);
 
+  drag_target_window_ = nullptr;
+
   // In order to guarantee ET_MOUSE_RELEASED event is delivered once the DND
   // session finishes, the focused window is not reset here. This is similar to
   // the "implicit grab" behavior implemented by Wayland compositors for
@@ -328,6 +334,12 @@
   DCHECK(data_offer_);
   data_offer_->FinishOffer();
   data_offer_.reset();
+
+  drag_target_window_ = nullptr;
+}
+
+const WaylandWindow* WaylandWindowDragController::GetDragTarget() const {
+  return drag_target_window_;
 }
 
 // This function is called when either 'cancelled' or 'finished' data source
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
index e3fade0..d0f5bd5 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.h
@@ -108,6 +108,7 @@
   void OnDragMotion(const gfx::PointF& location) override;
   void OnDragLeave() override;
   void OnDragDrop() override;
+  const WaylandWindow* GetDragTarget() const override;
 
   // WaylandDataSource::Delegate
   void OnDataSourceFinish(bool completed) override;
@@ -172,6 +173,8 @@
   // pointer focus when the session was initiated.
   WaylandWindow* origin_window_ = nullptr;
 
+  WaylandWindow* drag_target_window_ = nullptr;
+
   // The |origin_window_| can be destroyed during the DND session. If this
   // happens, |origin_surface_| takes ownership of its surface and ensure it
   // is kept alive until the end of the session.
diff --git a/ui/ozone/public/hardware_capabilities.h b/ui/ozone/public/hardware_capabilities.h
index 16bebaf0..d802b66 100644
--- a/ui/ozone/public/hardware_capabilities.h
+++ b/ui/ozone/public/hardware_capabilities.h
@@ -10,6 +10,8 @@
 namespace ui {
 
 struct HardwareCapabilities {
+  // Whether this is a valid response from the HardwareDisplayPlaneManager.
+  bool is_valid = false;
   // Number of planes available to the current CRTC(s).
   // This is specifically the count of non-CURSOR planes, because some boards
   // may have extra PRIMARY planes that could be used for overlays.
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 033ffbb..e4dae43 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -227,7 +227,6 @@
     "mouse_constants.h",
     "mouse_watcher.h",
     "mouse_watcher_view_host.h",
-    "native_cursor.h",
     "native_theme_delegate.h",
     "paint_info.h",
     "painter.h",
@@ -633,7 +632,6 @@
       "drag_utils_mac.mm",
       "event_monitor_mac.mm",
       "metrics_mac.cc",
-      "native_cursor_mac.mm",
       "style/platform_style_mac.mm",
       "views_touch_selection_controller_factory_mac.cc",
       "widget/native_widget_mac.mm",
@@ -746,7 +744,6 @@
       "drag_utils_aura.cc",
       "event_monitor_aura.cc",
       "metrics_aura.cc",
-      "native_cursor_aura.cc",
       "touchui/touch_selection_controller_impl.cc",
       "touchui/touch_selection_menu_runner_views.cc",
       "touchui/touch_selection_menu_views.cc",
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 4353a812..c748b7ed 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -38,7 +38,6 @@
 #include "ui/views/cascading_property.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/focus/focus_manager.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/selection_controller.h"
 
 namespace {
@@ -800,9 +799,9 @@
   UpdateColorsFromTheme();
 }
 
-gfx::NativeCursor Label::GetCursor(const ui::MouseEvent& event) {
-  return GetRenderTextForSelectionController() ? GetNativeIBeamCursor()
-                                               : gfx::kNullCursor;
+ui::Cursor Label::GetCursor(const ui::MouseEvent& event) {
+  return GetRenderTextForSelectionController() ? ui::mojom::CursorType::kIBeam
+                                               : ui::Cursor();
 }
 
 void Label::OnFocus() {
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index 109e19f..912c7d2 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -339,7 +339,7 @@
   void OnDeviceScaleFactorChanged(float old_device_scale_factor,
                                   float new_device_scale_factor) override;
   void OnThemeChanged() override;
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void OnFocus() override;
   void OnBlur() override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
diff --git a/ui/views/controls/link.cc b/ui/views/controls/link.cc
index 608fe02..b8d7020 100644
--- a/ui/views/controls/link.cc
+++ b/ui/views/controls/link.cc
@@ -19,7 +19,6 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/font_list.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/style/platform_style.h"
 
 namespace views {
@@ -60,10 +59,10 @@
   RecalculateFont();
 }
 
-gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
+ui::Cursor Link::GetCursor(const ui::MouseEvent& event) {
   if (!GetEnabled())
-    return gfx::kNullCursor;
-  return GetNativeHandCursor();
+    return ui::Cursor();
+  return ui::mojom::CursorType::kHand;
 }
 
 bool Link::GetCanProcessEventsWithinSubtree() const {
diff --git a/ui/views/controls/link.h b/ui/views/controls/link.h
index e45d754..405b605 100644
--- a/ui/views/controls/link.h
+++ b/ui/views/controls/link.h
@@ -63,7 +63,7 @@
   void SetForceUnderline(bool force_underline);
 
   // Label:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   bool GetCanProcessEventsWithinSubtree() const override;
   void OnMouseEntered(const ui::MouseEvent& event) override;
   void OnMouseExited(const ui::MouseEvent& event) override;
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
index eee9604..de3cbdf 100644
--- a/ui/views/controls/native/native_view_host.cc
+++ b/ui/views/controls/native/native_view_host.cc
@@ -234,7 +234,7 @@
   return View::GetNativeViewAccessible();
 }
 
-gfx::NativeCursor NativeViewHost::GetCursor(const ui::MouseEvent& event) {
+ui::Cursor NativeViewHost::GetCursor(const ui::MouseEvent& event) {
   return native_wrapper_->GetCursor(event.x(), event.y());
 }
 
diff --git a/ui/views/controls/native/native_view_host.h b/ui/views/controls/native/native_view_host.h
index 0b4187b..676cc60 100644
--- a/ui/views/controls/native/native_view_host.h
+++ b/ui/views/controls/native/native_view_host.h
@@ -112,7 +112,7 @@
   void VisibilityChanged(View* starting_from, bool is_visible) override;
   void OnFocus() override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void SetVisible(bool visible) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
 
diff --git a/ui/views/controls/native/native_view_host_aura.cc b/ui/views/controls/native/native_view_host_aura.cc
index 2bfb1d65..9752e79 100644
--- a/ui/views/controls/native/native_view_host_aura.cc
+++ b/ui/views/controls/native/native_view_host_aura.cc
@@ -43,8 +43,8 @@
   gfx::Size GetMaximumSize() const override { return gfx::Size(); }
   void OnBoundsChanged(const gfx::Rect& old_bounds,
                        const gfx::Rect& new_bounds) override {}
-  gfx::NativeCursor GetCursor(const gfx::Point& point) override {
-    return gfx::kNullCursor;
+  ui::Cursor GetCursor(const gfx::Point& point) override {
+    return ui::Cursor();
   }
   int GetNonClientComponent(const gfx::Point& point) const override {
     return HTCLIENT;
@@ -261,10 +261,10 @@
   return nullptr;
 }
 
-gfx::NativeCursor NativeViewHostAura::GetCursor(int x, int y) {
+ui::Cursor NativeViewHostAura::GetCursor(int x, int y) {
   if (host_->native_view())
     return host_->native_view()->GetCursor(gfx::Point(x, y));
-  return gfx::kNullCursor;
+  return ui::Cursor();
 }
 
 void NativeViewHostAura::SetVisible(bool visible) {
diff --git a/ui/views/controls/native/native_view_host_aura.h b/ui/views/controls/native/native_view_host_aura.h
index e486a40..ce3426e7 100644
--- a/ui/views/controls/native/native_view_host_aura.h
+++ b/ui/views/controls/native/native_view_host_aura.h
@@ -52,7 +52,7 @@
   void SetFocus() override;
   gfx::NativeView GetNativeViewContainer() const override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
-  gfx::NativeCursor GetCursor(int x, int y) override;
+  ui::Cursor GetCursor(int x, int y) override;
   void SetVisible(bool visible) override;
   void SetParentAccessible(gfx::NativeViewAccessible) override;
   gfx::NativeViewAccessible GetParentAccessible() override;
diff --git a/ui/views/controls/native/native_view_host_mac.h b/ui/views/controls/native/native_view_host_mac.h
index e1c6d24..5ec9cfc 100644
--- a/ui/views/controls/native/native_view_host_mac.h
+++ b/ui/views/controls/native/native_view_host_mac.h
@@ -61,7 +61,7 @@
   void SetFocus() override;
   gfx::NativeView GetNativeViewContainer() const override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
-  gfx::NativeCursor GetCursor(int x, int y) override;
+  ui::Cursor GetCursor(int x, int y) override;
   void SetVisible(bool visible) override;
   void SetParentAccessible(gfx::NativeViewAccessible) override;
   gfx::NativeViewAccessible GetParentAccessible() override;
diff --git a/ui/views/controls/native/native_view_host_mac.mm b/ui/views/controls/native/native_view_host_mac.mm
index 8335094f..b37f5dc 100644
--- a/ui/views/controls/native/native_view_host_mac.mm
+++ b/ui/views/controls/native/native_view_host_mac.mm
@@ -245,7 +245,7 @@
     return native_view_;
 }
 
-gfx::NativeCursor NativeViewHostMac::GetCursor(int x, int y) {
+ui::Cursor NativeViewHostMac::GetCursor(int x, int y) {
   // Intentionally not implemented: Not required on non-aura Mac because OSX
   // will query the native view for the cursor directly. For NativeViewHostMac
   // in practice, OSX will retrieve the cursor that was last set by
@@ -256,7 +256,7 @@
   // cleared (see -[NativeWidgetMacNSWindow cursorUpdate:]). However, while the
   // pointer is over a RenderWidgetHostViewCocoa, OSX won't ask for the fallback
   // cursor.
-  return gfx::kNullCursor;
+  return ui::Cursor();
 }
 
 void NativeViewHostMac::SetVisible(bool visible) {
diff --git a/ui/views/controls/native/native_view_host_wrapper.h b/ui/views/controls/native/native_view_host_wrapper.h
index c1084a3..3636a50 100644
--- a/ui/views/controls/native/native_view_host_wrapper.h
+++ b/ui/views/controls/native/native_view_host_wrapper.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ui/base/cursor/cursor.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
@@ -102,9 +103,8 @@
   // view.
   virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
 
-  // Returns the native cursor corresponding to the point (x, y)
-  // in the native view.
-  virtual gfx::NativeCursor GetCursor(int x, int y) = 0;
+  // Returns the cursor corresponding to the point (x, y) in the native view.
+  virtual ui::Cursor GetCursor(int x, int y) = 0;
 
   // Sets the visibility of the gfx::NativeView. This differs from
   // {Show,Hide}Widget because it doesn't affect the placement, size,
diff --git a/ui/views/controls/resize_area.cc b/ui/views/controls/resize_area.cc
index 18fa5c1..c0d2e367 100644
--- a/ui/views/controls/resize_area.cc
+++ b/ui/views/controls/resize_area.cc
@@ -10,7 +10,6 @@
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/controls/resize_area_delegate.h"
-#include "ui/views/native_cursor.h"
 
 namespace views {
 
@@ -19,8 +18,9 @@
 
 ResizeArea::~ResizeArea() = default;
 
-gfx::NativeCursor ResizeArea::GetCursor(const ui::MouseEvent& event) {
-  return GetEnabled() ? GetNativeEastWestResizeCursor() : gfx::kNullCursor;
+ui::Cursor ResizeArea::GetCursor(const ui::MouseEvent& event) {
+  return GetEnabled() ? ui::Cursor(ui::mojom::CursorType::kEastWestResize)
+                      : ui::Cursor();
 }
 
 void ResizeArea::OnGestureEvent(ui::GestureEvent* event) {
diff --git a/ui/views/controls/resize_area.h b/ui/views/controls/resize_area.h
index a9c7f6d..f6f13494 100644
--- a/ui/views/controls/resize_area.h
+++ b/ui/views/controls/resize_area.h
@@ -25,7 +25,7 @@
   ~ResizeArea() override;
 
   // views::View:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc
index c770d57..d0e8966 100644
--- a/ui/views/controls/table/table_header.cc
+++ b/ui/views/controls/table/table_header.cc
@@ -27,7 +27,6 @@
 #include "ui/views/controls/table/table_utils.h"
 #include "ui/views/controls/table/table_view.h"
 #include "ui/views/focus/focus_manager.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/style/platform_style.h"
 
 namespace views {
@@ -227,9 +226,9 @@
   table_->UpdateVirtualAccessibilityChildrenBounds();
 }
 
-gfx::NativeCursor TableHeader::GetCursor(const ui::MouseEvent& event) {
+ui::Cursor TableHeader::GetCursor(const ui::MouseEvent& event) {
   return GetResizeColumn(GetMirroredXInView(event.x())) != -1
-             ? GetNativeColumnResizeCursor()
+             ? ui::mojom::CursorType::kColumnResize
              : View::GetCursor(event);
 }
 
diff --git a/ui/views/controls/table/table_header.h b/ui/views/controls/table/table_header.h
index 072cd3de..a435e5d 100644
--- a/ui/views/controls/table/table_header.h
+++ b/ui/views/controls/table/table_header.h
@@ -47,7 +47,7 @@
   bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
   void OnVisibleBoundsChanged() override;
   void AddedToWidget() override;
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index ad0c697..985f989 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -59,7 +59,6 @@
 #include "ui/views/controls/views_text_services_context_menu.h"
 #include "ui/views/drag_utils.h"
 #include "ui/views/layout/layout_provider.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/painter.h"
 #include "ui/views/style/platform_style.h"
 #include "ui/views/views_delegate.h"
@@ -640,13 +639,13 @@
   View::SetBorder(std::move(b));
 }
 
-gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) {
+ui::Cursor Textfield::GetCursor(const ui::MouseEvent& event) {
   bool platform_arrow = PlatformStyle::kTextfieldUsesDragCursorWhenDraggable;
   bool in_selection = GetRenderText()->IsPointInSelection(event.location());
   bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
   bool text_cursor =
       !initiating_drag_ && (drag_event || !in_selection || !platform_arrow);
-  return text_cursor ? GetNativeIBeamCursor() : gfx::kNullCursor;
+  return text_cursor ? ui::mojom::CursorType::kIBeam : ui::Cursor();
 }
 
 bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 46966d4f..fdc2db0 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -326,7 +326,7 @@
   gfx::Size CalculatePreferredSize() const override;
   gfx::Size GetMinimumSize() const override;
   void SetBorder(std::unique_ptr<Border> b) override;
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
diff --git a/ui/views/examples/designer_example.cc b/ui/views/examples/designer_example.cc
index 989aabd..280334f 100644
--- a/ui/views/examples/designer_example.cc
+++ b/ui/views/examples/designer_example.cc
@@ -41,7 +41,6 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/box_layout_view.h"
 #include "ui/views/metadata/view_factory.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/vector_icons.h"
 #include "ui/views/view.h"
 #include "ui/views/view_targeter.h"
@@ -305,21 +304,20 @@
   }
 }
 
-gfx::NativeCursor DesignerExample::GrabHandle::GetCursor(
-    const ui::MouseEvent& event) {
+ui::Cursor DesignerExample::GrabHandle::GetCursor(const ui::MouseEvent& event) {
   switch (position_) {
     case GrabHandlePosition::kTop:
     case GrabHandlePosition::kBottom:
-      return views::GetNativeNorthSouthResizeCursor();
+      return ui::mojom::CursorType::kNorthSouthResize;
     case GrabHandlePosition::kLeft:
     case GrabHandlePosition::kRight:
-      return views::GetNativeEastWestResizeCursor();
+      return ui::mojom::CursorType::kEastWestResize;
     case GrabHandlePosition::kTopLeft:
     case GrabHandlePosition::kBottomRight:
-      return views::GetNativeNorthWestSouthEastResizeCursor();
+      return ui::mojom::CursorType::kNorthWestSouthEastResize;
     case GrabHandlePosition::kTopRight:
     case GrabHandlePosition::kBottomLeft:
-      return views::GetNativeNorthEastSouthWestResizeCursor();
+      return ui::mojom::CursorType::kNorthEastSouthWestResize;
   }
 }
 
diff --git a/ui/views/examples/designer_example.h b/ui/views/examples/designer_example.h
index 8dc81c0..0bc1309 100644
--- a/ui/views/examples/designer_example.h
+++ b/ui/views/examples/designer_example.h
@@ -84,7 +84,7 @@
 
    protected:
     // View overrides.
-    gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+    ui::Cursor GetCursor(const ui::MouseEvent& event) override;
     gfx::Size CalculatePreferredSize() const override;
     void OnPaint(gfx::Canvas* canvas) override;
     bool OnMousePressed(const ui::MouseEvent& event) override;
diff --git a/ui/views/native_cursor.h b/ui/views/native_cursor.h
deleted file mode 100644
index 6e01b2d..0000000
--- a/ui/views/native_cursor.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_NATIVE_CURSOR_H_
-#define UI_VIEWS_NATIVE_CURSOR_H_
-
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-
-VIEWS_EXPORT gfx::NativeCursor GetNativeIBeamCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeHandCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeColumnResizeCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeEastWestResizeCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeNorthSouthResizeCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeNorthWestSouthEastResizeCursor();
-VIEWS_EXPORT gfx::NativeCursor GetNativeNorthEastSouthWestResizeCursor();
-
-}  // namespace views
-
-#endif  // UI_VIEWS_NATIVE_CURSOR_H_
diff --git a/ui/views/native_cursor_aura.cc b/ui/views/native_cursor_aura.cc
deleted file mode 100644
index d9b86c31..0000000
--- a/ui/views/native_cursor_aura.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/native_cursor.h"
-
-#include "ui/base/cursor/cursor.h"
-#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
-
-namespace views {
-
-gfx::NativeCursor GetNativeIBeamCursor() {
-  return ui::mojom::CursorType::kIBeam;
-}
-
-gfx::NativeCursor GetNativeHandCursor() {
-  return ui::mojom::CursorType::kHand;
-}
-
-gfx::NativeCursor GetNativeColumnResizeCursor() {
-  return ui::mojom::CursorType::kColumnResize;
-}
-
-gfx::NativeCursor GetNativeEastWestResizeCursor() {
-  return ui::mojom::CursorType::kEastWestResize;
-}
-
-gfx::NativeCursor GetNativeNorthSouthResizeCursor() {
-  return ui::mojom::CursorType::kNorthSouthResize;
-}
-
-gfx::NativeCursor GetNativeNorthWestSouthEastResizeCursor() {
-  return ui::mojom::CursorType::kNorthWestSouthEastResize;
-}
-
-gfx::NativeCursor GetNativeNorthEastSouthWestResizeCursor() {
-  return ui::mojom::CursorType::kNorthEastSouthWestResize;
-}
-
-}  // namespace views
diff --git a/ui/views/native_cursor_mac.mm b/ui/views/native_cursor_mac.mm
deleted file mode 100644
index 059de768..0000000
--- a/ui/views/native_cursor_mac.mm
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/native_cursor.h"
-
-#include <Cocoa/Cocoa.h>
-
-#include "base/notreached.h"
-
-namespace views {
-
-gfx::NativeCursor GetNativeIBeamCursor() {
-  return [NSCursor IBeamCursor];
-}
-
-gfx::NativeCursor GetNativeArrowCursor() {
-  return [NSCursor arrowCursor];
-}
-
-gfx::NativeCursor GetNativeHandCursor() {
-  return [NSCursor pointingHandCursor];
-}
-
-gfx::NativeCursor GetNativeColumnResizeCursor() {
-  return [NSCursor resizeLeftRightCursor];
-}
-
-gfx::NativeCursor GetNativeEastWestResizeCursor() {
-  NOTIMPLEMENTED();
-  // TODO(tapted): This is the wrong cursor. Fetch the right one from WebCursor
-  // or ResourceBundle or CoreCursor private API.
-  return [NSCursor resizeLeftRightCursor];
-}
-
-gfx::NativeCursor GetNativeNorthSouthResizeCursor() {
-  NOTIMPLEMENTED();
-  return [NSCursor resizeUpDownCursor];
-}
-
-gfx::NativeCursor GetNativeNorthWestSouthEastResizeCursor() {
-  NOTIMPLEMENTED();
-  // TODO(tapted): This is the wrong cursor. Fetch the right one from WebCursor
-  // or ResourceBundle or CoreCursor private API.
-  return [NSCursor resizeLeftRightCursor];
-}
-
-gfx::NativeCursor GetNativeNorthEastSouthWestResizeCursor() {
-  NOTIMPLEMENTED();
-  return [NSCursor resizeUpDownCursor];
-}
-
-}  // namespace views
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 0a0ce34..88597c05 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -1358,8 +1358,8 @@
   return this;
 }
 
-gfx::NativeCursor View::GetCursor(const ui::MouseEvent& event) {
-  return gfx::kNullCursor;
+ui::Cursor View::GetCursor(const ui::MouseEvent& event) {
+  return ui::Cursor();
 }
 
 bool View::HitTestPoint(const gfx::Point& point) const {
diff --git a/ui/views/view.h b/ui/views/view.h
index 034e1652..ef40c57 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -29,6 +29,7 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/class_property.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
+#include "ui/base/cursor/cursor.h"
 #include "ui/base/dragdrop/drop_target_event.h"
 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
@@ -994,7 +995,7 @@
   // responsible for managing the lifetime of the returned object, though that
   // lifetime may vary from platform to platform. On Windows and Aura,
   // the cursor is a shared resource.
-  virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event);
+  virtual ui::Cursor GetCursor(const ui::MouseEvent& event);
 
   // A convenience function which calls HitTestRect() with a rect of size
   // 1x1 and an origin of |point|. |point| is in the local coordinate space
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 54373c0..12fa05a 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -1034,7 +1034,7 @@
     content_window_->ScheduleDraw();
 }
 
-void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
+void DesktopNativeWidgetAura::SetCursor(const ui::Cursor& cursor) {
   cursor_ = cursor;
   aura::client::CursorClient* cursor_client =
       aura::client::GetCursorClient(host_->window());
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index 11ae44a..5f578ef 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -190,7 +190,7 @@
                     ui::mojom::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
   void ScheduleLayout() override;
-  void SetCursor(gfx::NativeCursor cursor) override;
+  void SetCursor(const ui::Cursor& cursor) override;
   bool IsMouseEventsEnabled() const override;
   bool IsMouseButtonDown() const override;
   void ClearNativeFocus() override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 586c283..46dc46ed 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -104,8 +104,7 @@
     : delegate_(delegate),
       window_(new aura::Window(this, aura::client::WINDOW_TYPE_UNKNOWN)),
       ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
-      destroying_(false),
-      cursor_(gfx::kNullCursor) {
+      destroying_(false) {
   aura::client::SetFocusChangeObserver(window_, this);
   wm::SetActivationChangeObserver(window_, this);
 }
@@ -768,7 +767,7 @@
     window_->ScheduleDraw();
 }
 
-void NativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
+void NativeWidgetAura::SetCursor(const ui::Cursor& cursor) {
   cursor_ = cursor;
   aura::client::CursorClient* cursor_client =
       aura::client::GetCursorClient(window_->GetRootWindow());
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index f78b1c0..da3db65b 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -147,7 +147,7 @@
                     ui::mojom::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
   void ScheduleLayout() override;
-  void SetCursor(gfx::NativeCursor cursor) override;
+  void SetCursor(const ui::Cursor& cursor) override;
   bool IsMouseEventsEnabled() const override;
   bool IsMouseButtonDown() const override;
   void ClearNativeFocus() override;
@@ -251,7 +251,7 @@
   // Are we in the destructor?
   bool destroying_;
 
-  gfx::NativeCursor cursor_;
+  ui::Cursor cursor_;
 
   std::unique_ptr<TooltipManagerAura> tooltip_manager_;
 
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h
index 2955adf..84b9b647 100644
--- a/ui/views/widget/native_widget_mac.h
+++ b/ui/views/widget/native_widget_mac.h
@@ -175,7 +175,7 @@
                     ui::mojom::DragEventSource source) override;
   void SchedulePaintInRect(const gfx::Rect& rect) override;
   void ScheduleLayout() override;
-  void SetCursor(gfx::NativeCursor cursor) override;
+  void SetCursor(const ui::Cursor& cursor) override;
   void ShowEmojiPanel() override;
   bool IsMouseEventsEnabled() const override;
   bool IsMouseButtonDown() const override;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 96600c8..a56db90 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -710,7 +710,7 @@
     compositor->ScheduleDraw();
 }
 
-void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
+void NativeWidgetMac::SetCursor(const ui::Cursor& cursor) {
   if (GetInProcessNSWindowBridge())
     GetInProcessNSWindowBridge()->SetCursor(cursor);
 }
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index 670c6d4..dda0091 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -37,7 +37,6 @@
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/native/native_view_host.h"
-#include "ui/views/native_cursor.h"
 #include "ui/views/test/native_widget_factory.h"
 #include "ui/views/test/test_widget_observer.h"
 #include "ui/views/test/widget_test.h"
@@ -568,7 +567,7 @@
 // Simple view for the SetCursor test that overrides View::GetCursor().
 class CursorView : public View {
  public:
-  CursorView(int x, NSCursor* cursor) : cursor_(cursor) {
+  CursorView(int x, const ui::Cursor& cursor) : cursor_(cursor) {
     SetBounds(x, 0, 100, 300);
   }
 
@@ -576,12 +575,10 @@
   CursorView& operator=(const CursorView&) = delete;
 
   // View:
-  gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override {
-    return cursor_;
-  }
+  ui::Cursor GetCursor(const ui::MouseEvent& event) override { return cursor_; }
 
  private:
-  NSCursor* cursor_;
+  ui::Cursor cursor_;
 };
 
 // Test for Widget::SetCursor(). There is no Widget::GetCursor(), so this uses
@@ -590,15 +587,15 @@
 // is safe to use this in a non-interactive UI test with the EventGenerator.
 TEST_F(NativeWidgetMacTest, SetCursor) {
   NSCursor* arrow = [NSCursor arrowCursor];
-  NSCursor* hand = GetNativeHandCursor();
-  NSCursor* ibeam = GetNativeIBeamCursor();
+  NSCursor* hand = [NSCursor pointingHandCursor];
+  NSCursor* ibeam = [NSCursor IBeamCursor];
 
   Widget* widget = CreateTopLevelPlatformWidget();
   widget->SetBounds(gfx::Rect(0, 0, 300, 300));
   auto* view_hand = widget->non_client_view()->frame_view()->AddChildView(
-      std::make_unique<CursorView>(0, hand));
+      std::make_unique<CursorView>(0, ui::mojom::CursorType::kHand));
   auto* view_ibeam = widget->non_client_view()->frame_view()->AddChildView(
-      std::make_unique<CursorView>(100, ibeam));
+      std::make_unique<CursorView>(100, ui::mojom::CursorType::kIBeam));
   widget->Show();
   NSWindow* widget_window = widget->GetNativeWindow().GetNativeNSWindow();
 
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h
index 1131983..5aa2ee2ca 100644
--- a/ui/views/widget/native_widget_private.h
+++ b/ui/views/widget/native_widget_private.h
@@ -211,7 +211,7 @@
                             ui::mojom::DragEventSource source) = 0;
   virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
   virtual void ScheduleLayout() = 0;
-  virtual void SetCursor(gfx::NativeCursor cursor) = 0;
+  virtual void SetCursor(const ui::Cursor& cursor) = 0;
   virtual void ShowEmojiPanel();
   virtual bool IsMouseEventsEnabled() const = 0;
   // Returns true if any mouse button is currently down.
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index 8d04e283..dc9c8aab 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -604,7 +604,7 @@
     // some windows.  Let the non-client cursor handling code set the cursor
     // as we do above.
     if (!(event.flags() & ui::EF_IS_NON_CLIENT))
-      widget_->SetCursor(gfx::kNullCursor);
+      widget_->SetCursor(ui::Cursor());
     mouse_move_handler_ = nullptr;
   }
 }
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 77dd782..046d3cf 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -944,7 +944,7 @@
   native_widget_->ScheduleLayout();
 }
 
-void Widget::SetCursor(gfx::NativeCursor cursor) {
+void Widget::SetCursor(const ui::Cursor& cursor) {
   native_widget_->SetCursor(cursor);
 }
 
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 906d3576..d1032f9 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -816,9 +816,8 @@
   // not need to call this.
   void ScheduleLayout();
 
-  // Sets the currently visible cursor. If |cursor| is NULL, the cursor used
-  // before the current is restored.
-  void SetCursor(gfx::NativeCursor cursor);
+  // Sets the currently visible cursor.
+  void SetCursor(const ui::Cursor& cursor);
 
   // Returns true if and only if mouse events are enabled.
   bool IsMouseEventsEnabled() const;