diff --git a/DEPS b/DEPS
index 92435da..e7ac8734 100644
--- a/DEPS
+++ b/DEPS
@@ -202,7 +202,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:81cc063690e374fdad0215a7565a0951e7db8a07',
+  'luci_go': 'git_revision:7422359d33c606e8adb0e9cf461837eb9b49431f',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -234,7 +234,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': 'f46611ebdef95756820f2ec1252bd95703b14002',
+  'skia_revision': 'e2a038f956ff4e7564c40c8653a236aae5e630d1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -242,7 +242,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': 'c789169b4210f66e50f697d10dbfb2cf4a26d197',
+  'angle_revision': 'a56d3c13303b1807ea47c17e1a60865b9c2d29d9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -281,7 +281,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'cff026d41599945498044d2f4dcc0e610ffb6929',
+  'freetype_revision': '64e26ad3a2ef2e07190b2027b113a6b3f6eb8b0d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -309,7 +309,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': 'ac6b7152501bc95023f5e2c04fbb602c46eb04b1',
+  'devtools_frontend_revision': '19b714a6936e90642ad6b0170410fdd14216e2c9',
   # 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.
@@ -349,7 +349,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '1fe05467a6da2781ae63b092d336823724a8ae4a',
+  'dawn_revision': '33a044ea5f8ef2d5bf1c42040d6517eba48462d3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -627,7 +627,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '108f768308391bb70b7222bd9faeb4399fd231ab',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'c8272883386014fc079e8777a2bfb95945e7dda6',
       'condition': 'checkout_ios',
   },
 
@@ -708,7 +708,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': 'ACcUgI9WnZ3UR8P4aJ70iz8pox4s4SlqjZEb1wVvvWcC',
+          'version': 'tjDUZnRDfRwNyESHBJLS2WJSuJJKpq74mSbfBTq5YWgC',
         },
       ],
       'dep_type': 'cipd',
@@ -719,7 +719,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/mac-amd64',
-          'version': 'LRWdXjgDeIZerZXw4js8OHoWZhiFAyIcuFo8O4jZeIoC',
+          'version': 'e21q_i0io864UpRIXAkBKPDHVbkHSDUrDm7QfX0oeosC',
         },
       ],
       'dep_type': 'cipd',
@@ -730,7 +730,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/windows-amd64',
-          'version': 'LK5_G9LZLyQxOEsfut7TB0Oukcdl3rpMaWHJKmwi44MC',
+          'version': '_mv2OMpjccweT-C9WjlRVvg3G6Wl8DKlaXteORrc2ccC',
         },
       ],
       'dep_type': 'cipd',
@@ -791,7 +791,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'qVa1DxDFLR8hbH6wr8ziYpbEPLeUQNDBDCtZaWb0As8C',
+          'version': 'iVGn06-lNVsnXSXyo3Xe7rE4VVi_XIqRPKaXxKiUqp8C',
       },
     ],
     'condition': 'checkout_android',
@@ -1030,7 +1030,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2ffa1bde797a8127c0f72908d0bd74051fd65d0d',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '02f4003fdbfd383192fa725886af79116b1032aa',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1634,7 +1634,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f6f0c1129dffbd7f2c862ea6f7543f3cba582b4c',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ef5b21e6374a499c74827ee52958bc0a15a60b30',
+    Var('webrtc_git') + '/src.git' + '@' + 'ee225438297bb02b9f689e25719870bddcd4991f',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1692,7 +1692,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@759dc387649112f9379d42335dd85ae5323eebf4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0045ab90642dc17c18b4bfb35cbc7584be722005',
     'condition': 'checkout_src_internal',
   },
 
@@ -1711,7 +1711,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '0GcjqHJZegwvsIPHiLEnOFOdfaEK6L26o167s2-hedsC',
+        'version': 'jisTFt0NWEVVF9yxNGc6UAv-_gAHNekfAiyQaAlo7GEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1722,7 +1722,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'JEmXDhN3VbzOI8bjD--35jm3lzsgob59U_G2MC1PgbUC',
+        'version': 'Fhu-2t0HlKzg8-QXxw-EvIHb-l-XUjO8dF4I4pk8qVMC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1733,7 +1733,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'ADozDI7U5gOXhcsAGwaf7UdFBL4oZJ_5V365JsegRLcC',
+        'version': 'PK6ukKmq202iqT4OSpzHijFV-zoxvzJ5h5HaNOC3zqEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index be71da9..d9684b90 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -214,6 +214,8 @@
   android_manifest = "../javatests/AndroidManifest.xml"
   min_sdk_version = default_min_sdk_version
 
+  use_vpython3 = false
+
   deps = [
     ":webview_instrumentation_test_mock_services_java",
     ":webview_instrumentation_test_utils_java",
diff --git a/ash/components/arc/net/arc_net_host_impl.cc b/ash/components/arc/net/arc_net_host_impl.cc
index e81a6b52..ea30ace 100644
--- a/ash/components/arc/net/arc_net_host_impl.cc
+++ b/ash/components/arc/net/arc_net_host_impl.cc
@@ -943,7 +943,8 @@
     const mojom::PasspointCredentials& cred) {
   // Fill in EAP credentials fields.
   if (!cred.eap) {
-    LOG(ERROR) << "Failed to get EAP credentials for passpoint credentials";
+    LOG(ERROR) << "mojom::PasspointCredentials has no EAP properties";
+    return base::Value();
   }
   auto dict = TranslateEapCredentialsToDict(*cred.eap);
 
@@ -972,6 +973,11 @@
     return;
 
   const auto properties = TranslatePasspointCredentialsToDict(*credentials);
+  if (properties.is_none()) {
+    NET_LOG(ERROR) << "Failed to translate PasspointCredentials properties";
+    return;
+  }
+
   const auto* profile = GetNetworkProfile();
   if (!profile || profile->path.empty()) {
     LOG(ERROR) << "Unable to get network profile path";
diff --git a/ash/wm/desks/templates/desks_templates_icon_container.cc b/ash/wm/desks/templates/desks_templates_icon_container.cc
index 4d38e876..811a8a6 100644
--- a/ash/wm/desks/templates/desks_templates_icon_container.cc
+++ b/ash/wm/desks/templates/desks_templates_icon_container.cc
@@ -33,7 +33,6 @@
   int count;
 };
 
-// TODO(chinsenj): Revisit how we determine the sorting order.
 // Given a map from unique icon identifiers to their count, returns an ordered
 // vector of the unique icon identifiers (app ids/urls) and their number of
 // occurrences.
@@ -57,6 +56,54 @@
   return identifiers_with_count;
 }
 
+// Inserts an `IconInfo` struct into `out_identifier_info` if no entry exists
+// for `identifier`. If an entry exists for `identifier`, updates its values.
+void InsertIdentifierInfo(
+    const std::string& identifier,
+    int activation_index,
+    std::map<std::string, IconInfo>* out_identifier_info) {
+  // A single app/site can have multiple windows so count their occurrences and
+  // use the smallest activation index for sorting purposes.
+  if (!base::Contains(*out_identifier_info, identifier)) {
+    (*out_identifier_info)[identifier] = {activation_index, /*count=*/1};
+  } else {
+    ++(*out_identifier_info)[identifier].count;
+    (*out_identifier_info)[identifier].activation_index = std::min(
+        (*out_identifier_info)[identifier].activation_index, activation_index);
+  }
+}
+
+// Iterates through `launch_list`, inserting `IconInfo` structs into
+// `out_identifier_info` for each tab and app.
+void InsertIdentifierInfoFromLaunchList(
+    const std::string& app_id,
+    const app_restore::RestoreData::LaunchList& launch_list,
+    std::map<std::string, IconInfo>* out_identifier_info) {
+  // We want to group active tabs and apps ahead of inactive tabs so offsets
+  // inactive tabs activation index by `kInactiveTabOffset`. In almost every use
+  // case, there should be no more than `kInactiveTabOffset` number of tabs +
+  // apps on a desk.
+  constexpr int kInactiveTabOffset = 10000;
+
+  for (auto& restore_data : launch_list) {
+    const int activation_index = restore_data.second->activation_index.value();
+    if (restore_data.second->urls.has_value()) {
+      const int active_tab_index =
+          restore_data.second->active_tab_index.value();
+      const auto& urls = restore_data.second->urls.value();
+      for (int i = 0; i < static_cast<int>(urls.size()); ++i) {
+        InsertIdentifierInfo(urls[i].spec(),
+                             active_tab_index == i
+                                 ? activation_index
+                                 : kInactiveTabOffset + activation_index,
+                             out_identifier_info);
+      }
+    } else {
+      InsertIdentifierInfo(app_id, activation_index, out_identifier_info);
+    }
+  }
+}
+
 }  // namespace
 
 DesksTemplatesIconContainer::DesksTemplatesIconContainer() {
@@ -80,27 +127,9 @@
   std::map<std::string, IconInfo> identifier_info;
   for (auto& app_id_to_launch_list_entry :
        restore_data->app_id_to_launch_list()) {
-    for (auto& restore_data : app_id_to_launch_list_entry.second) {
-      const std::string& identifier =
-          restore_data.second->urls.has_value()
-              ? restore_data.second->urls
-                    .value()[restore_data.second->active_tab_index.value()]
-                    .spec()
-              : app_id_to_launch_list_entry.first;
-      const int activation_index =
-          restore_data.second->activation_index.value();
-
-      // A single app can have multiple windows so count their occurrences and
-      // use the smallest activation index for sorting purposes.
-      if (!base::Contains(identifier_info, identifier)) {
-        identifier_info[identifier] = {activation_index,
-                                       /*count=*/1};
-      } else {
-        ++identifier_info[identifier].count;
-        identifier_info[identifier].activation_index = std::min(
-            identifier_info[identifier].activation_index, activation_index);
-      }
-    }
+    InsertIdentifierInfoFromLaunchList(app_id_to_launch_list_entry.first,
+                                       app_id_to_launch_list_entry.second,
+                                       &identifier_info);
   }
 
   CreateIconViewsFromIconIdentifiers(SortIconIdentifiers(identifier_info));
@@ -130,14 +159,7 @@
           views::Widget::GetWidgetForNativeWindow(window)->GetColorProvider();
     }
 
-    // A single app can have multiple windows so count their occurrences and
-    // use their index in `windows` as their activation index.
-    if (!base::Contains(identifier_info, app_id)) {
-      identifier_info[app_id] = {/*activation_index=*/static_cast<int>(i),
-                                 /*count=*/1};
-    } else {
-      ++identifier_info[app_id].count;
-    }
+    InsertIdentifierInfo(app_id, i, &identifier_info);
   }
 
   CreateIconViewsFromIconIdentifiers(SortIconIdentifiers(identifier_info));
diff --git a/ash/wm/desks/templates/desks_templates_unittest.cc b/ash/wm/desks/templates/desks_templates_unittest.cc
index c065f6ac..ed0fdff 100644
--- a/ash/wm/desks/templates/desks_templates_unittest.cc
+++ b/ash/wm/desks/templates/desks_templates_unittest.cc
@@ -773,8 +773,6 @@
 }
 
 // Tests that the order of DesksTemplatesItemView is in order.
-// TODO(chinsenj): Once ordering is finalized, update this comment to reflect
-// final ordering. Also this test case should use Browsers as well.
 TEST_F(DesksTemplatesTest, IconsOrder) {
   // Create a `DeskTemplate` using which has 5 apps and each app has 1 window.
   AddEntry(base::GUID::GenerateRandomV4(), "template_1", base::Time::Now(),
@@ -804,6 +802,66 @@
   }
 }
 
+// Tests that icons are ordered such that active tabs and windows are ordered
+// before inactive tabs.
+TEST_F(DesksTemplatesTest, IconsOrderWithInactiveTabs) {
+  const std::string kAppId1 = "app_1";
+  constexpr int kWindowId1 = 1;
+  constexpr int kActiveTabIndex1 = 1;
+  const std::vector<GURL> kTabs1{GURL("http://a.com"), GURL("http://b.com"),
+                                 GURL("http://c.com")};
+
+  const std::string kAppId2 = "app_2";
+  constexpr int kWindowId2 = 2;
+  constexpr int kActiveTabIndex2 = 2;
+  const std::vector<GURL> kTabs2{GURL("http://d.com"), GURL("http://e.com"),
+                                 GURL("http://f.com")};
+
+  // Create `restore_data` for the template.
+  auto restore_data = std::make_unique<app_restore::RestoreData>();
+
+  // Add app launch info for the first browser instance.
+  auto app_launch_info_1 =
+      std::make_unique<app_restore::AppLaunchInfo>(kAppId1, kWindowId1);
+  app_launch_info_1->active_tab_index = kActiveTabIndex1;
+  app_launch_info_1->urls = absl::make_optional(kTabs1);
+  restore_data->AddAppLaunchInfo(std::move(app_launch_info_1));
+  app_restore::WindowInfo window_info_1;
+  window_info_1.activation_index = absl::make_optional<int32_t>(kWindowId1);
+  restore_data->ModifyWindowInfo(kAppId1, kWindowId1, window_info_1);
+
+  // Add app launch info for the second browser instance.
+  auto app_launch_info_2 =
+      std::make_unique<app_restore::AppLaunchInfo>(kAppId2, kWindowId2);
+  app_launch_info_2->active_tab_index = kActiveTabIndex2;
+  app_launch_info_2->urls = absl::make_optional(kTabs2);
+  restore_data->AddAppLaunchInfo(std::move(app_launch_info_2));
+  app_restore::WindowInfo window_info_2;
+  window_info_2.activation_index = absl::make_optional<int32_t>(kWindowId2);
+  restore_data->ModifyWindowInfo(kAppId2, kWindowId2, window_info_2);
+
+  AddEntry(base::GUID::GenerateRandomV4(), "template_1", base::Time::Now(),
+           std::move(restore_data));
+
+  OpenOverviewAndShowTemplatesGrid();
+
+  // Get the icon views.
+  DesksTemplatesItemView* item_view = GetItemViewFromOverviewGrid(
+      /*grid_item_index=*/0);
+  const std::vector<DesksTemplatesIconView*>& icon_views =
+      DesksTemplatesItemViewTestApi(item_view).icon_views();
+
+  // Check the icon views. The first two items should be the active tabs,
+  // ordered by activation index. The next two items should be the inactive tabs
+  // with the lowest activation indices, i.e. the rest of the tabs from the
+  // first browser instance.
+  ASSERT_EQ(5u, icon_views.size());
+  EXPECT_EQ(kTabs1[kActiveTabIndex1].spec(), icon_views[0]->icon_identifier());
+  EXPECT_EQ(kTabs2[kActiveTabIndex2].spec(), icon_views[1]->icon_identifier());
+  EXPECT_EQ(kTabs1[0].spec(), icon_views[2]->icon_identifier());
+  EXPECT_EQ(kTabs1[2].spec(), icon_views[3]->icon_identifier());
+}
+
 // Tests that the overflow count view is visible, in bounds, displays the right
 // count when there is more than `DesksTemplatesIconContainer::kMaxIcons` icons.
 TEST_F(DesksTemplatesTest, OverflowIconView) {
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index f3273aa6..80eb4b85 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -629,7 +629,7 @@
 
 extern "C" {
 
-#if !defined(OS_APPLE)
+#if !defined(OS_APPLE) && !defined(OS_ANDROID)
 
 SHIM_ALWAYS_EXPORT void malloc_stats(void) __THROW {}
 
@@ -637,7 +637,7 @@
   return 0;
 }
 
-#endif  // !defined(OS_APPLE)
+#endif  // !defined(OS_APPLE) && !defined(OS_ANDROID)
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 SHIM_ALWAYS_EXPORT struct mallinfo mallinfo(void) __THROW {
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h
index 8dff006..8fe720e8 100644
--- a/base/allocator/partition_allocator/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -53,6 +53,10 @@
 #error "Card table can only be used when *Scan is allowed"
 #endif
 
+// Use batched freeing when sweeping pages. This builds up a freelist in the
+// scanner thread and appends to the slot-span's freelist only once.
+#define PA_STARSCAN_BATCHED_FREE 1
+
 // POSIX is not only UNIX, e.g. macOS and other OSes. We do use Linux-specific
 // features such as futex(2).
 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 21068d4..9f31683 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -155,7 +155,7 @@
     : bucket(bucket), can_store_raw_size(bucket->CanStoreRawSize()) {}
 
 template <bool thread_safe>
-void SlotSpanMetadata<thread_safe>::FreeSlowPath() {
+void SlotSpanMetadata<thread_safe>::FreeSlowPath(size_t number_of_freed) {
 #if DCHECK_IS_ON()
   auto* root = PartitionRoot<thread_safe>::FromSlotSpan(this);
   root->lock_.AssertAcquired();
@@ -185,11 +185,13 @@
     // Ensure that the slot span is full. That's the only valid case if we
     // arrive here.
     PA_DCHECK(num_allocated_slots < 0);
-    // A transition of num_allocated_slots from 0 to -1 is not legal, and
-    // likely indicates a double-free.
-    PA_CHECK(num_allocated_slots != -1);
-    num_allocated_slots = -num_allocated_slots - 2;
-    PA_DCHECK(num_allocated_slots == bucket->get_slots_per_span() - 1);
+    // A transition of num_allocated_slots from 0 to a negative value is not
+    // legal, and likely indicates a double-free.
+    PA_CHECK(static_cast<intptr_t>(num_allocated_slots) <
+             -static_cast<intptr_t>(number_of_freed));
+    num_allocated_slots = -num_allocated_slots - 2 * number_of_freed;
+    PA_DCHECK(static_cast<size_t>(num_allocated_slots) ==
+              bucket->get_slots_per_span() - number_of_freed);
     // Fully used slot span became partially used. It must be put back on the
     // non-full list. Also make it the current slot span to increase the
     // chances of it being filled up again. The old current slot span will be
@@ -202,7 +204,7 @@
     // Special case: for a partition slot span with just a single slot, it may
     // now be empty and we want to run it through the empty logic.
     if (UNLIKELY(num_allocated_slots == 0))
-      FreeSlowPath();
+      FreeSlowPath(number_of_freed /*ignored*/);
   }
 }
 
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index d84aea07..ca9b04f 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -154,9 +154,12 @@
 
   // Public API
   // Note the matching Alloc() functions are in PartitionPage.
-  BASE_EXPORT NOINLINE void FreeSlowPath();
+  BASE_EXPORT NOINLINE void FreeSlowPath(size_t number_of_freed);
   ALWAYS_INLINE PartitionFreelistEntry* PopForAlloc(size_t size);
   ALWAYS_INLINE void Free(void* ptr);
+  ALWAYS_INLINE void AppendFreeList(PartitionFreelistEntry* head,
+                                    PartitionFreelistEntry* tail,
+                                    size_t number_of_freed);
 
   void Decommit(PartitionRoot<thread_safe>* root);
   void DecommitIfPossible(PartitionRoot<thread_safe>* root);
@@ -647,7 +650,51 @@
   SetFreelistHead(entry);
   --num_allocated_slots;
   if (UNLIKELY(num_allocated_slots <= 0)) {
-    FreeSlowPath();
+    FreeSlowPath(1);
+  } else {
+    // All single-slot allocations must go through the slow path to
+    // correctly update the raw size.
+    PA_DCHECK(!CanStoreRawSize());
+  }
+}
+
+template <bool thread_safe>
+ALWAYS_INLINE void SlotSpanMetadata<thread_safe>::AppendFreeList(
+    PartitionFreelistEntry* head,
+    PartitionFreelistEntry* tail,
+    size_t number_of_freed)
+    EXCLUSIVE_LOCKS_REQUIRED(
+        PartitionRoot<thread_safe>::FromSlotSpan(this)->lock_) {
+#if DCHECK_IS_ON()
+  auto* root = PartitionRoot<thread_safe>::FromSlotSpan(this);
+  root->lock_.AssertAcquired();
+  PA_DCHECK(!tail->GetNext(bucket->slot_size));
+  PA_DCHECK(number_of_freed);
+  PA_DCHECK(num_allocated_slots);
+  if (CanStoreRawSize()) {
+    PA_DCHECK(number_of_freed == 1);
+  }
+  {
+    size_t number_of_entries = 0;
+    for (auto* entry = head; entry;
+         entry = entry->GetNext(bucket->slot_size), ++number_of_entries) {
+      // Check that all entries belong to this slot span.
+      PA_DCHECK(ToSlotSpanStartPtr(this) <= entry);
+      PA_DCHECK(reinterpret_cast<char*>(entry) <
+                (static_cast<char*>(ToSlotSpanStartPtr(this)) +
+                 bucket->get_bytes_per_span()));
+    }
+    PA_DCHECK(number_of_entries == number_of_freed);
+  }
+#endif
+
+  tail->SetNext(freelist_head);
+  SetFreelistHead(head);
+  PA_DCHECK(static_cast<size_t>(num_allocated_slots) >= number_of_freed);
+  num_allocated_slots -= number_of_freed;
+
+  if (UNLIKELY(num_allocated_slots <= 0)) {
+    FreeSlowPath(number_of_freed);
   } else {
     // All single-slot allocations must go through the slow path to
     // correctly update the raw size.
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 2b86d09..ee743a3 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -48,6 +48,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
 #include "base/allocator/partition_allocator/partition_bucket_lookup.h"
 #include "base/allocator/partition_allocator/partition_direct_map_extent.h"
+#include "base/allocator/partition_allocator/partition_freelist_entry.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
 #include "base/allocator/partition_allocator/partition_oom.h"
 #include "base/allocator/partition_allocator/partition_page.h"
@@ -203,6 +204,7 @@
   using SlotSpan = internal::SlotSpanMetadata<thread_safe>;
   using Page = internal::PartitionPage<thread_safe>;
   using Bucket = internal::PartitionBucket<thread_safe>;
+  using FreeListEntry = internal::PartitionFreelistEntry;
   using SuperPageExtentEntry =
       internal::PartitionSuperPageExtentEntry<thread_safe>;
   using DirectMapExtent = internal::PartitionDirectMapExtent<thread_safe>;
@@ -492,6 +494,11 @@
   ALWAYS_INLINE void RawFree(void* slot_start, SlotSpan* slot_span)
       LOCKS_EXCLUDED(lock_);
 
+  ALWAYS_INLINE void RawFreeBatch(FreeListEntry* head,
+                                  FreeListEntry* tail,
+                                  size_t size,
+                                  SlotSpan* slot_span) LOCKS_EXCLUDED(lock_);
+
   ALWAYS_INLINE void RawFreeWithThreadCache(void* slot_start,
                                             SlotSpan* slot_span);
 
@@ -1225,6 +1232,26 @@
 }
 
 template <bool thread_safe>
+ALWAYS_INLINE void PartitionRoot<thread_safe>::RawFreeBatch(
+    FreeListEntry* head,
+    FreeListEntry* tail,
+    size_t size,
+    SlotSpan* slot_span) {
+  PA_DCHECK(head);
+  PA_DCHECK(tail);
+  PA_DCHECK(size > 0);
+  PA_DCHECK(slot_span);
+  PA_DCHECK(IsValidSlotSpan(slot_span));
+  // The passed freelist is likely to be just built up, which means that the
+  // corresponding pages were faulted in (without acquiring the lock). So there
+  // is no need to touch pages manually here before the lock.
+  ScopedGuard guard{lock_};
+  total_size_of_allocated_bytes -=
+      (slot_span->GetSlotSizeForBookkeeping() * size);
+  slot_span->AppendFreeList(head, tail, size);
+}
+
+template <bool thread_safe>
 ALWAYS_INLINE void PartitionRoot<thread_safe>::RawFreeWithThreadCache(
     void* slot_start,
     SlotSpan* slot_span) {
diff --git a/base/allocator/partition_allocator/starscan/pcscan_internal.cc b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
index 9b62a6c..23998aa 100644
--- a/base/allocator/partition_allocator/starscan/pcscan_internal.cc
+++ b/base/allocator/partition_allocator/starscan/pcscan_internal.cc
@@ -901,13 +901,15 @@
 
 namespace {
 
-size_t FreeAndUnmarkInCardTable(PartitionRoot<ThreadSafe>* root,
-                                SlotSpanMetadata<ThreadSafe>* slot_span,
-                                void* object) {
-  object = memory::RemaskPtr(object);
-  const size_t slot_size = slot_span->bucket->slot_size;
-  void* slot_start = root->AdjustPointerForExtrasSubtract(object);
-  root->FreeNoHooksImmediate(object, slot_span, slot_start);
+struct SweepStat {
+  // Bytes that were really swept (by calling free()).
+  size_t swept_bytes = 0;
+  // Bytes of marked quarantine memory that were discarded (by calling
+  // madvice(DONT_NEED)).
+  size_t discarded_bytes = 0;
+};
+
+void UnmarkInCardTable(void* object, SlotSpanMetadata<ThreadSafe>* slot_span) {
 #if PA_STARSCAN_USE_CARD_TABLE
   const uintptr_t object_as_uintptr = reinterpret_cast<uintptr_t>(object);
   // Reset card(s) for this quarantined object. Please note that the
@@ -918,21 +920,24 @@
   QuarantineCardTable::GetFrom(object_as_uintptr)
       .Unquarantine(object_as_uintptr, slot_span->GetUtilizedSlotSize());
 #endif
+}
+
+[[maybe_unused]] size_t FreeAndUnmarkInCardTable(
+    PartitionRoot<ThreadSafe>* root,
+    SlotSpanMetadata<ThreadSafe>* slot_span,
+    void* object) {
+  object = memory::RemaskPtr(object);
+  const size_t slot_size = slot_span->bucket->slot_size;
+  void* slot_start = root->AdjustPointerForExtrasSubtract(object);
+  root->FreeNoHooksImmediate(object, slot_span, slot_start);
+  UnmarkInCardTable(object, slot_span);
   return slot_size;
 }
 
-struct SweepStat {
-  // Bytes that were really swept (by calling free()).
-  size_t swept_bytes = 0;
-  // Bytes of marked quarantine memory that were discarded (by calling
-  // madvice(DONT_NEED)).
-  size_t discarded_bytes = 0;
-};
-
-void SweepSuperPage(ThreadSafePartitionRoot* root,
-                    void* super_page,
-                    size_t epoch,
-                    SweepStat& stat) {
+[[maybe_unused]] void SweepSuperPage(ThreadSafePartitionRoot* root,
+                                     void* super_page,
+                                     size_t epoch,
+                                     SweepStat& stat) {
   auto* bitmap = StateBitmapFromPointer(super_page);
   ThreadSafePartitionRoot::FromSuperPage(static_cast<char*>(super_page));
   bitmap->IterateUnmarkedQuarantined(epoch, [root, &stat](uintptr_t ptr) {
@@ -943,10 +948,11 @@
   });
 }
 
-void SweepSuperPageAndDiscardMarkedQuarantine(ThreadSafePartitionRoot* root,
-                                              void* super_page,
-                                              size_t epoch,
-                                              SweepStat& stat) {
+[[maybe_unused]] void SweepSuperPageAndDiscardMarkedQuarantine(
+    ThreadSafePartitionRoot* root,
+    void* super_page,
+    size_t epoch,
+    SweepStat& stat) {
   auto* bitmap = StateBitmapFromPointer(super_page);
   bitmap->IterateQuarantined(epoch, [root, &stat](uintptr_t ptr,
                                                   bool is_marked) {
@@ -976,6 +982,57 @@
   });
 }
 
+[[maybe_unused]] void SweepSuperPageWithBatchedFree(
+    ThreadSafePartitionRoot* root,
+    void* super_page,
+    size_t epoch,
+    SweepStat& stat) {
+  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
+
+  auto* bitmap = StateBitmapFromPointer(super_page);
+
+  SlotSpan* previous_slot_span = nullptr;
+  internal::PartitionFreelistEntry* freelist_tail = nullptr;
+  internal::PartitionFreelistEntry* freelist_head = nullptr;
+  size_t freelist_entries = 0;
+
+  const auto bitmap_iterator = [&](uintptr_t ptr) {
+    auto* ptr_void = reinterpret_cast<void*>(ptr);
+    SlotSpan* current_slot_span = SlotSpan::FromSlotStartPtr(ptr_void);
+    auto* entry = new (ptr_void) PartitionFreelistEntry();
+
+    if (current_slot_span != previous_slot_span) {
+      // We started scanning a new slot span. Flush the accumulated freelist to
+      // the slot-span's freelist. This is a single lock acquired per slot span.
+      if (previous_slot_span && freelist_entries) {
+        root->RawFreeBatch(freelist_head, freelist_tail, freelist_entries,
+                           previous_slot_span);
+      }
+      freelist_head = entry;
+      freelist_tail = nullptr;
+      freelist_entries = 0;
+      previous_slot_span = current_slot_span;
+    }
+
+    if (freelist_tail) {
+      freelist_tail->SetNext(entry);
+    }
+    freelist_tail = entry;
+    ++freelist_entries;
+
+    UnmarkInCardTable(ptr_void, current_slot_span);
+
+    stat.swept_bytes += current_slot_span->bucket->slot_size;
+  };
+
+  bitmap->IterateUnmarkedQuarantinedAndFree(epoch, bitmap_iterator);
+
+  if (previous_slot_span && freelist_entries) {
+    root->RawFreeBatch(freelist_head, freelist_tail, freelist_entries,
+                       previous_slot_span);
+  }
+}
+
 }  // namespace
 
 void PCScanTask::SweepQuarantine() {
@@ -997,11 +1054,17 @@
         auto* root = ThreadSafePartitionRoot::FromSuperPage(
             static_cast<char*>(super_page_as_void));
 
+#if PA_STARSCAN_BATCHED_FREE
+        SweepSuperPageWithBatchedFree(root, super_page_as_void, pcscan_epoch_,
+                                      stat);
+        (void)should_discard;
+#else
         if (UNLIKELY(should_discard && !root->allow_cookie))
           SweepSuperPageAndDiscardMarkedQuarantine(root, super_page_as_void,
                                                    pcscan_epoch_, stat);
         else
           SweepSuperPage(root, super_page_as_void, pcscan_epoch_, stat);
+#endif
       });
 
   stats_.IncreaseSweptSize(stat.swept_bytes);
diff --git a/base/allocator/partition_allocator/starscan/state_bitmap.h b/base/allocator/partition_allocator/starscan/state_bitmap.h
index 9b8e842..b4329b8 100644
--- a/base/allocator/partition_allocator/starscan/state_bitmap.h
+++ b/base/allocator/partition_allocator/starscan/state_bitmap.h
@@ -129,6 +129,12 @@
   //   void(uintptr_t object_start)
   template <typename Callback>
   inline void IterateUnmarkedQuarantined(size_t epoch, Callback) const;
+  // The callback is of type
+  //   void(uintptr_t object_start)
+  // The function is similar as above, but it also frees (clears) the iterated
+  // bits.
+  template <typename Callback>
+  inline void IterateUnmarkedQuarantinedAndFree(size_t epoch, Callback);
 
   inline void Clear();
 
@@ -180,8 +186,11 @@
     FilterUnmarkedQuarantine is_unmarked;
   };
 
-  template <typename Filter, typename CallbackForwarder, typename Callback>
-  inline void IterateImpl(size_t epoch, Callback) const;
+  template <typename Filter,
+            typename CallbackForwarder,
+            typename Callback,
+            bool Clear>
+  inline void IterateImpl(size_t epoch, Callback);
 
   ALWAYS_INLINE CellType LoadCell(size_t cell_index) const;
   ALWAYS_INLINE static constexpr std::pair<size_t, size_t>
@@ -381,11 +390,14 @@
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
-template <typename Filter, typename CallbackForwarder, typename Callback>
+template <typename Filter,
+          typename CallbackForwarder,
+          typename Callback,
+          bool Clear>
 inline void
 StateBitmap<PageSize, PageAlignment, AllocationAlignment>::IterateImpl(
     size_t epoch,
-    Callback callback) const {
+    Callback callback) {
   // The bitmap (|this|) is allocated inside the page with |kPageAlignment|.
   Filter filter{epoch};
   CallbackForwarder callback_forwarder{epoch};
@@ -408,7 +420,15 @@
       const uintptr_t object_address =
           base +
           (object_number * kAllocationAlignment / kBitsNeededForAllocation);
+
       callback_forwarder(callback, object_address, bits);
+
+      if (Clear) {
+        // Clear the current bits.
+        AsAtomicCell(cell_index)
+            .fetch_and(clear_value_mask, std::memory_order_relaxed);
+      }
+
       // Clear current object bit in temporary value to advance iteration.
       value &= clear_value_mask;
     }
@@ -420,8 +440,9 @@
 inline void
 StateBitmap<PageSize, PageAlignment, AllocationAlignment>::IterateAllocated(
     Callback callback) const {
-  IterateImpl<FilterAllocated, SimpleCallbackForwarder, Callback>(
-      0, std::move(callback));
+  const_cast<StateBitmap*>(this)
+      ->IterateImpl<FilterAllocated, SimpleCallbackForwarder, Callback, false>(
+          0, std::move(callback));
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
@@ -429,8 +450,9 @@
 inline void
 StateBitmap<PageSize, PageAlignment, AllocationAlignment>::IterateQuarantined(
     Callback callback) const {
-  IterateImpl<FilterQuarantine, SimpleCallbackForwarder, Callback>(
-      0, std::move(callback));
+  const_cast<StateBitmap*>(this)
+      ->IterateImpl<FilterQuarantine, SimpleCallbackForwarder, Callback, false>(
+          0, std::move(callback));
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
@@ -439,16 +461,26 @@
 StateBitmap<PageSize, PageAlignment, AllocationAlignment>::IterateQuarantined(
     size_t epoch,
     Callback callback) const {
-  IterateImpl<FilterQuarantine, QuarantineCallbackForwarder, Callback>(
-      epoch, std::move(callback));
+  const_cast<StateBitmap*>(this)
+      ->IterateImpl<FilterQuarantine, QuarantineCallbackForwarder, Callback,
+                    false>(epoch, std::move(callback));
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
 template <typename Callback>
 inline void StateBitmap<PageSize, PageAlignment, AllocationAlignment>::
     IterateUnmarkedQuarantined(size_t epoch, Callback callback) const {
-  IterateImpl<FilterUnmarkedQuarantine, SimpleCallbackForwarder, Callback>(
-      epoch, std::move(callback));
+  const_cast<StateBitmap*>(this)
+      ->IterateImpl<FilterUnmarkedQuarantine, SimpleCallbackForwarder, Callback,
+                    false>(epoch, std::move(callback));
+}
+
+template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
+template <typename Callback>
+inline void StateBitmap<PageSize, PageAlignment, AllocationAlignment>::
+    IterateUnmarkedQuarantinedAndFree(size_t epoch, Callback callback) {
+  IterateImpl<FilterUnmarkedQuarantine, SimpleCallbackForwarder, Callback,
+              true>(epoch, std::move(callback));
 }
 
 template <size_t PageSize, size_t PageAlignment, size_t AllocationAlignment>
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py
index ed32431..23c2143 100644
--- a/build/android/pylib/local/device/local_device_gtest_run.py
+++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -528,7 +528,7 @@
           # fact that adb doesn't use ipv6 for it's server, and so doesn't
           # listen on ipv6, but ssh remote forwarding does. 5037 is the port
           # number adb uses for its server.
-          if "[::1]:5037" in subprocess.check_output(
+          if b"[::1]:5037" in subprocess.check_output(
               "ss -o state listening 'sport = 5037'", shell=True):
             logging.error(
                 'Test Server cannot be started with a remote-forwarded adb '
diff --git a/build/android/pylib/local/machine/local_machine_junit_test_run.py b/build/android/pylib/local/machine/local_machine_junit_test_run.py
index 1e02c7e3..411a66d 100644
--- a/build/android/pylib/local/machine/local_machine_junit_test_run.py
+++ b/build/android/pylib/local/machine/local_machine_junit_test_run.py
@@ -270,7 +270,8 @@
 
 
 def _GetTestClasses(file_path):
-  test_jar_paths = subprocess.check_output([file_path, '--print-classpath'])
+  test_jar_paths = subprocess.check_output([file_path,
+                                            '--print-classpath']).decode()
   test_jar_paths = test_jar_paths.split(':')
 
   test_classes = []
diff --git a/build/android/pylib/utils/proguard.py b/build/android/pylib/utils/proguard.py
index 9d5bae28..7236277 100644
--- a/build/android/pylib/utils/proguard.py
+++ b/build/android/pylib/utils/proguard.py
@@ -88,7 +88,7 @@
     would produce a very complex JSON.
   """
 
-  with tempfile.NamedTemporaryFile() as proguard_output:
+  with tempfile.NamedTemporaryFile('w+') as proguard_output:
     cmd_helper.GetCmdStatusAndOutput([
         'java',
         '-jar', _GetProguardPath(),
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index d3833fd..ef59449f 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -790,6 +790,10 @@
       data += invoker.data
     }
 
+    if (defined(invoker.use_vpython3)) {
+      use_vpython3 = invoker.use_vpython3
+    }
+
     executable_args = [
       "@WrappedPath(" + rebase_path(_runner_script, root_build_dir) + ")",
       _test_type,
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 91417e94..aae10aa8 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -3709,6 +3709,7 @@
                                "modules",
                                "proguard_mapping_path",
                                "public_deps",
+                               "use_vpython3",
                                "use_webview_provider",
                              ])
       test_name = invoker.target_name
@@ -3854,7 +3855,9 @@
     _apk_target_name = "${target_name}__test_apk"
     forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
     android_test_apk(_apk_target_name) {
-      forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
+      forward_variables_from(invoker,
+                             "*",
+                             TESTONLY_AND_VISIBILITY + [ "use_vpython3" ])
     }
     instrumentation_test_runner(target_name) {
       forward_variables_from(invoker,
@@ -3869,6 +3872,7 @@
                                "modules",
                                "never_incremental",
                                "public_deps",
+                               "use_vpython3",
                                "use_webview_provider",
                              ])
       android_test_apk = ":${_apk_target_name}"
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 317bbecb..6631b8be 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-7.20211128.3.1
+7.20211129.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 317bbecb..1c60444c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-7.20211128.3.1
+7.20211129.1.1
diff --git a/build/util/generate_wrapper.gni b/build/util/generate_wrapper.gni
index 707bee8..3406013 100644
--- a/build/util/generate_wrapper.gni
+++ b/build/util/generate_wrapper.gni
@@ -92,7 +92,7 @@
       _script_language,
     ]
 
-    if (defined(invoker.use_vpython3) && invoker.use_vpython3) {
+    if (!defined(invoker.use_vpython3) || invoker.use_vpython3) {
       args += [ "--use-vpython3" ]
       data += [ "//.vpython3" ]
     }
diff --git a/chrome/VERSION b/chrome/VERSION
index 5ed64487..37f87bb 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=98
 MINOR=0
-BUILD=4737
+BUILD=4738
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8f3dd66..76b557c 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2915,6 +2915,7 @@
                              "enable_lint",
                              "enforce_resource_overlays_in_tests",
                              "shared_libraries",
+                             "use_vpython3",
                            ])
 
     testonly = true
@@ -3025,6 +3026,8 @@
   # TODO(wnwen): Re-enable when new lint failures are disabled for test targets.
   #enable_lint = true
 
+  use_vpython3 = false
+
   apk_name = "ChromePublicTest"
   android_manifest = chrome_public_test_apk_manifest
   android_manifest_dep = ":chrome_public_test_apk_manifest"
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
index c1473ce3..b8838ff6 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
@@ -20,9 +20,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.autofill_assistant.R;
-import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantMetrics;
 import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantPreferencesUtil;
-import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding;
 import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.components.embedder_support.util.UrlUtilitiesJni;
@@ -85,8 +83,6 @@
      */
     @Override
     public void show(Callback<Integer> callback) {
-        AutofillAssistantMetrics.recordOnBoarding(
-                OnBoarding.OB_SHOWN, mParameters.get(INTENT_IDENTFIER));
         mOnboardingShown = true;
 
         initViewImpl(callback);
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
index f342799..1e3452a7 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
@@ -9,7 +9,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
 import org.chromium.chrome.browser.autofill_assistant.metrics.FeatureModuleInstallation;
-import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding;
 import org.chromium.chrome.browser.autofill_assistant.strings.IntentStrings;
 import org.chromium.content_public.browser.WebContents;
 
@@ -35,20 +34,6 @@
     }
 
     /**
-     * Records the onboarding related action.
-     */
-    public static void recordOnBoarding(@OnBoarding int metric, String intent) {
-        String histogramSuffix = getHistogramSuffixForIntent(intent);
-
-        RecordHistogram.recordEnumeratedHistogram(
-                "Android.AutofillAssistant.OnBoarding." + histogramSuffix, metric,
-                OnBoarding.MAX_VALUE + 1);
-
-        RecordHistogram.recordEnumeratedHistogram(
-                "Android.AutofillAssistant.OnBoarding", metric, OnBoarding.MAX_VALUE + 1);
-    }
-
-    /**
      * Records the feature module installation action.
      */
     public static void recordFeatureModuleInstallation(@FeatureModuleInstallation int metric) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 1c3af51..5d352df 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -198,8 +198,7 @@
     @SmallTest
     @Feature({"NewTabPage", "FeedNewTabPage", "RenderTest"})
     public void testRender_SignInPromoWithAccount() throws Exception {
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(
-                AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
+        mAccountManagerTestRule.addAccount(AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
         // Scroll to the sign in promo in case it is not visible.
         onView(withId(R.id.feed_stream_recycler_view))
                 .perform(RecyclerViewActions.scrollToPosition(SIGNIN_PROMO_POSITION));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
index b4f4f1b2..fbaf62e0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java
@@ -105,8 +105,7 @@
         Assert.assertEquals(0,
                 SharedPreferencesManager.getInstance().readInt(
                         ChromePreferenceKeys.SYNC_PROMO_TOTAL_SHOW_COUNT));
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(
-                AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
+        mAccountManagerTestRule.addAccount(AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
         mPage = loadRecentTabsPage();
         mRenderTestRule.render(mPage.getView(), "personalized_signin_promo_recent_tabs_page");
         Assert.assertEquals(1,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
index fc3dc0a..8abf7fc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
@@ -9,7 +9,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.accounts.Account;
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
 
@@ -125,8 +124,7 @@
     /**
      * Checks that the XML is being created properly.
      */
-    private RequestGenerator createAndCheckXML(
-            DeviceType deviceType, boolean sendInstallEvent, Account... accounts) {
+    private RequestGenerator createAndCheckXML(DeviceType deviceType, boolean sendInstallEvent) {
         Context targetContext = InstrumentationRegistry.getTargetContext();
         AdvancedMockContext context = new AdvancedMockContext(targetContext);
 
@@ -136,10 +134,6 @@
         when(IdentityServicesProvider.get().getIdentityManager(any()).hasPrimaryAccount(anyInt()))
                 .thenReturn(true);
 
-        for (Account account : accounts) {
-            mAccountManagerTestRule.addAccount(account);
-        }
-
         String sessionId = "random_session_id";
         String requestId = "random_request_id";
         String version = "1.2.3.4";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
index 57669c17..8a13019 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java
@@ -197,7 +197,7 @@
         // test case therefore is not currently hittable on a real device; however it is included
         // here for completeness.
         mAccountManagerTestRule.addAccount("the.default.account@gmail.com");
-        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
+        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT.name);
 
         mActivityTestRule.startMainActivityOnBlankPage();
         UserActionTester actionTester = new UserActionTester();
@@ -214,7 +214,7 @@
     @Test
     @MediumTest
     public void signinWhenChildAccountIsFirstAccount() {
-        final CoreAccountInfo childAccount = mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
+        final CoreAccountInfo childAccount = mAccountManagerTestRule.addAccount(CHILD_ACCOUNT.name);
         mAccountManagerTestRule.addAccount("the.second.account@gmail.com");
 
         mActivityTestRule.startMainActivityOnBlankPage();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
index df2ea58..548d29e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
@@ -155,7 +155,7 @@
     @MediumTest
     @Feature("RenderTest")
     public void testFragmentRotationToLandscapeWithAccount() throws IOException {
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1);
         launchActivityWithFragment(Configuration.ORIENTATION_PORTRAIT);
 
         ActivityTestUtils.rotateActivityToOrientation(
@@ -171,7 +171,7 @@
     @MediumTest
     @Feature("RenderTest")
     public void testFragmentRotationToPortraitWithAccount() throws IOException {
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1);
         launchActivityWithFragment(Configuration.ORIENTATION_LANDSCAPE);
 
         ActivityTestUtils.rotateActivityToOrientation(
@@ -189,7 +189,7 @@
     @ParameterAnnotations.UseMethodParameter(NightModeAndOrientationParameterProvider.class)
     public void testFragmentWithAccount(boolean nightModeEnabled, int orientation)
             throws IOException {
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1);
 
         launchActivityWithFragment(orientation);
 
@@ -206,7 +206,7 @@
     public void testFragmentWithAccountOnManagedDevice(boolean nightModeEnabled, int orientation)
             throws IOException {
         when(mPolicyLoadListenerMock.get()).thenReturn(true);
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1);
 
         launchActivityWithFragment(orientation);
 
@@ -234,7 +234,7 @@
         });
         when(mSigninManagerMock.isSigninDisabledByPolicy()).thenReturn(true);
         when(mPolicyLoadListenerMock.get()).thenReturn(true);
-        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+        mAccountManagerTestRule.addAccount(TEST_EMAIL1);
 
         launchActivityWithFragment(orientation);
 
@@ -275,7 +275,7 @@
     @ParameterAnnotations.UseMethodParameter(NightModeAndOrientationParameterProvider.class)
     public void testFragmentWithChildAccount(boolean nightModeEnabled, int orientation)
             throws IOException {
-        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
+        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT.name);
 
         launchActivityWithFragment(orientation);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
index 62affa9d..64ac3aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -44,7 +44,6 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
-import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
@@ -128,11 +127,10 @@
             sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N)
     public void
     testAccountManagementViewForChildAccountWithSecondaryEduAccount() throws Exception {
-        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
+        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT.name);
         // The code under test doesn't care what account type this is, though in practice only
         // EDU accounts are supported on devices where the primary account is a child account.
-        mAccountManagerTestRule.addAccount(
-                AccountUtils.createAccountFromName("account@school.com"));
+        mAccountManagerTestRule.addAccount("account@school.com");
         mAccountManagerTestRule.waitForSeeding();
         final Profile profile = TestThreadUtils.runOnUiThreadBlockingNoException(
                 Profile::getLastUsedRegularProfile);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
index f38d6fd..4e73e8d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
@@ -51,7 +51,7 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class FirstRunFlowSequencerTest {
-    private static final String ADULT_ACCOUNT = "adult.account@gmail.com";
+    private static final String ADULT_ACCOUNT_NAME = "adult.account@gmail.com";
     private static final Account CHILD_ACCOUNT =
             AccountManagerTestRule.createChildAccount(/*baseName=*/"account@gmail.com");
 
@@ -182,7 +182,7 @@
     @Test
     @Feature({"FirstRun"})
     public void testStandardFlowOneChildAccount() {
-        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
+        mAccountManagerTestRule.addAccount(CHILD_ACCOUNT.name);
         when(mDataReductionProxySettingsMock.isDataReductionProxyFREPromoAllowed())
                 .thenReturn(false);
         mDelegate.isSyncAllowed = true;
@@ -206,7 +206,7 @@
     @Test
     @Feature({"FirstRun"})
     public void testStandardFlowShowDataReductionPage() {
-        mAccountManagerTestRule.addAccount(ADULT_ACCOUNT);
+        mAccountManagerTestRule.addAccount(ADULT_ACCOUNT_NAME);
         mAccountManagerTestRule.addAccount("second.test.account@gmail.com");
         mDelegate.isSyncAllowed = true;
         mDelegate.shouldSkipFirstUseHints = false;
@@ -276,7 +276,7 @@
     @Feature({"FirstRun"})
     @CommandLineFlags.Add({ChromeSwitches.FORCE_ENABLE_SIGNIN_FRE})
     public void testFlowShowSyncConsentPageWhenUserIsSignedIn() {
-        mAccountManagerTestRule.addAccount(ADULT_ACCOUNT);
+        mAccountManagerTestRule.addAccount(ADULT_ACCOUNT_NAME);
         when(mIdentityManagerMock.hasPrimaryAccount(ConsentLevel.SIGNIN)).thenReturn(true);
         mDelegate.isSyncAllowed = true;
         mDelegate.shouldSkipFirstUseHints = false;
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 6bef739..49e27dd5f 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2091,6 +2091,7 @@
     "//components/enterprise",
     "//components/enterprise/common/proto:connectors_proto",
     "//components/enterprise/common/proto:extensions_workflow_events_proto",
+    "//components/enterprise/content",
     "//components/error_page/common",
     "//components/error_page/content/browser",
     "//components/favicon/content",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f460c440..e08431b7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2882,6 +2882,12 @@
      flag_descriptions::kAutofillCenterAligngedSuggestionsDescription,
      kOsDesktop,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillCenterAlignedSuggestions)},
+    {"autofill-visual-improvements-for-suggestion-ui",
+     flag_descriptions::kAutofillVisualImprovementsForSuggestionUiName,
+     flag_descriptions::kAutofillVisualImprovementsForSuggestionUiDescription,
+     kOsDesktop,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillVisualImprovementsForSuggestionUi)},
     {"autofill-type-specific-popup-width",
      flag_descriptions::kAutofillTypeSpecificPopupWidthName,
      flag_descriptions::kAutofillTypeSpecificPopupWidthDescription, kOsDesktop,
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index 7a1911f..92b4505 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -460,6 +460,8 @@
   // Do not show the HID Detection screen if device is owned.
   if (!device_is_owned && CanShowHIDDetectionScreen() &&
       first_screen == OobeScreen::SCREEN_UNKNOWN) {
+    // Temp logs for crbug/1274589
+    VLOG(1) << "CheckIsScreenRequired";
     GetScreen<HIDDetectionScreen>()->CheckIsScreenRequired(
         base::BindOnce(&WizardController::OnHIDScreenNecessityCheck,
                        weak_factory_.GetWeakPtr()));
@@ -1963,6 +1965,8 @@
 }
 
 void WizardController::OnHIDScreenNecessityCheck(bool screen_needed) {
+  // Temp logs for crbug/1274589
+  VLOG(1) << "OnHIDScreenNecessityCheck " << screen_needed;
   if (!GetOobeUI())
     return;
 
@@ -2014,6 +2018,8 @@
 }
 
 void WizardController::AdvanceToScreen(OobeScreenId screen_id) {
+  // Temp logs for crbug/1274589
+  VLOG(1) << "AdvanceToScreen " << screen_id;
   if (!CanNavigateTo(screen_id)) {
     LOG(WARNING) << "Cannot advance to screen : " << screen_id
                  << " as it's priority is less than the current screen : "
diff --git a/chrome/browser/ash/policy/networking/euicc_status_uploader.cc b/chrome/browser/ash/policy/networking/euicc_status_uploader.cc
index 4e21740..29c478a 100644
--- a/chrome/browser/ash/policy/networking/euicc_status_uploader.cc
+++ b/chrome/browser/ash/policy/networking/euicc_status_uploader.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/policy/networking/euicc_status_uploader.h"
 
 #include "base/json/json_string_value_serializer.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -236,6 +237,8 @@
 void EuiccStatusUploader::OnStatusUploaded(bool success) {
   currently_uploading_ = false;
   retry_entry_.InformOfRequest(/*succeeded=*/success);
+  base::UmaHistogramBoolean(
+      "Network.Cellular.ESim.Policy.EuiccStatusUploadResult", success);
 
   if (!success) {
     LOG(ERROR) << "Failed to upload EUICC status.";
diff --git a/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc b/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc
index 85cc746..a38095a8 100644
--- a/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc
+++ b/chrome/browser/ash/policy/networking/euicc_status_uploader_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/constants/ash_pref_names.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/values_test_util.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/dbus/shill/shill_manager_client.h"
@@ -66,6 +67,8 @@
 
 const char kFakeObjectPath[] = "object-path";
 const char kFakeEid[] = "12";
+const char kEuiccStatusUploadResultHistogram[] =
+    "Network.Cellular.ESim.Policy.EuiccStatusUploadResult";
 
 const char kEmptyEuiccStatus[] =
     R"(
@@ -249,11 +252,22 @@
 
   int GetRequestCount() { return cloud_policy_client_.num_requests(); }
 
+  void CheckHistogram(int total_count, int success_count, int failed_count) {
+    histogram_tester_.ExpectTotalCount(kEuiccStatusUploadResultHistogram,
+                                       total_count);
+    histogram_tester_.ExpectBucketCount(kEuiccStatusUploadResultHistogram, true,
+                                        /*expected_count=*/success_count);
+    histogram_tester_.ExpectBucketCount(kEuiccStatusUploadResultHistogram,
+                                        false,
+                                        /*expected_count=*/failed_count);
+  }
+
  private:
   content::BrowserTaskEnvironment task_environment_;
   FakeCloudPolicyClient cloud_policy_client_;
   TestingPrefServiceSimple local_state_;
   std::unique_ptr<ash::NetworkHandlerTestHelper> helper_;
+  base::HistogramTester histogram_tester_;
 };
 
 TEST_F(EuiccStatusUploaderTest, EmptySetup) {
@@ -262,6 +276,7 @@
   EXPECT_EQ(GetRequestCount(), 1);
   // No value is uploaded yet.
   EXPECT_EQ("{}", GetStoredPrefString());
+  CheckHistogram(/*total_count=*/1, /*success_count=*/0, /*failed_count=*/1);
 
   // Make server accept requests.
   SetServerSuccessStatus(true);
@@ -269,6 +284,7 @@
   EXPECT_EQ(GetRequestCount(), 2);
   // Verify that last uploaded configuration is stored.
   ValidateUploadedStatus(kEmptyEuiccStatus, /*clear_profile_list=*/false);
+  CheckHistogram(/*total_count=*/2, /*success_count=*/1, /*failed_count=*/1);
 }
 
 TEST_F(EuiccStatusUploaderTest, ServerError) {
@@ -277,11 +293,13 @@
   EXPECT_EQ(GetRequestCount(), 1);
   // No value is uploaded yet.
   EXPECT_EQ("{}", GetStoredPrefString());
+  CheckHistogram(/*total_count=*/1, /*success_count=*/0, /*failed_count=*/1);
 
   UpdateUploader(status_uploader.get());
   EXPECT_EQ(GetRequestCount(), 2);
   // Nothing is stored when requests fail.
   EXPECT_EQ("{}", GetStoredPrefString());
+  CheckHistogram(/*total_count=*/2, /*success_count=*/0, /*failed_count=*/2);
 }
 
 TEST_F(EuiccStatusUploaderTest, Basic) {
@@ -292,6 +310,7 @@
   EXPECT_EQ(GetRequestCount(), 1);
   // No value is uploaded yet.
   EXPECT_EQ("{}", GetStoredPrefString());
+  CheckHistogram(/*total_count=*/1, /*success_count=*/0, /*failed_count=*/1);
 
   // Make server accept requests.
   SetServerSuccessStatus(true);
@@ -300,6 +319,7 @@
   // Verify that last uploaded configuration is stored.
   ValidateUploadedStatus(kEuiccStatusWithOneProfile,
                          /*clear_profile_list=*/false);
+  CheckHistogram(/*total_count=*/2, /*success_count=*/1, /*failed_count=*/1);
 }
 
 TEST_F(EuiccStatusUploaderTest, MultipleProfiles) {
@@ -310,6 +330,7 @@
   EXPECT_EQ(GetRequestCount(), 1);
   // No value is uploaded yet.
   EXPECT_EQ("{}", GetStoredPrefString());
+  CheckHistogram(/*total_count=*/1, /*success_count=*/0, /*failed_count=*/1);
 
   // Make server accept requests.
   SetServerSuccessStatus(true);
@@ -319,6 +340,7 @@
   // Verify that last uploaded configuration is stored.
   ValidateUploadedStatus(kEuiccStatusWithTwoProfiles,
                          /*clear_profile_list=*/false);
+  CheckHistogram(/*total_count=*/2, /*success_count=*/1, /*failed_count=*/1);
 }
 
 TEST_F(EuiccStatusUploaderTest, SameValueAsBefore) {
@@ -331,6 +353,7 @@
   auto status_uploader = CreateStatusUploader();
   // No value is uploaded since it has been previously sent.
   EXPECT_EQ(GetRequestCount(), 0);
+  CheckHistogram(/*total_count=*/0, /*success_count=*/0, /*failed_count=*/0);
 }
 
 TEST_F(EuiccStatusUploaderTest, NewValue) {
@@ -344,6 +367,7 @@
   // Verify that last uploaded configuration is stored.
   ValidateUploadedStatus(kEuiccStatusWithOneProfile,
                          /*clear_profile_list=*/false);
+  CheckHistogram(/*total_count=*/1, /*success_count=*/1, /*failed_count=*/0);
 }
 
 TEST_F(EuiccStatusUploaderTest, ResetRequest) {
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base.h b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base.h
new file mode 100644
index 0000000..c7bef16
--- /dev/null
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base.h
@@ -0,0 +1,78 @@
+// 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 CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_EVENTS_OBSERVER_BASE_H_
+#define CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_EVENTS_OBSERVER_BASE_H_
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "components/reporting/metrics/sampler.h"
+#include "components/reporting/proto/synced/metric_data.pb.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace reporting {
+
+// A base class containing common functionalities needed for observing and
+// reporting cros_healthd events.
+template <typename Interface>
+class CrosHealthdEventsObserverBase : public MetricEventObserver {
+ public:
+  explicit CrosHealthdEventsObserverBase(Interface* interface)
+      : receiver_{interface} {}
+
+  CrosHealthdEventsObserverBase(const CrosHealthdEventsObserverBase&) = delete;
+  CrosHealthdEventsObserverBase& operator=(
+      const CrosHealthdEventsObserverBase&) = delete;
+
+  ~CrosHealthdEventsObserverBase() override = default;
+
+  void SetReportingEnabled(bool is_enabled) override {
+    is_reporting_enabled_ = is_enabled;
+    SetObservation();
+  }
+
+  void SetOnEventObservedCallback(MetricRepeatingCallback cb) override {
+    DCHECK(!on_event_observed_cb_);
+    on_event_observed_cb_ = std::move(cb);
+  }
+
+ protected:
+  virtual void AddObserver() = 0;
+
+  void OnEventObserved(MetricData metric_data) {
+    on_event_observed_cb_.Run(std::move(metric_data));
+  }
+
+  mojo::PendingRemote<Interface> BindNewPipeAndPassRemote() {
+    return receiver_.BindNewPipeAndPassRemote();
+  }
+
+  mojo::Receiver<Interface> receiver_;
+
+ private:
+  void SetObservation() {
+    if (receiver_.is_bound()) {
+      receiver_.reset();
+    }
+
+    if (is_reporting_enabled_) {
+      AddObserver();
+      receiver_.set_disconnect_handler(
+          base::BindOnce(&CrosHealthdEventsObserverBase::SetObservation,
+                         weak_ptr_factory_.GetWeakPtr()));
+    }
+  }
+
+  bool is_reporting_enabled_ = false;
+
+  MetricRepeatingCallback on_event_observed_cb_;
+
+  base::WeakPtrFactory<CrosHealthdEventsObserverBase> weak_ptr_factory_{this};
+};
+}  // namespace reporting
+
+#endif  // CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_CROS_HEALTHD_EVENTS_OBSERVER_BASE_H_
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base_unittest.cc
new file mode 100644
index 0000000..100efe7
--- /dev/null
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base_unittest.cc
@@ -0,0 +1,141 @@
+// 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 "chrome/browser/ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base.h"
+
+#include <string>
+#include <utility>
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
+#include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
+#include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
+#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_events.mojom.h"
+#include "components/reporting/proto/synced/metric_data.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::chromeos::cros_healthd::mojom::CrosHealthdAudioObserver;
+
+namespace reporting {
+namespace {
+
+class FakeCrosHealthdAudioObserver
+    : public CrosHealthdAudioObserver,
+      public CrosHealthdEventsObserverBase<CrosHealthdAudioObserver> {
+ public:
+  FakeCrosHealthdAudioObserver()
+      : CrosHealthdEventsObserverBase<CrosHealthdAudioObserver>(this) {}
+
+  FakeCrosHealthdAudioObserver(const FakeCrosHealthdAudioObserver&) = delete;
+  FakeCrosHealthdAudioObserver& operator=(const FakeCrosHealthdAudioObserver&) =
+      delete;
+
+  ~FakeCrosHealthdAudioObserver() override = default;
+
+  void OnUnderrun() override {
+    MetricData metric_data;
+    metric_data.mutable_telemetry_data();
+    OnEventObserved(std::move(metric_data));
+  }
+
+  void OnSevereUnderrun() override {}
+
+  void FlushForTesting() { receiver_.FlushForTesting(); }
+
+ protected:
+  void AddObserver() override {
+    ::chromeos::cros_healthd::ServiceConnection::GetInstance()
+        ->AddAudioObserver(BindNewPipeAndPassRemote());
+  }
+};
+
+class CrosHealthdEventsObserverBaseTest : public ::testing::Test {
+ public:
+  CrosHealthdEventsObserverBaseTest() = default;
+
+  CrosHealthdEventsObserverBaseTest(const CrosHealthdEventsObserverBaseTest&) =
+      delete;
+  CrosHealthdEventsObserverBaseTest& operator=(
+      const CrosHealthdEventsObserverBaseTest&) = delete;
+
+  ~CrosHealthdEventsObserverBaseTest() override = default;
+
+  void SetUp() override { ::chromeos::CrosHealthdClient::InitializeFake(); }
+
+  void TearDown() override {
+    ::chromeos::CrosHealthdClient::Shutdown();
+
+    // Wait for ServiceConnection to observe the destruction of the client.
+    ::chromeos::cros_healthd::ServiceConnection::GetInstance()
+        ->FlushForTesting();
+  }
+
+ private:
+  base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(CrosHealthdEventsObserverBaseTest, Default) {
+  FakeCrosHealthdAudioObserver audio_observer;
+  MetricData result_metric_data;
+  auto cb = base::BindLambdaForTesting([&](MetricData metric_data) {
+    result_metric_data = std::move(metric_data);
+  });
+  audio_observer.SetOnEventObservedCallback(std::move(cb));
+
+  {
+    base::RunLoop run_loop;
+
+    audio_observer.SetReportingEnabled(true);
+    ::chromeos::cros_healthd::FakeCrosHealthdClient::Get()
+        ->EmitAudioUnderrunEventForTesting();
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // Reporting is enabled.
+  ASSERT_TRUE(result_metric_data.has_telemetry_data());
+
+  // Shutdown cros_healthd to simulate crash.
+  chromeos::CrosHealthdClient::Shutdown();
+  chromeos::cros_healthd::ServiceConnection::GetInstance()->FlushForTesting();
+  // Restart cros_healthd.
+  chromeos::CrosHealthdClient::InitializeFake();
+  audio_observer.FlushForTesting();
+  chromeos::cros_healthd::ServiceConnection::GetInstance()->FlushForTesting();
+
+  result_metric_data.Clear();
+  {
+    base::RunLoop run_loop;
+
+    ::chromeos::cros_healthd::FakeCrosHealthdClient::Get()
+        ->EmitAudioUnderrunEventForTesting();
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // Observer reconnected after crash.
+  EXPECT_TRUE(result_metric_data.has_telemetry_data());
+
+  result_metric_data.Clear();
+  {
+    base::RunLoop run_loop;
+
+    audio_observer.SetReportingEnabled(false);
+    ::chromeos::cros_healthd::FakeCrosHealthdClient::Get()
+        ->EmitAudioUnderrunEventForTesting();
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // Reporting is disabled.
+  EXPECT_FALSE(result_metric_data.has_telemetry_data());
+}
+}  // namespace
+}  // namespace reporting
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index ddfcfb4..408b80d3 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -146,7 +146,7 @@
 }
 }  // namespace
 
-// Crashes on Mac tryslaves.
+// Crashes on Mac trybots.
 // http://crbug.com/165458
 // Also crashes on Windows under Dr. Memory (https://crbug.com/606779),
 // presumably broken on all platforms.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0d5b81f..05cc330a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -186,6 +186,7 @@
 #include "components/embedder_support/content_settings_utils.h"
 #include "components/embedder_support/switches.h"
 #include "components/embedder_support/user_agent_utils.h"
+#include "components/enterprise/content/pref_names.h"
 #include "components/error_page/common/error.h"
 #include "components/error_page/common/error_page_switches.h"
 #include "components/error_page/common/localized_error.h"
@@ -1313,7 +1314,7 @@
   registry->RegisterBooleanPref(prefs::kCorsNonWildcardRequestHeadersSupport,
                                 true);
   registry->RegisterDictionaryPref(
-      policy::policy_prefs::kCopyPreventionSettings);
+      enterprise::content::kCopyPreventionSettings);
 }
 
 // static
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 699601b..9a202f2 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2637,6 +2637,7 @@
     "../ash/policy/reporting/install_event_logger_base.h",
     "../ash/policy/reporting/metrics_reporting/cpu/cpu_info_sampler.cc",
     "../ash/policy/reporting/metrics_reporting/cpu/cpu_info_sampler.h",
+    "../ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base.h",
     "../ash/policy/reporting/metrics_reporting/cros_reporting_settings.cc",
     "../ash/policy/reporting/metrics_reporting/cros_reporting_settings.h",
     "../ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc",
@@ -4372,6 +4373,7 @@
     "../ash/policy/reporting/extension_install_event_logger_unittest.cc",
     "../ash/policy/reporting/install_event_log_util_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/cpu/cpu_info_sampler_unittest.cc",
+    "../ash/policy/reporting/metrics_reporting/cros_healthd_events_observer_base_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/cros_reporting_settings_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/network/https_latency_sampler_unittest.cc",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 2c0b8cf8..0cfdd26 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -500,6 +500,11 @@
     "expiry_milestone": 96
   },
   {
+    "name": "autofill-visual-improvements-for-suggestion-ui",
+    "owners": [ "koerber", "vasilii" ],
+    "expiry_milestone": 100
+  },
+  {
     "name": "back-forward-cache",
     "owners": [ "bfcache-dev@chromium.org" ],
     "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 6b4b9cc4..9a2d2cca 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -294,6 +294,12 @@
     "When enabled, the Autofill suggestion popup will be aligned to the center "
     "of the initiating field and not to its border.";
 
+const char kAutofillVisualImprovementsForSuggestionUiName[] =
+    "Visual improvements for the Autofill and Password Manager suggestion UI.";
+const char kAutofillVisualImprovementsForSuggestionUiDescription[] =
+    "Non function changes that visually improve the suggestion UI used for "
+    "addresses, passswords and credit cards.";
+
 const char kAutofillTypeSpecificPopupWidthName[] =
     "Type-specific width limits for the Autofill popup";
 const char kAutofillTypeSpecificPopupWidthDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 65d0aa6..294b4f0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -177,6 +177,9 @@
 extern const char kAutofillCenterAligngedSuggestionsName[];
 extern const char kAutofillCenterAligngedSuggestionsDescription[];
 
+extern const char kAutofillVisualImprovementsForSuggestionUiName[];
+extern const char kAutofillVisualImprovementsForSuggestionUiDescription[];
+
 extern const char kAutofillTypeSpecificPopupWidthName[];
 extern const char kAutofillTypeSpecificPopupWidthDescription[];
 
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index 1108f86..7b899bd 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -890,9 +890,9 @@
 }
 
 // Regression test to make sure calling GetPreferences() does not re-insert
-// galleries on auto-detected removable devices that were blacklisted.
+// galleries on auto-detected removable devices that were blocklisted.
 TEST_F(MediaFileSystemRegistryTest,
-       GetPreferencesDoesNotReinsertBlacklistedGalleries) {
+       GetPreferencesDoesNotReinsertBlocklistedGalleries) {
   CreateProfileState(1);
   AssertAllAutoAddedGalleries();
 
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller.cc b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
index 0b64b16d..9e41ee8 100644
--- a/chrome/browser/media_galleries/media_galleries_permission_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
@@ -291,7 +291,7 @@
   MediaGalleryPrefInfo gallery;
   DCHECK(preferences_);
   bool gallery_exists = preferences_->LookUpGalleryByPath(path, &gallery);
-  if (gallery_exists && !gallery.IsBlackListedType()) {
+  if (gallery_exists && !gallery.IsBlockListedType()) {
     // The prefs are in sync with |known_galleries_|, so it should exist in
     // |known_galleries_| as well. User selecting a known gallery effectively
     // just sets the gallery to permitted.
@@ -317,7 +317,7 @@
 
   // Lastly, if not found, add a new gallery to |new_galleries_|.
   // prefId == kInvalidMediaGalleryPrefId for completely new galleries.
-  // The old prefId is retained for blacklisted galleries.
+  // The old prefId is retained for blocklisted galleries.
   gallery.pref_id = GetDialogId(gallery.pref_id);
   new_galleries_[gallery.pref_id] = Entry(gallery, true);
   dialog_->UpdateGalleries();
@@ -382,7 +382,7 @@
   const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
   for (auto iter = galleries.begin(); iter != galleries.end(); ++iter) {
     const MediaGalleryPrefInfo& gallery = iter->second;
-    if (gallery.IsBlackListedType())
+    if (gallery.IsBlockListedType())
       continue;
 
     GalleryDialogId gallery_id = GetDialogId(gallery.pref_id);
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller.h b/chrome/browser/media_galleries/media_galleries_permission_controller.h
index f143c08..df7b0e9 100644
--- a/chrome/browser/media_galleries/media_galleries_permission_controller.h
+++ b/chrome/browser/media_galleries/media_galleries_permission_controller.h
@@ -166,7 +166,7 @@
   void SavePermissions();
 
   // Updates the model and view when |preferences_| changes. Some of the
-  // possible changes includes a gallery getting blacklisted, or a new
+  // possible changes includes a gallery getting blocklisted, or a new
   // auto detected gallery becoming available.
   void UpdateGalleriesOnPreferencesEvent();
 
@@ -188,7 +188,7 @@
   // Mapping between pref ids and dialog ids.
   DialogIdMap id_map_;
 
-  // This map excludes those galleries which have been blacklisted; it only
+  // This map excludes those galleries which have been blocklisted; it only
   // counts active known galleries.
   GalleryPermissionsMap known_galleries_;
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc
index 5ca04bb6..cbed5bd 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -78,7 +78,7 @@
 const char kMediaGalleriesScanVideoCountKey[] = "videoCount";
 
 const char kMediaGalleriesTypeAutoDetectedValue[] = "autoDetected";
-const char kMediaGalleriesTypeBlackListedValue[] = "blackListed";
+const char kMediaGalleriesTypeBlockListedValue[] = "blockListed";
 const char kMediaGalleriesTypeRemovedScanValue[] = "removedScan";
 const char kMediaGalleriesTypeScanResultValue[] = "scanResult";
 const char kMediaGalleriesTypeUserAddedValue[] = "userAdded";
@@ -131,8 +131,8 @@
     *type = MediaGalleryPrefInfo::kAutoDetected;
     return true;
   }
-  if (string_type == kMediaGalleriesTypeBlackListedValue) {
-    *type = MediaGalleryPrefInfo::kBlackListed;
+  if (string_type == kMediaGalleriesTypeBlockListedValue) {
+    *type = MediaGalleryPrefInfo::kBlockListed;
     return true;
   }
   if (string_type == kMediaGalleriesTypeScanResultValue) {
@@ -156,8 +156,8 @@
     case MediaGalleryPrefInfo::kAutoDetected:
       result = kMediaGalleriesTypeAutoDetectedValue;
       break;
-    case MediaGalleryPrefInfo::kBlackListed:
-      result = kMediaGalleriesTypeBlackListedValue;
+    case MediaGalleryPrefInfo::kBlockListed:
+      result = kMediaGalleriesTypeBlockListedValue;
       break;
     case MediaGalleryPrefInfo::kScanResult:
       result = kMediaGalleriesTypeScanResultValue;
@@ -385,8 +385,8 @@
   return base_path.empty() ? base_path : base_path.Append(path);
 }
 
-bool MediaGalleryPrefInfo::IsBlackListedType() const {
-  return type == kBlackListed || type == kRemovedScan;
+bool MediaGalleryPrefInfo::IsBlockListedType() const {
+  return type == kBlockListed || type == kRemovedScan;
 }
 
 std::u16string MediaGalleryPrefInfo::GetGalleryDisplayName() const {
@@ -746,7 +746,7 @@
     bool update_gallery_type = false;
     MediaGalleryPrefInfo::Type new_type = existing.type;
     if (type == MediaGalleryPrefInfo::kUserAdded) {
-      if (existing.type == MediaGalleryPrefInfo::kBlackListed) {
+      if (existing.type == MediaGalleryPrefInfo::kBlockListed) {
         new_type = MediaGalleryPrefInfo::kAutoDetected;
         update_gallery_type = true;
       }
@@ -782,10 +782,10 @@
          (existing.last_attach_time != last_attach_time));
 
     bool update_scan_counts =
-      new_type != MediaGalleryPrefInfo::kRemovedScan &&
-      new_type != MediaGalleryPrefInfo::kBlackListed &&
-      (audio_count > 0 || image_count > 0 || video_count > 0 ||
-       existing.audio_count || existing.image_count || existing.video_count);
+        new_type != MediaGalleryPrefInfo::kRemovedScan &&
+        new_type != MediaGalleryPrefInfo::kBlockListed &&
+        (audio_count > 0 || image_count > 0 || video_count > 0 ||
+         existing.audio_count || existing.image_count || existing.video_count);
 
     if (!update_gallery_name && !update_gallery_type &&
         !update_gallery_metadata && !update_scan_counts &&
@@ -954,7 +954,7 @@
   DCHECK(IsInitialized());
   MediaGalleryPrefInfo gallery_info;
   if (LookUpGalleryByPath(path, &gallery_info) &&
-      !gallery_info.IsBlackListedType()) {
+      !gallery_info.IsBlockListedType()) {
     return gallery_info.pref_id;
   }
   return AddOrUpdateGalleryInternal(gallery_info.device_id,
@@ -973,15 +973,16 @@
 }
 
 void MediaGalleriesPreferences::ForgetGalleryById(MediaGalleryPrefId id) {
-  EraseOrBlacklistGalleryById(id, false);
+  EraseOrBlocklistGalleryById(id, false);
 }
 
 void MediaGalleriesPreferences::EraseGalleryById(MediaGalleryPrefId id) {
-  EraseOrBlacklistGalleryById(id, true);
+  EraseOrBlocklistGalleryById(id, true);
 }
 
-void MediaGalleriesPreferences::EraseOrBlacklistGalleryById(
-    MediaGalleryPrefId id, bool erase) {
+void MediaGalleriesPreferences::EraseOrBlocklistGalleryById(
+    MediaGalleryPrefId id,
+    bool erase) {
   DCHECK(IsInitialized());
   PrefService* prefs = profile_->GetPrefs();
   std::unique_ptr<ListPrefUpdate> update(
@@ -1004,7 +1005,7 @@
            type == MediaGalleryPrefInfo::kScanResult)) {
         if (type == MediaGalleryPrefInfo::kAutoDetected) {
           iter->SetStringKey(kMediaGalleriesTypeKey,
-                             kMediaGalleriesTypeBlackListedValue);
+                             kMediaGalleriesTypeBlockListedValue);
         } else {
           iter->SetStringKey(kMediaGalleriesTypeKey,
                              kMediaGalleriesTypeRemovedScanValue);
@@ -1087,7 +1088,7 @@
         continue;
       }
 
-      if (!gallery->second.IsBlackListedType()) {
+      if (!gallery->second.IsBlockListedType()) {
         result.insert(it->pref_id);
       } else {
         NOTREACHED() << gallery->second.device_id;
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.h b/chrome/browser/media_galleries/media_galleries_preferences.h
index b087c64..9f72b65 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.h
+++ b/chrome/browser/media_galleries/media_galleries_preferences.h
@@ -47,7 +47,7 @@
   enum Type {
     kUserAdded,     // Explicitly added by the user.
     kAutoDetected,  // Auto added to the list of galleries.
-    kBlackListed,   // Auto added but then removed by the user.
+    kBlockListed,   // Auto added but then removed by the user.
     kScanResult,    // Discovered by a disk scan.
     kRemovedScan,   // Discovered by a disk scan but then removed by the user.
     kInvalidType,
@@ -68,8 +68,8 @@
   base::FilePath AbsolutePath() const;
 
   // True if the gallery should not be displayed to the user
-  // i.e. kBlackListed || kRemovedScan.
-  bool IsBlackListedType() const;
+  // i.e. kBlockListed || kRemovedScan.
+  bool IsBlockListedType() const;
 
   // The ID that identifies this gallery in this Profile.
   MediaGalleryPrefId pref_id;
@@ -224,7 +224,7 @@
       bool include_unpermitted_galleries);
 
   // Teaches the registry about a new gallery. If the gallery is in a
-  // blacklisted state, it is unblacklisted. |type| should not be a blacklisted
+  // blocklisted state, it is unblocklisted. |type| should not be a blocklisted
   // type. Returns the gallery's pref id.
   MediaGalleryPrefId AddGallery(const std::string& device_id,
                                 const base::FilePath& relative_path,
@@ -239,14 +239,14 @@
                                 int video_count);
 
   // Teach the registry about a gallery simply from the path. If the gallery is
-  // in a blacklisted state, it is unblacklisted. |type| should not be a
-  // blacklisted type. Returns the gallery's pref id.
+  // in a blocklisted state, it is unblocklisted. |type| should not be a
+  // blocklisted type. Returns the gallery's pref id.
   MediaGalleryPrefId AddGalleryByPath(const base::FilePath& path,
                                       MediaGalleryPrefInfo::Type type);
 
   // Logically removes the gallery identified by |id| from the store. For
   // auto added or scan result galleries, this means moving them into a
-  // blacklisted state, otherwise they may come back when they are detected
+  // blocklisted state, otherwise they may come back when they are detected
   // again.
   void ForgetGalleryById(MediaGalleryPrefId id);
 
@@ -315,7 +315,7 @@
       int prefs_version,
       MediaGalleryPrefInfo::DefaultGalleryType default_gallery_type);
 
-  void EraseOrBlacklistGalleryById(MediaGalleryPrefId id, bool erase);
+  void EraseOrBlocklistGalleryById(MediaGalleryPrefId id, bool erase);
 
   // Updates the default galleries: finds the previously default galleries
   // and updates their device IDs (i.e., their paths) inplace if they have
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index 3e5129d..19e2d7b 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -213,7 +213,7 @@
     for (auto it = known_galleries.begin(); it != known_galleries.end(); ++it) {
       VerifyGalleryInfo(it->second, it->first);
       if (it->second.type != MediaGalleryPrefInfo::kAutoDetected &&
-          it->second.type != MediaGalleryPrefInfo::kBlackListed) {
+          it->second.type != MediaGalleryPrefInfo::kBlockListed) {
         if (!base::Contains(expected_galleries_for_all, it->first) &&
             !base::Contains(expected_galleries_for_regular, it->first)) {
           EXPECT_FALSE(gallery_prefs_->NonAutoGalleryHasPermission(it->first));
@@ -500,13 +500,13 @@
   EXPECT_EQ(other_info.device_id(), gallery_info.device_id);
   EXPECT_EQ(relative_path.value(), gallery_info.path.value());
 
-  // Remove an auto added gallery (i.e. make it blacklisted).
+  // Remove an auto added gallery (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(auto_id);
-  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlackListed;
+  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlockListed;
   expected_galleries_for_all.erase(auto_id);
   Verify();
 
-  // Remove a scan result (i.e. make it blacklisted).
+  // Remove a scan result (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(scan_id);
   expected_galleries_[scan_id].type = MediaGalleryPrefInfo::kRemovedScan;
   Verify();
@@ -550,7 +550,7 @@
   Verify();
 
   gallery_prefs()->ForgetGalleryById(auto_forget);
-  expected_galleries_[auto_forget].type = MediaGalleryPrefInfo::kBlackListed;
+  expected_galleries_[auto_forget].type = MediaGalleryPrefInfo::kBlockListed;
   expected_galleries_for_all.erase(auto_forget);
   Verify();
 
@@ -577,7 +577,7 @@
   expected_device_map[device_id].erase(scan_erase);
   Verify();
 
-  // Also erase the previously forgetten ones to check erasing blacklisted ones.
+  // Also erase the previously forgetten ones to check erasing blocklisted ones.
   gallery_prefs()->EraseGalleryById(auto_forget);
   device_id = expected_galleries_[auto_forget].device_id;
   expected_galleries_.erase(auto_forget);
@@ -657,10 +657,10 @@
   Verify();
 }
 
-// Whenever an "AutoDetected" gallery is removed, it is moved to a black listed
-// state.  When the gallery is added again, the black listed state is updated
+// Whenever an "AutoDetected" gallery is removed, it is moved to a block listed
+// state.  When the gallery is added again, the block listed state is updated
 // back to the "AutoDetected" type.
-TEST_F(MediaGalleriesPreferencesTest, AutoAddedBlackListing) {
+TEST_F(MediaGalleriesPreferencesTest, AutoAddedBlockListing) {
   MediaGalleryPrefId auto_id, id;
   base::FilePath path;
   StorageInfo info;
@@ -679,9 +679,9 @@
                         MediaGalleryPrefInfo::kAutoDetected);
   Verify();
 
-  // Remove an auto added gallery (i.e. make it blacklisted).
+  // Remove an auto added gallery (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(auto_id);
-  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlackListed;
+  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlockListed;
   expected_galleries_for_all.erase(auto_id);
   Verify();
 
@@ -700,10 +700,10 @@
   Verify();
 }
 
-// Whenever a "ScanResult" gallery is removed, it is moved to a black listed
-// state.  When the gallery is added again, the black listed state is updated
+// Whenever a "ScanResult" gallery is removed, it is moved to a block listed
+// state.  When the gallery is added again, the block listed state is updated
 // back to the "ScanResult" type.
-TEST_F(MediaGalleriesPreferencesTest, ScanResultBlackListing) {
+TEST_F(MediaGalleriesPreferencesTest, ScanResultBlockListing) {
   MediaGalleryPrefId scan_id, id;
   base::FilePath path;
   StorageInfo info;
@@ -722,7 +722,7 @@
                         MediaGalleryPrefInfo::kScanResult);
   Verify();
 
-  // Remove a scan result gallery (i.e. make it blacklisted).
+  // Remove a scan result gallery (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(scan_id);
   expected_galleries_[scan_id].type = MediaGalleryPrefInfo::kRemovedScan;
   expected_galleries_for_all.erase(scan_id);
@@ -773,8 +773,8 @@
 }
 
 TEST_F(MediaGalleriesPreferencesTest, GalleryPermissions) {
-  MediaGalleryPrefId auto_id, user_added_id, to_blacklist_id, scan_id,
-                     to_scan_remove_id, id;
+  MediaGalleryPrefId auto_id, user_added_id, to_blocklist_id, scan_id,
+      to_scan_remove_id, id;
   base::FilePath path;
   StorageInfo info;
   base::FilePath relative_path;
@@ -803,13 +803,13 @@
                         MediaGalleryPrefInfo::kAutoDetected);
   Verify();
 
-  path = MakeMediaGalleriesTestingPath("to_blacklist");
+  path = MakeMediaGalleriesTestingPath("to_blocklist");
   MediaStorageUtil::GetDeviceInfoFromPath(path, &info, &relative_path);
-  gallery_name = u"ToBlacklistGallery";
+  gallery_name = u"ToBlocklistGallery";
   id = AddGalleryWithNameV1(info.device_id(), gallery_name, relative_path,
                             false /*auto*/);
   EXPECT_EQ(default_galleries_count() + 3UL, id);
-  to_blacklist_id = id;
+  to_blocklist_id = id;
   AddGalleryExpectation(id, gallery_name, info.device_id(), relative_path,
                         MediaGalleryPrefInfo::kAutoDetected);
   Verify();
@@ -848,8 +848,8 @@
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
-      *all_permission_extension.get(), to_blacklist_id, false);
-  expected_galleries_for_all.erase(to_blacklist_id);
+      *all_permission_extension.get(), to_blocklist_id, false);
+  expected_galleries_for_all.erase(to_blocklist_id);
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
@@ -874,8 +874,8 @@
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
-      *all_permission_extension.get(), to_blacklist_id, true);
-  expected_galleries_for_all.insert(to_blacklist_id);
+      *all_permission_extension.get(), to_blocklist_id, true);
+  expected_galleries_for_all.insert(to_blocklist_id);
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
@@ -900,8 +900,8 @@
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
-      *regular_permission_extension.get(), to_blacklist_id, true);
-  expected_galleries_for_regular.insert(to_blacklist_id);
+      *regular_permission_extension.get(), to_blocklist_id, true);
+  expected_galleries_for_regular.insert(to_blocklist_id);
   Verify();
 
   gallery_prefs()->SetGalleryPermissionForExtension(
@@ -914,12 +914,12 @@
   expected_galleries_for_regular.insert(to_scan_remove_id);
   Verify();
 
-  // Blacklist the to be black listed gallery
-  gallery_prefs()->ForgetGalleryById(to_blacklist_id);
-  expected_galleries_[to_blacklist_id].type =
-      MediaGalleryPrefInfo::kBlackListed;
-  expected_galleries_for_all.erase(to_blacklist_id);
-  expected_galleries_for_regular.erase(to_blacklist_id);
+  // Blocklist the to be block listed gallery
+  gallery_prefs()->ForgetGalleryById(to_blocklist_id);
+  expected_galleries_[to_blocklist_id].type =
+      MediaGalleryPrefInfo::kBlockListed;
+  expected_galleries_for_all.erase(to_blocklist_id);
+  expected_galleries_for_regular.erase(to_blocklist_id);
   Verify();
 
   gallery_prefs()->ForgetGalleryById(to_scan_remove_id);
@@ -1095,9 +1095,9 @@
   // Remove the first observer.
   gallery_prefs()->RemoveGalleryChangeObserver(&observer1);
 
-  // Remove an auto added gallery (i.e. make it blacklisted).
+  // Remove an auto added gallery (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(auto_id);
-  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlackListed;
+  expected_galleries_[auto_id].type = MediaGalleryPrefInfo::kBlockListed;
   expected_galleries_for_all.erase(auto_id);
 
   EXPECT_EQ(2, observer1.notifications());
@@ -1140,7 +1140,7 @@
                            relative_path, 4, 5, 6);
   Verify();
 
-  // Remove a scan result (i.e. make it blacklisted).
+  // Remove a scan result (i.e. make it blocklisted).
   gallery_prefs()->ForgetGalleryById(id);
   expected_galleries_[id].type = MediaGalleryPrefInfo::kRemovedScan;
   expected_galleries_[id].audio_count = 0;
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackend.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackend.java
index 69f06fbb..de0d5ec 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackend.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackend.java
@@ -32,6 +32,30 @@
     void getAllLogins(Callback<byte[]> loginsReply, Callback<Exception> failureCallback);
 
     /**
+     * Triggers an async list call to retrieve autofillable logins.
+     *
+     * @param loginsReply Callback that is called on success with serialized {@link
+     *         org.chromium.components.sync.protocol.ListPasswordsResult} data.
+     * @param failureCallback A callback that is called on failure for any reason. May return sync.
+     * TODO(crbug.com/1229655): Remove default keyword after downstream implementation.
+     */
+    default void getAutofillableLogins(
+            Callback<byte[]> loginsReply, Callback<Exception> failureCallback){};
+
+    /**
+     * Triggers an async list call to retrieve logins with matching signon realm.
+     *
+     * @param signonRealm Signon realm string matched by a substring match. The returned results
+     * must be validated (e.g matching "sample.com" also returns logins for "not-sample.com").
+     * @param loginsReply Callback that is called on success with serialized {@link
+     *         org.chromium.components.sync.protocol.ListPasswordsResult} data.
+     * @param failureCallback A callback that is called on failure for any reason. May return sync.
+     * TODO(crbug.com/1229655): Remove default keyword after downstream implementation.
+     */
+    default void getLoginsForSignonRealm(String signonRealm, Callback<byte[]> loginsReply,
+            Callback<Exception> failureCallback){};
+
+    /**
      * Triggers an async call to add a login to the store.
      *
      * @param pwdWithLocalData Serialized PasswordWithLocalData identifying the login to be added.
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 4ff3a03..02330ce7 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -73,15 +73,14 @@
   std::u16string name;
   success = plugin_dict->GetString("name", &name);
   DCHECK(success);
-  bool display_url = true;
-  plugin_dict->GetBoolean("displayurl", &display_url);
+  bool display_url = plugin_dict->FindBoolKey("displayurl").value_or(true);
   std::u16string group_name_matcher;
   success = plugin_dict->GetString("group_name_matcher", &group_name_matcher);
   DCHECK(success);
   std::string language_str;
   plugin_dict->GetString("lang", &language_str);
-  bool plugin_is_deprecated = false;
-  plugin_dict->GetBoolean("plugin_is_deprecated", &plugin_is_deprecated);
+  bool plugin_is_deprecated =
+      plugin_dict->FindBoolKey("plugin_is_deprecated").value_or(false);
 
   std::unique_ptr<PluginMetadata> plugin = std::make_unique<PluginMetadata>(
       identifier, name, display_url, GURL(url), GURL(help_url),
diff --git a/chrome/browser/plugins/plugin_finder_unittest.cc b/chrome/browser/plugins/plugin_finder_unittest.cc
index 893a4c8..2d16fa2 100644
--- a/chrome/browser/plugins/plugin_finder_unittest.cc
+++ b/chrome/browser/plugins/plugin_finder_unittest.cc
@@ -6,10 +6,12 @@
 
 #include "base/values.h"
 #include "chrome/browser/plugins/plugin_metadata.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::DictionaryValue;
-using base::ListValue;
+using ::base::DictionaryValue;
+using ::base::ListValue;
+using ::testing::Optional;
 
 TEST(PluginFinderTest, JsonSyntax) {
   std::unique_ptr<base::DictionaryValue> plugin_list =
@@ -24,7 +26,6 @@
     const base::DictionaryValue* plugin = NULL;
     ASSERT_TRUE(plugin_it.value().GetAsDictionary(&plugin));
     std::string dummy_str;
-    bool dummy_bool;
     if (plugin->HasKey("lang"))
       EXPECT_TRUE(plugin->GetString("lang", &dummy_str));
     if (plugin->HasKey("url"))
@@ -32,13 +33,11 @@
     EXPECT_TRUE(plugin->GetString("name", &dummy_str));
     if (plugin->HasKey("help_url"))
       EXPECT_TRUE(plugin->GetString("help_url", &dummy_str));
-    bool display_url = false;
     if (plugin->HasKey("displayurl")) {
-      EXPECT_TRUE(plugin->GetBoolean("displayurl", &display_url));
-      EXPECT_TRUE(display_url);
+      EXPECT_THAT(plugin->FindBoolKey("displayurl"), Optional(true));
     }
     if (plugin->HasKey("requires_authorization"))
-      EXPECT_TRUE(plugin->GetBoolean("requires_authorization", &dummy_bool));
+      EXPECT_TRUE(plugin->FindBoolKey("requires_authorization").has_value());
     const base::ListValue* mime_types = NULL;
     if (plugin->GetList("mime_types", &mime_types)) {
       for (const auto& mime_type : mime_types->GetList()) {
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 8a1efb7..3155f60 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -67,6 +67,8 @@
 #include "components/embedder_support/pref_names.h"
 #include "components/enterprise/browser/reporting/cloud_reporting_policy_handler.h"
 #include "components/enterprise/browser/reporting/common_pref_names.h"
+#include "components/enterprise/content/copy_prevention_settings_policy_handler.h"
+#include "components/enterprise/content/pref_names.h"
 #include "components/feed/core/shared_prefs/pref_names.h"
 #include "components/history/core/common/pref_names.h"
 #include "components/language/core/browser/pref_names.h"
@@ -1551,9 +1553,6 @@
   { key::kUserAgentClientHintsGREASEUpdateEnabled,
     policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled,
     base::Value::Type::BOOLEAN},
-  { key::kCopyPreventionSettings,
-    policy_prefs::kCopyPreventionSettings,
-    base::Value::Type::DICTIONARY},
 };
 // clang-format on
 
@@ -1806,6 +1805,10 @@
       SCHEMA_ALLOW_UNKNOWN,
       SimpleSchemaValidatingPolicyHandler::RECOMMENDED_PROHIBITED,
       SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED));
+
+  handlers->AddHandler(std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      key::kCopyPreventionSettings,
+      enterprise::content::kCopyPreventionSettings, chrome_schema));
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_WIN) || \
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/liblouis_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/liblouis_test.js
index 9811c7f..e80716c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/liblouis_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/liblouis_test.js
@@ -10,7 +10,8 @@
 // Include test fixture.
 GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']);
 
-ChromeVoxLibLouisTest = class extends ChromeVoxE2ETest {
+// Disabled due to high flakes/failures; see https://crbug.com/1274472.
+DISABLED_ChromeVoxLibLouisTest = class extends ChromeVoxE2ETest {
   createLiblouis() {
     return new LibLouis(
         chrome.extension.getURL('chromevox/braille/liblouis_wrapper.js'), '',
@@ -37,7 +38,8 @@
         chrome.extension.getURL('chromevox/braille/liblouis_wrapper.js'), '',
         testFunc.bind(this));
   };
-  TEST_F('ChromeVoxLibLouisTest', testName, wrappedTestFunc, opt_preamble);
+  TEST_F('DISABLED_ChromeVoxLibLouisTest', testName, wrappedTestFunc,
+         opt_preamble);
 }
 
 function LIBLOUIS_TEST_F_WITH_PREAMBLE(preamble, testName, testFunc) {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_completion_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_completion_fragment.ts
index 468ca10..b5c17875 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_completion_fragment.ts
+++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_completion_fragment.ts
@@ -82,7 +82,7 @@
 
   private onWaaClick_() {
     OpenWindowProxyImpl.getInstance().openURL(
-        loadTimeData.getString('activityControlsUrl'));
+        loadTimeData.getString('activityControlsUrlInPrivacyReview'));
   }
 }
 
diff --git a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/SigninPromoControllerTest.java b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/SigninPromoControllerTest.java
index 6d0e63e..38ffc33b 100644
--- a/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/SigninPromoControllerTest.java
+++ b/chrome/browser/ui/android/signin/junit/src/org/chromium/chrome/browser/ui/signin/SigninPromoControllerTest.java
@@ -36,7 +36,7 @@
 import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
-import org.chromium.components.signin.AccountUtils;
+import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
@@ -96,13 +96,12 @@
 
     @Test
     public void shouldHideSyncPromoForNTPWhenDefaultAccountCannotOfferSyncPromos() {
-        final Account account =
-                AccountUtils.createAccountFromName("test.account.default@gmail.com");
-        mAccountManagerTestRule.addAccount(account);
+        final CoreAccountInfo accountInfo =
+                mAccountManagerTestRule.addAccount("test.account.default@gmail.com");
         mAccountManagerTestRule.addAccount("test.account.secondary@gmail.com");
         doReturn(Optional.of(false))
                 .when(mFakeAccountManagerFacade)
-                .canOfferExtendedSyncPromos(account);
+                .canOfferExtendedSyncPromos(CoreAccountInfo.getAndroidAccountFrom(accountInfo));
 
         Assert.assertFalse(
                 SigninPromoController.canShowSyncPromo(SigninAccessPoint.NTP_CONTENT_SUGGESTIONS));
@@ -110,9 +109,7 @@
 
     @Test
     public void shouldHideSyncPromoForNTPWhenDefaultAccountCapabilityIsNotFetched() {
-        final Account account =
-                AccountUtils.createAccountFromName("test.account.default@gmail.com");
-        mAccountManagerTestRule.addAccount(account);
+        mAccountManagerTestRule.addAccount("test.account.default@gmail.com");
         mAccountManagerTestRule.addAccount("test.account.secondary@gmail.com");
 
         Assert.assertFalse(
@@ -121,16 +118,16 @@
 
     @Test
     public void shouldShowSyncPromoForNTPWhenSecondaryAccountCannotOfferSyncPromos() {
-        final Account secondAccount =
-                AccountUtils.createAccountFromName("test.account.secondary@gmail.com");
+        mAccountManagerTestRule.addAccount("test.account.default@gmail.com");
+        final CoreAccountInfo secondAccountInfo =
+                mAccountManagerTestRule.addAccount("test.account.secondary@gmail.com");
+        final Account secondAccount = CoreAccountInfo.getAndroidAccountFrom(secondAccountInfo);
         doAnswer(invocation -> {
             final Account account0 = invocation.getArgument(0);
             return Optional.of(!account0.equals(secondAccount));
         })
                 .when(mFakeAccountManagerFacade)
                 .canOfferExtendedSyncPromos(any());
-        mAccountManagerTestRule.addAccount("test.account.default@gmail.com");
-        mAccountManagerTestRule.addAccount(secondAccount);
 
         Assert.assertTrue(
                 SigninPromoController.canShowSyncPromo(SigninAccessPoint.NTP_CONTENT_SUGGESTIONS));
diff --git a/chrome/browser/ui/user_education/OWNERS b/chrome/browser/ui/user_education/OWNERS
index 0cee3d9f..62918d8 100644
--- a/chrome/browser/ui/user_education/OWNERS
+++ b/chrome/browser/ui/user_education/OWNERS
@@ -4,3 +4,4 @@
 # Backup
 bsep@chromium.org
 pbos@chromium.org
+dpenning@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 2138aff18..c156f462 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -108,7 +108,7 @@
 int GetContentsVerticalPadding() {
   return ChromeLayoutProvider::Get()->GetDistanceMetric(
       base::FeatureList::IsEnabled(
-          autofill::features::kAutofillCenterAlignedSuggestions)
+          autofill::features::kAutofillVisualImprovementsForSuggestionUi)
           ? DISTANCE_CONTENT_LIST_VERTICAL_SINGLE
           : DISTANCE_CONTENT_LIST_VERTICAL_MULTI);
 }
@@ -760,7 +760,7 @@
     }
 
     if (!base::FeatureList::IsEnabled(
-            features::kAutofillCenterAlignedSuggestions)) {
+            features::kAutofillVisualImprovementsForSuggestionUi)) {
       label->SetEnabledColor(fg_color);
       continue;
     }
@@ -792,7 +792,7 @@
     std::unique_ptr<views::Label> label = CreateLabelWithStyleAndContext(
         text, views::style::CONTEXT_DIALOG_BODY_TEXT,
         base::FeatureList::IsEnabled(
-            features::kAutofillCenterAlignedSuggestions)
+            features::kAutofillVisualImprovementsForSuggestionUi)
             ? views::style::STYLE_PRIMARY
             : views::style::STYLE_SECONDARY);
     KeepLabel(label.get());
@@ -884,7 +884,7 @@
 
 gfx::Font::Weight AutofillPopupSuggestionView::GetPrimaryTextWeight() const {
   return base::FeatureList::IsEnabled(
-             features::kAutofillCenterAlignedSuggestions)
+             features::kAutofillVisualImprovementsForSuggestionUi)
              ? gfx::Font::Weight::NORMAL
              : views::TypographyProvider::MediumWeightForUI();
 }
diff --git a/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc b/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
index 1bcc0bc7..4baa415d 100644
--- a/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
+++ b/chrome/browser/ui/views/sync/inline_login_ui_browsertest.cc
@@ -720,8 +720,9 @@
   ASSERT_FALSE(entry->IsSigninRequired());
 }
 
-// https://crbug.com/1271819: Added Mac due to excessive flakiness
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
+// https://crbug.com/1271819: Added Mac and Win due to excessive flakiness
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
+    defined(OS_WIN)
 #define MAYBE_InvokeUi_default DISABLED_InvokeUi_default
 #else
 #define MAYBE_InvokeUi_default InvokeUi_default
diff --git a/chrome/browser/ui/views/user_education/OWNERS b/chrome/browser/ui/views/user_education/OWNERS
index 79454ae..08d4f80 100644
--- a/chrome/browser/ui/views/user_education/OWNERS
+++ b/chrome/browser/ui/views/user_education/OWNERS
@@ -4,3 +4,4 @@
 # Backup
 bdea@chromium.org
 robliao@chromium.org
+dpenning@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index 073678e..7f01fdc 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -313,6 +313,9 @@
                                 base::ASCIIToUTF16(sync_dashboard_url)));
   html_source->AddString("activityControlsUrl",
                          chrome::kGoogleAccountActivityControlsURL);
+  html_source->AddString(
+      "activityControlsUrlInPrivacyReview",
+      chrome::kGoogleAccountActivityControlsURLInPrivacyReview);
   html_source->AddString("syncDashboardUrl", sync_dashboard_url);
   html_source->AddString(
       "passphraseExplanationText",
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index a62fcab..0c2b5e2 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1638165066-db258650e4e51bb8739074deb8426a157dacee5f.profdata
+chrome-linux-main-1638187072-c0dd588a4a2e599b98ce41cbc553808c7d57cc5b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 42094ce3..1ec8cef5 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1638165066-52c7ac4714b97319b41e8a48505cef9f0d505fba.profdata
+chrome-mac-main-1638187072-b450ad1e8ee0d7f09f6ce94610f4e7c47d20e7aa.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 6dd0528d..ebfee43b 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1638176117-1f2fee57268db1d1424d9a7db4a9d35eb47ad44d.profdata
+chrome-win32-main-1638197998-5dd69ba961935af86cd81a28b3a06c2dfdf5e460.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9f6a77f6..94c1822 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1638176117-83d9647a24675389c052caab609038965280a611.profdata
+chrome-win64-main-1638197998-ee5dc921d19358fe7a268d772324944bf2617f73.profdata
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 585e66a..77ff4dd 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -157,6 +157,10 @@
 const char kGoogleAccountActivityControlsURL[] =
     "https://myaccount.google.com/activitycontrols/search";
 
+const char kGoogleAccountActivityControlsURLInPrivacyReview[] =
+    "https://myaccount.google.com/activitycontrols/"
+    "search&utm_source=chrome&utm_medium=privacy-guide";
+
 const char kGoogleAccountLanguagesURL[] =
     "https://myaccount.google.com/language";
 
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index b08d421..e306255 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -160,6 +160,10 @@
 // URL of the 'Activity controls' section of the privacy settings page.
 extern const char kGoogleAccountActivityControlsURL[];
 
+// URL of the 'Activity controls' section of the privacy settings page, with
+// privacy review parameters and a link for users to manage data.
+extern const char kGoogleAccountActivityControlsURLInPrivacyReview[];
+
 // URL of the Google Account.
 extern const char kGoogleAccountURL[];
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
index f5040f4..52702ee 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
@@ -110,20 +110,6 @@
     }
 
     /**
-     * Adds an account to the fake AccountManagerFacade, if the {@link FakeAccountInfoService} is
-     * set up, add the corresponding {@link AccountInfo} to the {@link FakeAccountInfoService}.
-     * @return The CoreAccountInfo for the account added.
-     */
-    public CoreAccountInfo addAccount(Account account) {
-        if (mFakeAccountInfoService != null) {
-            return addAccountWithNameAndAvatar(account.name);
-        } else {
-            mFakeAccountManagerFacade.addAccount(account);
-            return toCoreAccountInfo(account.name);
-        }
-    }
-
-    /**
      * Adds an account of the given accountName to the fake AccountManagerFacade.
      * @return The CoreAccountInfo for the account added.
      */
@@ -145,16 +131,6 @@
     }
 
     /**
-     * Adds an account to the fake AccountManagerFacade and the corresponding {@link AccountInfo}
-     * with name and avatar to {@link FakeAccountInfoService}.
-     */
-    public CoreAccountInfo addAccountWithNameAndAvatar(String email) {
-        assert mFakeAccountInfoService != null;
-        final String baseEmail = email.split("@", 2)[0];
-        return addAccount(email, baseEmail + ".full", baseEmail + ".given", createAvatar());
-    }
-
-    /**
      * Removes an account with the given account email.
      */
     public void removeAccount(String accountEmail) {
@@ -266,6 +242,30 @@
     }
 
     /**
+     * Adds an account to the fake AccountManagerFacade, if the {@link FakeAccountInfoService} is
+     * set up, add the corresponding {@link AccountInfo} to the {@link FakeAccountInfoService}.
+     * @return The CoreAccountInfo for the account added.
+     */
+    private CoreAccountInfo addAccount(Account account) {
+        if (mFakeAccountInfoService != null) {
+            return addAccountWithNameAndAvatar(account.name);
+        } else {
+            mFakeAccountManagerFacade.addAccount(account);
+            return toCoreAccountInfo(account.name);
+        }
+    }
+
+    /**
+     * Adds an account to the fake AccountManagerFacade and the corresponding {@link AccountInfo}
+     * with name and avatar to {@link FakeAccountInfoService}.
+     */
+    private CoreAccountInfo addAccountWithNameAndAvatar(String email) {
+        assert mFakeAccountInfoService != null;
+        final String baseEmail = email.split("@", 2)[0];
+        return addAccount(email, baseEmail + ".full", baseEmail + ".given", createAvatar());
+    }
+
+    /**
      * Returns an avatar image created from test resource.
      */
     private static Bitmap createAvatar() {
diff --git a/chromeos/system/kiosk_oem_manifest_parser.cc b/chromeos/system/kiosk_oem_manifest_parser.cc
index a70c55ba..1fa79f2 100644
--- a/chromeos/system/kiosk_oem_manifest_parser.cc
+++ b/chromeos/system/kiosk_oem_manifest_parser.cc
@@ -40,9 +40,20 @@
   }
 
   dict->GetString(kDeviceRequisition, &manifest->device_requisition);
-  dict->GetBoolean(kKeyboardDrivenOobe, &manifest->keyboard_driven_oobe);
-  if (!dict->GetBoolean(kEnterpriseManaged, &manifest->enterprise_managed) ||
-      !dict->GetBoolean(kAllowReset, &manifest->can_exit_enrollment)) {
+
+  if (absl::optional<bool> v = dict->FindBoolPath(kKeyboardDrivenOobe)) {
+    manifest->keyboard_driven_oobe = *v;
+  }
+
+  if (absl::optional<bool> v = dict->FindBoolPath(kEnterpriseManaged)) {
+    manifest->enterprise_managed = *v;
+  } else {
+    return false;
+  }
+
+  if (absl::optional<bool> v = dict->FindBoolPath(kAllowReset)) {
+    manifest->can_exit_enrollment = *v;
+  } else {
     return false;
   }
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 7a6f08a..297be2e 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -275,6 +275,7 @@
       "//components/domain_reliability:unit_tests",
       "//components/drive:unit_tests",
       "//components/embedder_support:unit_tests",
+      "//components/enterprise/content:unit_tests",
       "//components/favicon/content:unit_tests",
       "//components/federated_learning:unit_tests",
       "//components/feed:unit_tests",
diff --git a/components/account_manager_core/account.cc b/components/account_manager_core/account.cc
index bb71180..9f1e1ef 100644
--- a/components/account_manager_core/account.cc
+++ b/components/account_manager_core/account.cc
@@ -19,13 +19,26 @@
 }
 
 bool AccountKey::operator==(const AccountKey& other) const {
-  return id_ == other.id_ && account_type_ == other.account_type_;
+  return std::tie(id_, account_type_) ==
+         std::tie(other.id_, other.account_type_);
 }
 
 bool AccountKey::operator!=(const AccountKey& other) const {
   return !(*this == other);
 }
 
+bool Account::operator<(const Account& other) const {
+  return std::tie(key, raw_email) < std::tie(other.key, other.raw_email);
+}
+
+bool Account::operator==(const Account& other) const {
+  return std::tie(key, raw_email) == std::tie(other.key, other.raw_email);
+}
+
+bool Account::operator!=(const Account& other) const {
+  return !(*this == other);
+}
+
 COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
 std::ostream& operator<<(std::ostream& os, const AccountType& account_type) {
   switch (account_type) {
diff --git a/components/account_manager_core/account.h b/components/account_manager_core/account.h
index b3c19bc..d6c2ac69 100644
--- a/components/account_manager_core/account.h
+++ b/components/account_manager_core/account.h
@@ -39,7 +39,7 @@
   bool operator!=(const AccountKey& other) const;
 
  private:
-  // Fields are not const to allow assignmenent operator.
+  // Fields are not const to allow assignment operator.
   std::string id_;
   AccountType account_type_;
 };
@@ -51,6 +51,10 @@
 
   // The raw, un-canonicalized email id for this account.
   std::string raw_email;
+
+  bool operator<(const Account& other) const;
+  bool operator==(const Account& other) const;
+  bool operator!=(const Account& other) const;
 };
 
 // For logging.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 167ee7e..80ec0cf 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -422,6 +422,12 @@
 const base::Feature kAutofillUseUnassociatedListedElements{
     "AutofillUseUnassociatedListedElements", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Introduces various visual improvements of the Autofill suggestion UI that is
+// also used for the password manager.
+const base::Feature kAutofillVisualImprovementsForSuggestionUi{
+    "AutofillVisualImprovementsForSuggestionUi",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls an ablation study in which autofill for addresses and payment data
 // can be suppressed.
 const base::Feature kAutofillEnableAblationStudy{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 979d5f7..48a7738e 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -157,6 +157,8 @@
 extern const base::Feature kAutofillUseConsistentPopupSettingsIcons;
 COMPONENT_EXPORT(AUTOFILL)
 extern const base::Feature kAutofillUseUnassociatedListedElements;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillVisualImprovementsForSuggestionUi;
 
 COMPONENT_EXPORT(AUTOFILL)
 extern const base::Feature kAutofillEnableAblationStudy;
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index b987b6b1..bc2c43ca 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -431,9 +431,6 @@
 
 CollectUserDataAction::LoginDetails::~LoginDetails() = default;
 
-CollectUserDataAction::MetricsData::MetricsData() = default;
-CollectUserDataAction::MetricsData::~MetricsData() = default;
-
 CollectUserDataAction::CollectUserDataAction(ActionDelegate* delegate,
                                              const ActionProto& proto)
     : Action(delegate, proto) {
@@ -526,6 +523,8 @@
   collect_user_data_options_->selected_user_data_changed_callback =
       base::BindRepeating(&CollectUserDataAction::OnSelectionStateChanged,
                           weak_ptr_factory_.GetWeakPtr());
+  collect_user_data_options_->reload_data_callback = base::BindOnce(
+      &CollectUserDataAction::ReloadAction, weak_ptr_factory_.GetWeakPtr());
   if (requests_pwm_logins) {
     delegate_->GetWebsiteLoginManager()->GetLoginsForUrl(
         delegate_->GetWebContents()->GetLastCommittedURL(),
@@ -539,17 +538,21 @@
 }
 
 void CollectUserDataAction::EndAction(const ClientStatus& status) {
-  delegate_->CleanUpAfterPrompt();
   metrics_data_.action_successful = status.ok();
-  UpdateProcessedAction(status);
   MaybeLogMetrics();
   if (metrics_data_.action_successful) {
     delegate_->SetLastSuccessfulUserDataOptions(
         std::move(collect_user_data_options_));
   }
+  delegate_->CleanUpAfterPrompt();
+  UpdateProcessedAction(status);
   std::move(callback_).Run(std::move(processed_action_proto_));
 }
 
+bool CollectUserDataAction::HasActionEnded() const {
+  return !callback_;
+}
+
 void CollectUserDataAction::OnGetLogins(
     const LoginDetailsProto::LoginOptionProto& login_option,
     std::vector<WebsiteLoginManager::Login> logins) {
@@ -678,16 +681,7 @@
   UpdateDateTimeRangeStart(user_data);
   UpdateDateTimeRangeEnd(user_data);
 
-  // Gather info for UMA histograms.
-  if (!shown_to_user_) {
-    shown_to_user_ = true;
-    metrics_data_.source_id =
-        ukm::GetSourceIdForWebContentsDocument(delegate_->GetWebContents());
-    FillInitialDataStateForMetrics(user_data->available_contacts_,
-                                   user_data->available_addresses_,
-                                   user_data->available_payment_instruments_);
-    FillInitiallySelectedDataStateForMetrics(user_data);
-  }
+  UpdateMetrics(user_data);
 
   if (collect_user_data.has_prompt()) {
     delegate_->SetStatusMessage(collect_user_data.prompt());
@@ -697,12 +691,33 @@
   delegate_->CollectUserData(collect_user_data_options_.get());
 }
 
+void CollectUserDataAction::UpdateMetrics(UserData* user_data) {
+  DCHECK(user_data);
+  if (!shown_to_user_) {
+    shown_to_user_ = true;
+    if (user_data->previous_user_data_metrics_) {
+      // Restore metrics data from a previous run that was interrupted by
+      // reloading the user data.
+      metrics_data_ = *user_data->previous_user_data_metrics_;
+    } else {
+      metrics_data_.source_id =
+          ukm::GetSourceIdForWebContentsDocument(delegate_->GetWebContents());
+      FillInitialDataStateForMetrics(user_data->available_contacts_,
+                                     user_data->available_addresses_,
+                                     user_data->available_payment_instruments_);
+      FillInitiallySelectedDataStateForMetrics(user_data);
+    }
+  }
+  user_data->previous_user_data_metrics_.reset();
+}
+
 void CollectUserDataAction::OnGetUserData(
     const CollectUserDataProto& collect_user_data,
     UserData* user_data,
     const UserModel* user_model) {
-  if (!callback_)
+  if (HasActionEnded()) {
     return;
+  }
   action_stopwatch_.StartActiveTime();
   delegate_->GetPersonalDataManager()->RemoveObserver(this);
 
@@ -719,8 +734,9 @@
     int index,
     UserData* user_data,
     const UserModel* user_model) {
-  if (!callback_)
+  if (HasActionEnded()) {
     return;
+  }
   action_stopwatch_.StartActiveTime();
   delegate_->GetPersonalDataManager()->RemoveObserver(this);
 
@@ -734,8 +750,9 @@
     int link,
     UserData* user_data,
     const UserModel* user_model) {
-  if (!callback_)
+  if (HasActionEnded()) {
     return;
+  }
   action_stopwatch_.StartActiveTime();
   delegate_->GetPersonalDataManager()->RemoveObserver(this);
 
@@ -745,6 +762,20 @@
   EndAction(ClientStatus(ACTION_APPLIED));
 }
 
+void CollectUserDataAction::ReloadAction(UserData* user_data) {
+  if (HasActionEnded()) {
+    return;
+  }
+  action_stopwatch_.StartActiveTime();
+  delegate_->GetPersonalDataManager()->RemoveObserver(this);
+
+  metrics_data_.personal_data_changed = true;
+  user_data->previous_user_data_metrics_ = metrics_data_;
+  // We do not wish to log this yet.
+  metrics_data_.metrics_logged = true;
+  EndAction(ClientStatus(RESEND_USER_DATA));
+}
+
 void CollectUserDataAction::OnSelectionStateChanged(
     UserDataEventField field,
     UserDataEventType event_type) {
@@ -1731,7 +1762,7 @@
 }
 
 void CollectUserDataAction::OnPersonalDataChanged() {
-  if (!callback_) {
+  if (HasActionEnded()) {
     return;
   }
 
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.h b/components/autofill_assistant/browser/actions/collect_user_data_action.h
index 3f28349..5ddd78b 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action.h
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action.h
@@ -75,41 +75,9 @@
     absl::optional<WebsiteLoginManager::Login> login;
   };
 
-  struct MetricsData {
-    MetricsData();
-    ~MetricsData();
-    bool metrics_logged = false;
-    ukm::SourceId source_id;
-
-    bool initially_prefilled = false;
-    bool personal_data_changed = false;
-    bool action_successful = false;
-
-    // Selection states.
-    Metrics::UserDataSelectionState contact_selection_state =
-        Metrics::UserDataSelectionState::NO_CHANGE;
-    Metrics::UserDataSelectionState credit_card_selection_state =
-        Metrics::UserDataSelectionState::NO_CHANGE;
-    Metrics::UserDataSelectionState shipping_selection_state =
-        Metrics::UserDataSelectionState::NO_CHANGE;
-
-    // Initial counts of complete/incomplete entries.
-    int complete_contacts_initial_count;
-    int incomplete_contacts_initial_count;
-    int complete_credit_cards_initial_count;
-    int incomplete_credit_cards_initial_count;
-    int complete_shipping_addresses_initial_count;
-    int incomplete_shipping_addresses_initial_count;
-
-    // Bitmasks of fields present in the initially selected entries.
-    int selected_contact_field_bitmask;
-    int selected_shipping_address_field_bitmask;
-    int selected_credit_card_field_bitmask;
-    int selected_billing_address_field_bitmask;
-  };
-
   void InternalProcessAction(ProcessActionCallback callback) override;
   void EndAction(const ClientStatus& status);
+  bool HasActionEnded() const;
 
   void OnGetUserData(const CollectUserDataProto& collect_user_data,
                      UserData* user_data,
@@ -120,6 +88,7 @@
   void OnTermsAndConditionsLinkClicked(int link,
                                        UserData* user_data,
                                        const UserModel* user_model);
+  void ReloadAction(UserData* user_data);
 
   // Only used for logging purposes.
   void OnSelectionStateChanged(UserDataEventField field,
@@ -129,6 +98,7 @@
                    std::vector<WebsiteLoginManager::Login> logins);
   void ShowToUser();
   void OnShowToUser(UserData* user_data, UserData::FieldChange* field_change);
+  void UpdateMetrics(UserData* user_data);
 
   // Creates a new instance of |CollectUserDataOptions| from |proto_|.
   bool CreateOptionsFromProto();
@@ -163,7 +133,7 @@
                               UserData::FieldChange* field_change = nullptr);
   void MaybeLogMetrics();
 
-  MetricsData metrics_data_;
+  UserDataMetrics metrics_data_;
   bool shown_to_user_ = false;
   std::unique_ptr<CollectUserDataOptions> collect_user_data_options_;
   ProcessActionCallback callback_;
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index c312c37..71841a98 100644
--- a/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -3699,5 +3699,94 @@
                   source_id_, kInitialCreditCardFieldsStatus, 0)}));
 }
 
+TEST_F(CollectUserDataActionTest, ReloadsDataOnRequest) {
+  ON_CALL(mock_action_delegate_, CollectUserData(_))
+      .WillByDefault(
+          Invoke([=](CollectUserDataOptions* collect_user_data_options) {
+            std::move(collect_user_data_options->reload_data_callback)
+                .Run(&user_data_);
+          }));
+
+  ActionProto action_proto;
+  auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
+  collect_user_data_proto->set_privacy_notice_text("privacy");
+  collect_user_data_proto->set_request_terms_and_conditions(false);
+
+  EXPECT_CALL(callback_,
+              Run(Pointee(AllOf(
+                  Property(&ProcessedActionProto::status, RESEND_USER_DATA)))));
+  CollectUserDataAction action(&mock_action_delegate_, action_proto);
+  action.ProcessAction(callback_.Get());
+
+  ASSERT_TRUE(user_data_.previous_user_data_metrics_);
+  EXPECT_TRUE(user_data_.previous_user_data_metrics_->personal_data_changed);
+}
+
+TEST_F(CollectUserDataActionTest, ReloadingActionDoesNotLog) {
+  base::HistogramTester histogram_tester;
+
+  ON_CALL(mock_action_delegate_, CollectUserData(_))
+      .WillByDefault(
+          Invoke([=](CollectUserDataOptions* collect_user_data_options) {
+            std::move(collect_user_data_options->reload_data_callback)
+                .Run(&user_data_);
+          }));
+
+  ActionProto action_proto;
+  auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
+  collect_user_data_proto->set_privacy_notice_text("privacy");
+  collect_user_data_proto->set_request_terms_and_conditions(false);
+
+  std::unique_ptr<CollectUserDataAction> action =
+      std::make_unique<CollectUserDataAction>(&mock_action_delegate_,
+                                              action_proto);
+  action->ProcessAction(callback_.Get());
+  // We can't wait for the callback_ to be called and destroy the action there,
+  // it will trigger a "heap use after free" error.
+  action.reset();
+  histogram_tester.ExpectTotalCount(
+      "Android.AutofillAssistant.PaymentRequest.Prefilled", 0u);
+  histogram_tester.ExpectTotalCount(
+      "Android.AutofillAssistant.PaymentRequest.AutofillChanged", 0u);
+}
+
+TEST_F(CollectUserDataActionTest, ActionLogsPreviousState) {
+  base::HistogramTester histogram_tester;
+
+  UserDataMetrics metrics;
+  metrics.source_id = source_id_;
+  metrics.initially_prefilled = true;
+  metrics.personal_data_changed = true;
+  user_data_.previous_user_data_metrics_ = metrics;
+
+  ON_CALL(mock_action_delegate_, CollectUserData(_))
+      .WillByDefault(
+          Invoke([=](CollectUserDataOptions* collect_user_data_options) {
+            // We don't have data. "Initially prefilled" would be set to
+            // false. Don't finish the action, let the destructor log.
+          }));
+
+  ActionProto action_proto;
+  auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
+  collect_user_data_proto->set_privacy_notice_text("privacy");
+  collect_user_data_proto->set_request_terms_and_conditions(false);
+  collect_user_data_proto->set_shipping_address_name("shipping");
+
+  std::unique_ptr<CollectUserDataAction> action =
+      std::make_unique<CollectUserDataAction>(&mock_action_delegate_,
+                                              action_proto);
+  action->ProcessAction(callback_.Get());
+  // We can't wait for the callback_ to be called and destroy the action there,
+  // it will trigger a "heap use after free" error.
+  action.reset();
+  histogram_tester.ExpectUniqueSample(
+      "Android.AutofillAssistant.PaymentRequest.Prefilled",
+      Metrics::PaymentRequestPrefilled::PREFILLED_FAILURE, 1u);
+  histogram_tester.ExpectUniqueSample(
+      "Android.AutofillAssistant.PaymentRequest.AutofillChanged",
+      Metrics::PaymentRequestPrefilled::PREFILLED_FAILURE, 1u);
+  EXPECT_FALSE(user_data_.previous_user_data_metrics_);
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/client_status.cc b/components/autofill_assistant/browser/client_status.cc
index 4a05cec0..98485857 100644
--- a/components/autofill_assistant/browser/client_status.cc
+++ b/components/autofill_assistant/browser/client_status.cc
@@ -158,6 +158,9 @@
     case ProcessedActionStatusProto::EMPTY_VALUE_EXPRESSION_RESULT:
       out << "EMPTY_VALUE_EXPRESSION_RESULT";
       break;
+    case ProcessedActionStatusProto::RESEND_USER_DATA:
+      out << "RESEND_USER_DATA";
+      break;
 
       // Intentionally no default case to make compilation fail if a new value
       // was added to the enum but not to this list.
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index adc9229..8bd419b 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -1765,6 +1765,20 @@
   UpdateCollectUserDataActions();
 }
 
+void Controller::ReloadUserData(UserDataEventField event_field,
+                                UserDataEventType event_type) {
+  if (collect_user_data_options_ == nullptr) {
+    return;
+  }
+
+  collect_user_data_options_->selected_user_data_changed_callback.Run(
+      event_field, event_type);
+
+  auto callback = std::move(collect_user_data_options_->reload_data_callback);
+  SetCollectUserDataOptions(nullptr);
+  std::move(callback).Run(&user_data_);
+}
+
 void Controller::SetTermsAndConditions(
     TermsAndConditionsState terms_and_conditions) {
   user_data_.terms_and_conditions_ = terms_and_conditions;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 744859ed..90441dd 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -235,6 +235,8 @@
   void SetCreditCard(std::unique_ptr<autofill::CreditCard> card,
                      std::unique_ptr<autofill::AutofillProfile> billing_profile,
                      UserDataEventType event_type) override;
+  void ReloadUserData(UserDataEventField event_field,
+                      UserDataEventType event_type) override;
   void SetTermsAndConditions(
       TermsAndConditionsState terms_and_conditions) override;
   void SetLoginOption(const std::string& identifier) override;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 3a7d5609..40a891a3 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -2179,6 +2179,24 @@
       }));
 }
 
+TEST_F(ControllerTest, UserDataFormReload) {
+  auto options = std::make_unique<MockCollectUserDataOptions>();
+  base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
+  options->reload_data_callback = reload_callback.Get();
+  base::MockCallback<
+      base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
+      change_callback;
+  options->selected_user_data_changed_callback = change_callback.Get();
+
+  controller_->SetCollectUserDataOptions(options.get());
+
+  EXPECT_CALL(change_callback, Run(UserDataEventField::CONTACT_EVENT,
+                                   UserDataEventType::ENTRY_CREATED));
+  EXPECT_CALL(reload_callback, Run);
+  controller_->ReloadUserData(UserDataEventField::CONTACT_EVENT,
+                              UserDataEventType::ENTRY_CREATED);
+}
+
 TEST_F(ControllerTest, SetTermsAndConditions) {
   auto options = std::make_unique<MockCollectUserDataOptions>();
 
diff --git a/components/autofill_assistant/browser/metrics.cc b/components/autofill_assistant/browser/metrics.cc
index b3ece84..210a649 100644
--- a/components/autofill_assistant/browser/metrics.cc
+++ b/components/autofill_assistant/browser/metrics.cc
@@ -7,6 +7,7 @@
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/intent_strings.h"
 #include "components/ukm/content/source_url_recorder.h"
@@ -28,7 +29,6 @@
 
 namespace {
 const char kDropOut[] = "Android.AutofillAssistant.DropOutReason";
-const char kOnboarding[] = "Android.AutofillAssistant.OnBoarding";
 const char kTtsButtonAction[] =
     "Android.AutofillAssistant.TextToSpeech.ButtonAction";
 const char kTtsEngineEvent[] =
@@ -66,6 +66,113 @@
   }
   return histogramsSuffixes[intent];
 }
+
+// Extracts the enum value corresponding to the intent specified in
+// |script_parameters|.
+Metrics::AutofillAssistantIntent ExtractIntentFromScriptParameters(
+    const ScriptParameters& script_parameters) {
+  auto intent = script_parameters.GetIntent();
+  if (!intent) {
+    return Metrics::AutofillAssistantIntent::UNDEFINED_INTENT;
+  }
+  // The list of intents that is known at compile-time. Intents not in this list
+  // will be recorded as UNDEFINED_INTENT.
+  static const base::NoDestructor<
+      base::flat_map<std::string, Metrics::AutofillAssistantIntent>>
+      intents(
+          {{"BUY_MOVIE_TICKET",
+            Metrics::AutofillAssistantIntent::BUY_MOVIE_TICKET},
+           {"RENT_CAR", Metrics::AutofillAssistantIntent::RENT_CAR},
+           {"SHOPPING", Metrics::AutofillAssistantIntent::SHOPPING},
+           {"TELEPORT", Metrics::AutofillAssistantIntent::TELEPORT},
+           {"SHOPPING_ASSISTED_CHECKOUT",
+            Metrics::AutofillAssistantIntent::SHOPPING_ASSISTED_CHECKOUT},
+           {"FLIGHTS_CHECKIN",
+            Metrics::AutofillAssistantIntent::FLIGHTS_CHECKIN},
+           {"FOOD_ORDERING", Metrics::AutofillAssistantIntent::FOOD_ORDERING},
+           {"PASSWORD_CHANGE",
+            Metrics::AutofillAssistantIntent::PASSWORD_CHANGE},
+           {"FOOD_ORDERING_PICKUP",
+            Metrics::AutofillAssistantIntent::FOOD_ORDERING_PICKUP},
+           {"FOOD_ORDERING_DELIVERY",
+            Metrics::AutofillAssistantIntent::FOOD_ORDERING_DELIVERY},
+           {"UNLAUNCHED_VERTICAL_1",
+            Metrics::AutofillAssistantIntent::UNLAUNCHED_VERTICAL_1},
+           {"FIND_COUPONS", Metrics::AutofillAssistantIntent::FIND_COUPONS}});
+
+  auto enum_value_iter = intents->find(*intent);
+  if (enum_value_iter == intents->end()) {
+    return Metrics::AutofillAssistantIntent::UNDEFINED_INTENT;
+  }
+  return enum_value_iter->second;
+}  // namespace
+
+// Extracts the enum value corresponding to the caller specified in
+// |script_parameters|.
+Metrics::AutofillAssistantCaller ExtractCallerFromScriptParameters(
+    const ScriptParameters& script_parameters) {
+  auto caller = script_parameters.GetCaller();
+  if (!caller ||
+      *caller >
+          static_cast<int64_t>(Metrics::AutofillAssistantCaller::kMaxValue) ||
+      *caller < 0) {
+    return Metrics::AutofillAssistantCaller::UNKNOWN_CALLER;
+  }
+
+  return static_cast<Metrics::AutofillAssistantCaller>(*caller);
+}
+
+// Extracts the enum value corresponding to the source specified in
+// |script_parameters|.
+Metrics::AutofillAssistantSource ExtractSourceFromScriptParameters(
+    const ScriptParameters& script_parameters) {
+  auto source = script_parameters.GetSource();
+  if (!source ||
+      *source >
+          static_cast<int64_t>(Metrics::AutofillAssistantSource::kMaxValue) ||
+      *source < 0) {
+    return Metrics::AutofillAssistantSource::UNKNOWN_SOURCE;
+  }
+
+  return static_cast<Metrics::AutofillAssistantSource>(*source);
+}
+
+// Extracts the list of experiments specified in |script_parameters|, if any.
+// Returns a bit-wise OR of the running experiments.
+int64_t ExtractExperimentsFromScriptParameters(
+    const ScriptParameters& script_parameters) {
+  std::vector<std::string> experiments = script_parameters.GetExperiments();
+  if (experiments.empty()) {
+    return static_cast<int64_t>(
+        Metrics::AutofillAssistantExperiment::NO_EXPERIMENT);
+  }
+
+  // This will be bit-wise OR of running experiments. Currently, there are no
+  // known experiments.
+  return static_cast<int64_t>(
+      Metrics::AutofillAssistantExperiment::UNKNOWN_EXPERIMENT);
+}
+
+Metrics::AutofillAssistantStarted ToAutofillAssistantStarted(
+    StartupUtil::StartupMode event) {
+  switch (event) {
+    case StartupUtil::StartupMode::FEATURE_DISABLED:
+      return Metrics::AutofillAssistantStarted::FAILED_FEATURE_DISABLED;
+    case StartupUtil::StartupMode::MANDATORY_PARAMETERS_MISSING:
+      return Metrics::AutofillAssistantStarted::
+          FAILED_MANDATORY_PARAMETER_MISSING;
+    case StartupUtil::StartupMode::SETTING_DISABLED:
+      return Metrics::AutofillAssistantStarted::FAILED_SETTING_DISABLED;
+    case StartupUtil::StartupMode::NO_INITIAL_URL:
+      return Metrics::AutofillAssistantStarted::FAILED_NO_INITIAL_URL;
+    case StartupUtil::StartupMode::START_REGULAR:
+      return Metrics::AutofillAssistantStarted::OK_IMMEDIATE_START;
+    case StartupUtil::StartupMode::START_BASE64_TRIGGER_SCRIPT:
+    case StartupUtil::StartupMode::START_RPC_TRIGGER_SCRIPT:
+      return Metrics::AutofillAssistantStarted::OK_DELAYED_START;
+  }
+}
+
 }  // namespace
 
 // static
@@ -217,6 +324,15 @@
 }
 
 // static
+void Metrics::RecordRegularScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+                                            ukm::SourceId source_id,
+                                            Metrics::Onboarding event) {
+  ukm::builders::AutofillAssistant_RegularScriptOnboarding(source_id)
+      .SetOnboarding(static_cast<int64_t>(event))
+      .Record(ukm_recorder);
+}
+
+// static
 void Metrics::RecordInChromeTriggerAction(ukm::UkmRecorder* ukm_recorder,
                                           ukm::SourceId source_id,
                                           InChromeTriggerAction event) {
@@ -226,12 +342,6 @@
 }
 
 // static
-void Metrics::RecordOnboardingResult(OnBoarding event) {
-  DCHECK_LE(event, OnBoarding::kMaxValue);
-  base::UmaHistogramEnumeration(kOnboarding, event);
-}
-
-// static
 void Metrics::RecordTtsButtonAction(TtsButtonAction action) {
   DCHECK_LE(action, TtsButtonAction::kMaxValue);
   base::UmaHistogramEnumeration(kTtsButtonAction, action);
@@ -267,6 +377,24 @@
                                 dependencies_invalidated);
 }
 
+// static
+void Metrics::RecordStartRequest(ukm::UkmRecorder* ukm_recorder,
+                                 ukm::SourceId source_id,
+                                 const ScriptParameters& script_parameters,
+                                 StartupUtil::StartupMode event) {
+  ukm::builders::AutofillAssistant_StartRequest(source_id)
+      .SetCaller(static_cast<int64_t>(
+          ExtractCallerFromScriptParameters(script_parameters)))
+      .SetSource(static_cast<int64_t>(
+          ExtractSourceFromScriptParameters(script_parameters)))
+      .SetIntent(static_cast<int64_t>(
+          ExtractIntentFromScriptParameters(script_parameters)))
+      .SetExperiments(ExtractExperimentsFromScriptParameters(script_parameters))
+      .SetStarted(static_cast<int64_t>(ToAutofillAssistantStarted(event)))
+      .Record(ukm_recorder);
+}
+
+// static
 void Metrics::RecordContactMetrics(ukm::UkmRecorder* ukm_recorder,
                                    ukm::SourceId source_id,
                                    int complete_count,
@@ -299,6 +427,7 @@
       .Record(ukm_recorder);
 }
 
+// static
 void Metrics::RecordShippingMetrics(ukm::UkmRecorder* ukm_recorder,
                                     ukm::SourceId source_id,
                                     int complete_count,
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h
index 12431a88..b473141 100644
--- a/components/autofill_assistant/browser/metrics.h
+++ b/components/autofill_assistant/browser/metrics.h
@@ -7,6 +7,7 @@
 
 #include <ostream>
 #include "base/time/time.h"
+#include "components/autofill_assistant/browser/script_parameters.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/startup_util.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
@@ -60,23 +61,24 @@
     kMaxValue = MULTIPLE_AUTOSTARTABLE_SCRIPTS
   };
 
-  // The different ways that autofill assistant can stop. Note that this only
-  // covers regular onboarding. Trigger script onboarding is covered by
-  // TriggerScriptOnboarding.
+  // The different ways to complete the onboarding / user consent screen.
   //
-  // GENERATED_JAVA_ENUM_PACKAGE: (
-  // org.chromium.chrome.browser.autofill_assistant.metrics)
-  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OnBoarding
-  //
-  // This enum is used in histograms, do not remove/renumber entries. Only add
+  // This enum is used in UKM metrics, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantOnBoarding enum listing in
+  // AutofillAssistantOnboarding enum listing in
   // tools/metrics/histograms/enums.xml.
-  enum class OnBoarding {
+  enum class Onboarding {
+    // The onboarding was shown to the user.
     OB_SHOWN = 0,
+    // The onboarding was not shown to the user, because the user has already
+    // accepted the onboarding in a previous flow.
     OB_NOT_SHOWN = 1,
+    // The user explicitly accepted the onboarding by tapping the relevant chip.
     OB_ACCEPTED = 2,
+    // The user explicitly rejected the onboarding by tapping the relevant chip.
     OB_CANCELLED = 3,
+    // The user implicitly rejected the onboarding. Some of the possible reasons
+    // include navigating away, tapping the back button, closing the tab, etc.
     OB_NO_ANSWER = 4,
 
     kMaxValue = OB_NO_ANSWER
@@ -406,7 +408,7 @@
   //
   // This enum is used in histograms, do not remove/renumber entries. Only add
   // at the end and update kMaxValue. Also remember to update the
-  // AutofillAssistantWindowAttachmentChange enum listing in
+  // AutofillAssistantDependenciesInvalidated enum listing in
   // tools/metrics/histograms/enums.xml.
   enum class DependenciesInvalidated {
     // The dependencies were invalidated while the starter existed but before
@@ -421,6 +423,104 @@
     kMaxValue = DURING_FLOW
   };
 
+  // Used for logging the CALLER script parameter.
+  //
+  // This enum is used in histograms, do not remove/renumber entries. Only add
+  // at the end and update kMaxValue. Also remember to update the
+  // AutofillAssistantCaller enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AutofillAssistantCaller {
+    UNKNOWN_CALLER = 0,
+    ASSISTANT = 1,
+    SEARCH = 2,
+    STARTER_APP = 3,
+    SEARCH_ADS = 4,
+    SHOPPING_PROPERTY = 5,
+    EMULATOR = 6,
+    IN_CHROME = 7,
+    DIRECT_ACTION = 8,
+
+    kMaxValue = DIRECT_ACTION
+  };
+
+  // Used for logging the SOURCE script parameter.
+  //
+  // This enum is used in histograms, do not remove/renumber entries. Only add
+  // at the end and update kMaxValue. Also remember to update the
+  // AutofillAssistantSource enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AutofillAssistantSource {
+    UNKNOWN_SOURCE = 0,
+    ORGANIC = 1,
+    FRESH_DEEPLINK = 2,
+    STARTER_APP = 3,
+    EMULATOR_VALIDATION = 4,
+    S_API = 5,
+    C_CARD = 6,
+    MD_CARD = 7,
+    C_NOTIFICATION = 8,
+    G_CAROUSEL = 9,
+
+    kMaxValue = G_CAROUSEL
+  };
+
+  // Used for logging the intent of an autofill-assistant flow.
+  //
+  // This enum is used in UKM metrics, do not remove/renumber entries. Only add
+  // at the end and update kMaxValue. Also remember to update the
+  // AutofillAssistantIntent enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AutofillAssistantIntent {
+    UNDEFINED_INTENT = 0,
+    BUY_MOVIE_TICKET = 3,
+    RENT_CAR = 9,
+    SHOPPING = 10,
+    TELEPORT = 11,
+    SHOPPING_ASSISTED_CHECKOUT = 14,
+    FLIGHTS_CHECKIN = 15,
+    FOOD_ORDERING = 17,
+    PASSWORD_CHANGE = 18,
+    FOOD_ORDERING_PICKUP = 19,
+    FOOD_ORDERING_DELIVERY = 20,
+    UNLAUNCHED_VERTICAL_1 = 22,
+    FIND_COUPONS = 25,
+
+    kMaxValue = FIND_COUPONS
+  };
+
+  // Used for logging active autofill-assistant experiments. This is intended
+  // to be a bitmask to support cases where more than one experiment is running.
+  //
+  // This enum is used in UKM metrics, do not remove/renumber entries. Only add
+  // at the end and update kMaxValue. Also remember to update the
+  // AutofillAssistantExperiment enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AutofillAssistantExperiment {
+    // No experiment is running.
+    NO_EXPERIMENT = 0,
+    // An unknown experiment is running.
+    UNKNOWN_EXPERIMENT = 1,
+
+    kMaxValue = UNKNOWN_EXPERIMENT
+  };
+
+  // Used to record successful and failed autofill-assistant startup requests.
+  //
+  // This enum is used in UKM metrics, do not remove/renumber entries. Only add
+  // at the end and update kMaxValue. Also remember to update the
+  // AutofillAssistantStarted enum listing in
+  // tools/metrics/histograms/enums.xml.
+  enum class AutofillAssistantStarted {
+    FAILED_FEATURE_DISABLED = 0,
+    FAILED_MANDATORY_PARAMETER_MISSING = 1,
+    FAILED_SETTING_DISABLED = 2,
+    FAILED_NO_INITIAL_URL = 3,
+    OK_DELAYED_START = 4,
+    OK_IMMEDIATE_START = 5,
+
+    kMaxValue = OK_IMMEDIATE_START
+  };
+
   // Used to track what action the user performed on the contact/shipping/card
   // data. Only reported at the end of a CollectUserData action. Reported up to
   // three times for each of contact/shipping/credit card and only if the given
@@ -537,10 +637,12 @@
       ukm::SourceId source_id,
       TriggerScriptProto::TriggerUIType trigger_ui_type,
       TriggerScriptOnboarding event);
+  static void RecordRegularScriptOnboarding(ukm::UkmRecorder* ukm_recorder,
+                                            ukm::SourceId source_id,
+                                            Metrics::Onboarding event);
   static void RecordInChromeTriggerAction(ukm::UkmRecorder* ukm_recorder,
                                           ukm::SourceId source_id,
                                           InChromeTriggerAction event);
-  static void RecordOnboardingResult(OnBoarding event);
   static void RecordTtsButtonAction(TtsButtonAction action);
   static void RecordTtsEngineEvent(TtsEngineEvent event);
   static void RecordFeatureModuleInstallation(FeatureModuleInstallation event);
@@ -550,6 +652,10 @@
       base::TimeDelta evaluation_time);
   static void RecordDependenciesInvalidated(
       DependenciesInvalidated dependencies_invalidated);
+  static void RecordStartRequest(ukm::UkmRecorder* ukm_recorder,
+                                 ukm::SourceId source_id,
+                                 const ScriptParameters& script_parameters,
+                                 StartupUtil::StartupMode event);
   static void RecordContactMetrics(ukm::UkmRecorder* ukm_recorder,
                                    ukm::SourceId source_id,
                                    int complete_count,
@@ -680,7 +786,7 @@
   }
 
   // Intended for debugging: writes string representation of |metric| to |out|.
-  friend std::ostream& operator<<(std::ostream& out, const OnBoarding& metric) {
+  friend std::ostream& operator<<(std::ostream& out, const Onboarding& metric) {
 #ifdef NDEBUG
     // Non-debugging builds write the enum number.
     out << static_cast<int>(metric);
@@ -688,19 +794,19 @@
 #else
     // Debugging builds write a string representation of |metric|.
     switch (metric) {
-      case OnBoarding::OB_SHOWN:
+      case Onboarding::OB_SHOWN:
         out << "OB_SHOWN";
         break;
-      case OnBoarding::OB_NOT_SHOWN:
+      case Onboarding::OB_NOT_SHOWN:
         out << "OB_NOT_SHOWN";
         break;
-      case OnBoarding::OB_ACCEPTED:
+      case Onboarding::OB_ACCEPTED:
         out << "OB_ACCEPTED";
         break;
-      case OnBoarding::OB_CANCELLED:
+      case Onboarding::OB_CANCELLED:
         out << "OB_CANCELLED";
         break;
-      case OnBoarding::OB_NO_ANSWER:
+      case Onboarding::OB_NO_ANSWER:
         out << "OB_NO_ANSWER";
         break;
         // Do not add default case to force compilation error for new values.
diff --git a/components/autofill_assistant/browser/model.proto b/components/autofill_assistant/browser/model.proto
index 799338d..255de7f2f 100644
--- a/components/autofill_assistant/browser/model.proto
+++ b/components/autofill_assistant/browser/model.proto
@@ -231,6 +231,10 @@
   // The requested value expression resulted in an empty string.
   EMPTY_VALUE_EXPRESSION_RESULT = 35;
 
+  // The collect user data action has detected a change and requires the user
+  // data to be resent.
+  RESEND_USER_DATA = 36;
+
   reserved 15, 23, 25, 32;
 }
 
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc
index 0cd051b..d1e33cd 100644
--- a/components/autofill_assistant/browser/starter.cc
+++ b/components/autofill_assistant/browser/starter.cc
@@ -302,7 +302,8 @@
            std::vector<std::string>(intents.begin(), intents.end()), ",")},
       {"START_IMMEDIATELY", "false"},
       {"REQUEST_TRIGGER_SCRIPT", "true"},
-      {"ORIGINAL_DEEPLINK", url.spec()}};
+      {"ORIGINAL_DEEPLINK", url.spec()},
+      {"CALLER", "7"}};
   // Add/overwrite with debug parameters if specified.
   for (const auto& debug_param :
        implicit_triggering_debug_parameters_.additional_script_parameters()) {
@@ -430,6 +431,9 @@
       {platform_delegate_->GetMakeSearchesAndBrowsingBetterEnabled(),
        platform_delegate_->GetProactiveHelpSettingEnabled(),
        platform_delegate_->GetFeatureModuleInstalled()});
+  Metrics::RecordStartRequest(ukm_recorder_, current_ukm_source_id_,
+                              pending_trigger_context_->GetScriptParameters(),
+                              startup_mode);
 
   // Trigger scripts may need to wait for navigation to the deeplink domain to
   // ensure that UKMs are recorded for the right source-id.
@@ -485,8 +489,11 @@
   }
   platform_delegate_->HideOnboarding();
   if (waiting_for_onboarding_) {
-    Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_NO_ANSWER);
-    Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_SHOWN);
+    Metrics::RecordRegularScriptOnboarding(ukm_recorder_,
+                                           current_ukm_source_id_,
+                                           Metrics::Onboarding::OB_NO_ANSWER);
+    Metrics::RecordRegularScriptOnboarding(
+        ukm_recorder_, current_ukm_source_id_, Metrics::Onboarding::OB_SHOWN);
     waiting_for_onboarding_ = false;
   }
   OnStartDone(/* start_regular_script = */ false);
@@ -689,25 +696,47 @@
           std::string());
   switch (result) {
     case OnboardingResult::DISMISSED:
-      Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_NO_ANSWER);
+      Metrics::RecordRegularScriptOnboarding(ukm_recorder_,
+                                             current_ukm_source_id_,
+                                             Metrics::Onboarding::OB_NO_ANSWER);
       Metrics::RecordDropOut(
           Metrics::DropOutReason::ONBOARDING_BACK_BUTTON_CLICKED, intent);
       break;
     case OnboardingResult::REJECTED:
-      Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_CANCELLED);
+      if (shown) {
+        Metrics::RecordRegularScriptOnboarding(
+            ukm_recorder_, current_ukm_source_id_,
+            Metrics::Onboarding::OB_CANCELLED);
+      } else {
+        // Should not happen, but it's technically possible. Only OB_NOT_SHOWN
+        // will be recorded, since OB_REJECTED is intended to convey explicit
+        // user rejection only.
+      }
       Metrics::RecordDropOut(Metrics::DropOutReason::DECLINED, intent);
       break;
     case OnboardingResult::NAVIGATION:
-      Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_NO_ANSWER);
+      Metrics::RecordRegularScriptOnboarding(ukm_recorder_,
+                                             current_ukm_source_id_,
+                                             Metrics::Onboarding::OB_NO_ANSWER);
       Metrics::RecordDropOut(Metrics::DropOutReason::ONBOARDING_NAVIGATION,
                              intent);
       break;
     case OnboardingResult::ACCEPTED:
-      Metrics::RecordOnboardingResult(Metrics::OnBoarding::OB_ACCEPTED);
+      if (shown) {
+        Metrics::RecordRegularScriptOnboarding(
+            ukm_recorder_, current_ukm_source_id_,
+            Metrics::Onboarding::OB_ACCEPTED);
+      } else {
+        // This can happen if the onboarding was already accepted and was thus
+        // not shown. We will record OB_NOT_SHOWN but not OB_ACCEPTED, as the
+        // latter is intended to convey explicit user consent only.
+      }
       break;
   }
-  Metrics::RecordOnboardingResult(shown ? Metrics::OnBoarding::OB_SHOWN
-                                        : Metrics::OnBoarding::OB_NOT_SHOWN);
+  Metrics::RecordRegularScriptOnboarding(
+      ukm_recorder_, current_ukm_source_id_,
+      shown ? Metrics::Onboarding::OB_SHOWN
+            : Metrics::Onboarding::OB_NOT_SHOWN);
 
   if (result != OnboardingResult::ACCEPTED) {
     runtime_manager_->SetUIState(UIState::kNotShown);
diff --git a/components/autofill_assistant/browser/starter_unittest.cc b/components/autofill_assistant/browser/starter_unittest.cc
index d8a67dd..95051d5 100644
--- a/components/autofill_assistant/browser/starter_unittest.cc
+++ b/components/autofill_assistant/browser/starter_unittest.cc
@@ -267,8 +267,15 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::FAILED_NO_INITIAL_URL,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, TriggerScriptFailsWithoutInitialUrl) {
@@ -290,8 +297,15 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::FAILED_NO_INITIAL_URL,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, FailWithoutMandatoryScriptParameter) {
@@ -314,15 +328,27 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::
+                         FAILED_MANDATORY_PARAMETER_MISSING,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, FailWhenFeatureDisabled) {
   base::flat_map<std::string, std::string> params = {
       {"ENABLED", "true"},
       {"START_IMMEDIATELY", "false"},
-      {"TRIGGER_SCRIPTS_BASE64", "abc"}};
+      {"TRIGGER_SCRIPTS_BASE64", "abc"},
+      {"INTENT", "SHOPPING"},
+      {"EXPERIMENT_IDS", "fake_experiment"},
+      {"CALLER", "7"},
+      {"SOURCE", "1"}};
   TriggerContext::Options options;
   options.initial_url = kExampleDeeplink;
   auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
@@ -341,8 +367,16 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(
+      GetUkmStartRequest(ukm_recorder_),
+      ElementsAreArray(ToHumanReadableMetrics(
+          {{navigation_ids_[0],
+            {Metrics::AutofillAssistantStarted::FAILED_FEATURE_DISABLED,
+             Metrics::AutofillAssistantIntent::SHOPPING,
+             Metrics::AutofillAssistantCaller::IN_CHROME,
+             Metrics::AutofillAssistantSource::ORGANIC,
+             Metrics::AutofillAssistantExperiment::UNKNOWN_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, RegularStartupForReturningUsersSucceeds) {
@@ -372,10 +406,18 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_ACCEPTED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_NOT_SHOWN, 1u);
+  EXPECT_THAT(
+      GetUkmRegularScriptOnboarding(ukm_recorder_),
+      ElementsAreArray(ToHumanReadableMetrics(
+          {{navigation_ids_[0], {Metrics::Onboarding::OB_NOT_SHOWN}}})));
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::OK_IMMEDIATE_START,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, RegularStartupForFirstTimeUsersSucceeds) {
@@ -406,10 +448,10 @@
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_FOREGROUND_INSTALLATION_SUCCEEDED,
       1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_ACCEPTED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_SHOWN, 1u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0], {Metrics::Onboarding::OB_ACCEPTED}},
+                   {navigation_ids_[0], {Metrics::Onboarding::OB_SHOWN}}})));
 }
 
 TEST_F(StarterTest, ForceOnboardingFlagForReturningUsersSucceeds) {
@@ -500,8 +542,7 @@
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_FOREGROUND_INSTALLATION_FAILED,
       1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, RegularStartupFailsIfOnboardingRejected) {
@@ -527,10 +568,10 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_CANCELLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_SHOWN, 1u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0], {Metrics::Onboarding::OB_CANCELLED}},
+                   {navigation_ids_[0], {Metrics::Onboarding::OB_SHOWN}}})));
 }
 
 TEST_F(StarterTest, RpcTriggerScriptFailsIfMsbbIsDisabled) {
@@ -559,8 +600,7 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, RpcTriggerScriptFailsIfProactiveHelpIsDisabled) {
@@ -589,8 +629,15 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::FAILED_SETTING_DISABLED,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, RpcTriggerScriptSucceeds) {
@@ -663,8 +710,15 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmStartRequest(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0],
+                    {Metrics::AutofillAssistantStarted::OK_DELAYED_START,
+                     Metrics::AutofillAssistantIntent::UNDEFINED_INTENT,
+                     Metrics::AutofillAssistantCaller::UNKNOWN_CALLER,
+                     Metrics::AutofillAssistantSource::UNKNOWN_SOURCE,
+                     Metrics::AutofillAssistantExperiment::NO_EXPERIMENT}}})));
 }
 
 TEST_F(StarterTest, Base64TriggerScriptFailsForInvalidBase64) {
@@ -697,8 +751,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, Base64TriggerScriptFailsIfProactiveHelpIsDisabled) {
@@ -728,8 +781,7 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, Base64TriggerScriptSucceeds) {
@@ -785,8 +837,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, CancelPendingTriggerScriptWhenTransitioningFromCctToTab) {
@@ -875,10 +926,10 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_NO_ANSWER, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_SHOWN, 1u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[0], {Metrics::Onboarding::OB_NO_ANSWER}},
+                   {navigation_ids_[0], {Metrics::Onboarding::OB_SHOWN}}})));
 }
 
 TEST_F(StarterTest, TriggerScriptStartupFailsIfNavigationDuringOnboarding) {
@@ -928,8 +979,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, RegularStartupAllowsCertainNavigationsDuringOnboarding) {
@@ -951,8 +1001,7 @@
   // subdomain of the ORIGINAL_DEEPLINK, nor by redirects along the way.
   SimulateRedirectToUrl(
       {GURL("http://redirect.com/example"), GURL("https://login.example.com")});
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 
   // Navigating to a different domain will cancel the onboarding.
   SimulateNavigateToUrl(GURL("https://www.different.com"));
@@ -963,10 +1012,10 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_NO_ANSWER, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_SHOWN, 1u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_),
+              ElementsAreArray(ToHumanReadableMetrics(
+                  {{navigation_ids_[1], {Metrics::Onboarding::OB_NO_ANSWER}},
+                   {navigation_ids_[1], {Metrics::Onboarding::OB_SHOWN}}})));
 }
 
 TEST_F(StarterTest, TriggerScriptAllowsHttpToHttpsRedirect) {
@@ -1017,8 +1066,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, ImplicitStartupOnSupportedDomain) {
@@ -1090,8 +1138,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, DoNotStartImplicitlyIfSettingDisabled) {
@@ -1163,8 +1210,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, StartTriggerScriptBeforeRedirectRecordsUkmForTargetUrl) {
@@ -1205,8 +1251,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, RedirectFailsDuringPendingTriggerScriptStart) {
@@ -1254,8 +1299,7 @@
   EXPECT_THAT(GetUkmTriggerScriptOnboarding(ukm_recorder_), IsEmpty());
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, StartTriggerScriptDuringRedirectRecordsUkmForTargetUrl) {
@@ -1301,8 +1345,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, RegularStartupDoesNotWaitForNavigationToFinish) {
@@ -1338,10 +1381,10 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_ACCEPTED, 1u);
-  histogram_tester_.ExpectBucketCount("Android.AutofillAssistant.OnBoarding",
-                                      Metrics::OnBoarding::OB_NOT_SHOWN, 1u);
+  EXPECT_THAT(
+      GetUkmRegularScriptOnboarding(ukm_recorder_),
+      ElementsAreArray(ToHumanReadableMetrics(
+          {{navigation_ids_[1], {Metrics::Onboarding::OB_NOT_SHOWN}}})));
 }
 
 TEST_F(StarterTest, DoNotStartImplicitlyIfAlreadyRunning) {
@@ -1368,10 +1411,8 @@
 
   histogram_tester_.ExpectTotalCount(
       "Android.AutofillAssistant.FeatureModuleInstallation", 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 TEST_F(StarterTest, FailedTriggerScriptFetchesForImplicitStartupAreCached) {
@@ -2123,8 +2164,7 @@
   histogram_tester_.ExpectUniqueSample(
       "Android.AutofillAssistant.FeatureModuleInstallation",
       Metrics::FeatureModuleInstallation::DFM_ALREADY_INSTALLED, 0u);
-  histogram_tester_.ExpectTotalCount("Android.AutofillAssistant.OnBoarding",
-                                     0u);
+  EXPECT_THAT(GetUkmRegularScriptOnboarding(ukm_recorder_), IsEmpty());
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index cbb3b51f..cba3896c 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -114,6 +114,10 @@
       std::unique_ptr<autofill::AutofillProfile> billing_profile,
       UserDataEventType event_type) = 0;
 
+  // Reload the user data for the collect user data action.
+  virtual void ReloadUserData(UserDataEventField event_field,
+                              UserDataEventType event_type) = 0;
+
   // Sets the state of the third party terms & conditions, pertaining to the
   // current collect user data options.
   virtual void SetTermsAndConditions(
diff --git a/components/autofill_assistant/browser/ukm_test_util.cc b/components/autofill_assistant/browser/ukm_test_util.cc
index e894219b..797d032 100644
--- a/components/autofill_assistant/browser/ukm_test_util.cc
+++ b/components/autofill_assistant/browser/ukm_test_util.cc
@@ -44,6 +44,17 @@
                                  {kTriggerConditionTimingMs});
 }
 
+std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> GetUkmStartRequest(
+    ukm::TestAutoSetUkmRecorder& ukm_recorder) {
+  return ukm_recorder.GetEntries(
+      kStartRequestEntry, {kStarted, kCaller, kSource, kIntent, kExperiments});
+}
+
+std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
+GetUkmRegularScriptOnboarding(ukm::TestAutoSetUkmRecorder& ukm_recorder) {
+  return ukm_recorder.GetEntries(kRegularScriptOnboardingEntry, {kOnboarding});
+}
+
 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
 GetUkmCompleteContactProfilesCount(ukm::TestAutoSetUkmRecorder& ukm_recorder) {
   return ukm_recorder.GetEntries(kAutofillAssistantCollectContact,
diff --git a/components/autofill_assistant/browser/ukm_test_util.h b/components/autofill_assistant/browser/ukm_test_util.h
index 35ff80ba..ab5ff167 100644
--- a/components/autofill_assistant/browser/ukm_test_util.h
+++ b/components/autofill_assistant/browser/ukm_test_util.h
@@ -27,6 +27,9 @@
     "AutofillAssistant.LiteScriptOnboarding";
 const char kInChromeTriggeringEntry[] = "AutofillAssistant.InChromeTriggering";
 const char kAutofillAssistantTimingEntry[] = "AutofillAssistant.Timing";
+const char kStartRequestEntry[] = "AutofillAssistant.StartRequest";
+const char kRegularScriptOnboardingEntry[] =
+    "AutofillAssistant.RegularScriptOnboarding";
 const char kAutofillAssistantCollectContact[] =
     "AutofillAssistant.CollectContact";
 const char kAutofillAssistantCollectCreditCard[] =
@@ -44,6 +47,12 @@
 const char kTriggerScriptOnboarding[] = "LiteScriptOnboarding";
 const char kInChromeTriggerAction[] = "InChromeTriggerAction";
 const char kTriggerConditionTimingMs[] = "TriggerConditionEvaluationMs";
+const char kStarted[] = "Started";
+const char kCaller[] = "Caller";
+const char kSource[] = "Source";
+const char kIntent[] = "Intent";
+const char kExperiments[] = "Experiments";
+const char kOnboarding[] = "Onboarding";
 const char kCompleteContactProfilesCount[] = "CompleteContactProfilesCount";
 const char kIncompleteContactProfilesCount[] = "IncompleteContactProfilesCount";
 const char kInitialContactFieldsStatus[] = "InitialContactFieldsStatus";
@@ -75,7 +84,10 @@
 GetUkmInChromeTriggering(ukm::TestAutoSetUkmRecorder& ukm_recorder);
 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
 GetUkmTriggerConditionEvaluationTime(ukm::TestAutoSetUkmRecorder& ukm_recorder);
-
+std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry> GetUkmStartRequest(
+    ukm::TestAutoSetUkmRecorder& ukm_recorder);
+std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
+GetUkmRegularScriptOnboarding(ukm::TestAutoSetUkmRecorder& ukm_recorder);
 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
 GetUkmCompleteContactProfilesCount(ukm::TestAutoSetUkmRecorder& ukm_recorder);
 std::vector<ukm::TestUkmRecorder::HumanReadableUkmEntry>
@@ -119,13 +131,28 @@
                                      Metrics::TriggerScriptStarted,
                                      Metrics::TriggerScriptFinishedState,
                                      Metrics::TriggerScriptOnboarding,
-                                     Metrics::InChromeTriggerAction>;
+                                     Metrics::InChromeTriggerAction,
+                                     Metrics::AutofillAssistantStarted,
+                                     Metrics::AutofillAssistantCaller,
+                                     Metrics::AutofillAssistantSource,
+                                     Metrics::AutofillAssistantIntent,
+                                     Metrics::AutofillAssistantExperiment,
+                                     Metrics::Onboarding>;
 
 // The metric names corresponding to the variant alternatives of UkmEnumVariant.
 // NOTE: When adding entries, remember to also modify UkmEnumVariant!
-const std::vector<std::string> kUkmEnumMetricNames = {
-    kTriggerUiType,         kTriggerScriptShownToUser, kTriggerScriptStarted,
-    kTriggerScriptFinished, kTriggerScriptOnboarding,  kInChromeTriggerAction};
+const std::vector<std::string> kUkmEnumMetricNames = {kTriggerUiType,
+                                                      kTriggerScriptShownToUser,
+                                                      kTriggerScriptStarted,
+                                                      kTriggerScriptFinished,
+                                                      kTriggerScriptOnboarding,
+                                                      kInChromeTriggerAction,
+                                                      kStarted,
+                                                      kCaller,
+                                                      kSource,
+                                                      kIntent,
+                                                      kExperiments,
+                                                      kOnboarding};
 
 // Intended to be used to convert a UkmEnumVariant to int64_t using a visitor.
 // Usage:
diff --git a/components/autofill_assistant/browser/user_data.cc b/components/autofill_assistant/browser/user_data.cc
index 96a96f53..124b495 100644
--- a/components/autofill_assistant/browser/user_data.cc
+++ b/components/autofill_assistant/browser/user_data.cc
@@ -50,6 +50,11 @@
     : profile(std::move(_profile)) {}
 Address::~Address() = default;
 
+UserDataMetrics::UserDataMetrics() = default;
+UserDataMetrics::~UserDataMetrics() = default;
+UserDataMetrics::UserDataMetrics(const UserDataMetrics&) = default;
+UserDataMetrics& UserDataMetrics::operator=(const UserDataMetrics&) = default;
+
 UserData::UserData() = default;
 UserData::~UserData() = default;
 
diff --git a/components/autofill_assistant/browser/user_data.h b/components/autofill_assistant/browser/user_data.h
index 84eb13b..c1cd1c2 100644
--- a/components/autofill_assistant/browser/user_data.h
+++ b/components/autofill_assistant/browser/user_data.h
@@ -14,9 +14,11 @@
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill_assistant/browser/cud_condition.pb.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/user_action.h"
 #include "components/autofill_assistant/browser/website_login_manager.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace autofill {
@@ -133,6 +135,43 @@
   std::unique_ptr<autofill::AutofillProfile> profile;
 };
 
+// Struct for holding metrics data used by CollectUserDataAction.
+struct UserDataMetrics {
+  UserDataMetrics();
+  ~UserDataMetrics();
+  UserDataMetrics(const UserDataMetrics&);
+  UserDataMetrics& operator=(const UserDataMetrics&);
+
+  bool metrics_logged = false;
+  ukm::SourceId source_id;
+
+  bool initially_prefilled = false;
+  bool personal_data_changed = false;
+  bool action_successful = false;
+
+  // Selection states.
+  Metrics::UserDataSelectionState contact_selection_state =
+      Metrics::UserDataSelectionState::NO_CHANGE;
+  Metrics::UserDataSelectionState credit_card_selection_state =
+      Metrics::UserDataSelectionState::NO_CHANGE;
+  Metrics::UserDataSelectionState shipping_selection_state =
+      Metrics::UserDataSelectionState::NO_CHANGE;
+
+  // Initial counts of complete/incomplete entries.
+  int complete_contacts_initial_count = 0;
+  int incomplete_contacts_initial_count = 0;
+  int complete_credit_cards_initial_count = 0;
+  int incomplete_credit_cards_initial_count = 0;
+  int complete_shipping_addresses_initial_count = 0;
+  int incomplete_shipping_addresses_initial_count = 0;
+
+  // Bitmasks of fields present in the initially selected entries.
+  int selected_contact_field_bitmask = 0;
+  int selected_shipping_address_field_bitmask = 0;
+  int selected_credit_card_field_bitmask = 0;
+  int selected_billing_address_field_bitmask = 0;
+};
+
 // Struct for holding the user data.
 class UserData {
  public:
@@ -168,6 +207,8 @@
 
   absl::optional<WebsiteLoginManager::Login> selected_login_;
 
+  absl::optional<UserDataMetrics> previous_user_data_metrics_;
+
   // Return true if address has been selected, otherwise return false.
   // Note that selected_address() might return nullptr when
   // has_selected_address() is true because fill manually was chosen.
@@ -285,6 +326,7 @@
       additional_actions_callback;
   base::OnceCallback<void(int, UserData*, const UserModel*)>
       terms_link_callback;
+  base::OnceCallback<void(UserData*)> reload_data_callback;
   // Called whenever there is a change to the selected user data.
   base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>
       selected_user_data_changed_callback;
diff --git a/components/browser_watcher/OWNERS b/components/browser_watcher/OWNERS
index a2ea389c..4fa8ee3f 100644
--- a/components/browser_watcher/OWNERS
+++ b/components/browser_watcher/OWNERS
@@ -1,2 +1,2 @@
+chrisha@chromium.org
 siggi@chromium.org
-manzagop@chromium.org
diff --git a/components/browser_watcher/activity_report_extractor_unittest.cc b/components/browser_watcher/activity_report_extractor_unittest.cc
index c500fd2..b7998f62 100644
--- a/components/browser_watcher/activity_report_extractor_unittest.cc
+++ b/components/browser_watcher/activity_report_extractor_unittest.cc
@@ -86,7 +86,8 @@
     std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
     bool success = mmfile->Initialize(
         File(debug_file_path_, File::FLAG_CREATE | File::FLAG_READ |
-                                   File::FLAG_WRITE | File::FLAG_SHARE_DELETE),
+                                   File::FLAG_WRITE |
+                                   File::FLAG_WIN_SHARE_DELETE),
         {0, static_cast<int64_t>(kFileSize)},
         MemoryMappedFile::READ_WRITE_EXTEND);
     if (!success || !mmfile->IsValid())
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 3a93f28..23c84ca 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "4.42",
-  "log_list_timestamp": "2021-11-28T01:33:42Z",
+  "version": "4.43",
+  "log_list_timestamp": "2021-11-29T01:34:01Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/components_strings.grd b/components/components_strings.grd
index 61f4c20d..5f3971e0 100644
--- a/components/components_strings.grd
+++ b/components/components_strings.grd
@@ -297,6 +297,7 @@
       <part file="crash_strings.grdp" />
       <part file="dialog_strings.grdp" />
       <part file="dom_distiller_strings.grdp" />
+      <part file="enterprise_strings.grdp" />
       <part file="error_page_strings.grdp" />
       <part file="find_in_page_strings.grdp" />
       <part file="flags_strings.grdp" />
diff --git a/components/enterprise/content/BUILD.gn b/components/enterprise/content/BUILD.gn
new file mode 100644
index 0000000..58550bb
--- /dev/null
+++ b/components/enterprise/content/BUILD.gn
@@ -0,0 +1,50 @@
+# 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.
+
+import("//build/config/chromeos/ui_mode.gni")
+
+static_library("content") {
+  sources = [
+    "clipboard_restriction_service.cc",
+    "clipboard_restriction_service.h",
+    "copy_prevention_settings_policy_handler.cc",
+    "copy_prevention_settings_policy_handler.h",
+    "pref_names.cc",
+    "pref_names.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/content:content",
+    "//components/policy/core/browser",
+    "//components/policy/core/common",
+    "//components/policy/proto",
+    "//components/prefs",
+    "//components/strings:components_strings_grit",
+    "//components/url_matcher",
+    "//components/user_prefs:user_prefs",
+    "//content/public/browser",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "clipboard_restriction_service_unittest.cc",
+    "copy_prevention_settings_policy_handler_unittests.cc",
+  ]
+
+  deps = [
+    ":content",
+    "//base",
+    "//base/test:test_support",
+    "//components/policy/core/browser",
+    "//components/policy/core/common",
+    "//components/prefs",
+    "//components/prefs:test_support",
+    "//testing/gtest",
+    "//url:url",
+  ]
+}
diff --git a/components/enterprise/content/DEPS b/components/enterprise/content/DEPS
new file mode 100644
index 0000000..4bad09e
--- /dev/null
+++ b/components/enterprise/content/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+  "+components/keyed_service/content",
+  "+components/keyed_service/core",
+  "+components/policy",
+  "+components/prefs",
+  "+components/url_matcher",
+  "+components/user_prefs",
+  "+content/public/browser",
+]
diff --git a/components/enterprise/content/OWNERS b/components/enterprise/content/OWNERS
new file mode 100644
index 0000000..29ef1d3
--- /dev/null
+++ b/components/enterprise/content/OWNERS
@@ -0,0 +1,2 @@
+anthonyvd@chromium.org
+domfc@chromium.org
\ No newline at end of file
diff --git a/components/enterprise/content/clipboard_restriction_service.cc b/components/enterprise/content/clipboard_restriction_service.cc
new file mode 100644
index 0000000..e02e5241
--- /dev/null
+++ b/components/enterprise/content/clipboard_restriction_service.cc
@@ -0,0 +1,124 @@
+// 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 "components/enterprise/content/clipboard_restriction_service.h"
+
+#include "components/enterprise/content/pref_names.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/policy/core/common/policy_pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
+
+ClipboardRestrictionService::ClipboardRestrictionService(
+    PrefService* pref_service)
+    : pref_service_(pref_service),
+      next_id_(0),
+      enable_url_matcher_(nullptr),
+      disable_url_matcher_(nullptr) {
+  pref_change_registrar_.Init(pref_service_);
+  pref_change_registrar_.Add(
+      enterprise::content::kCopyPreventionSettings,
+      base::BindRepeating(&ClipboardRestrictionService::UpdateSettings,
+                          base::Unretained(this)));
+  UpdateSettings();
+}
+
+ClipboardRestrictionService::~ClipboardRestrictionService() = default;
+
+bool ClipboardRestrictionService::IsUrlAllowedToCopy(const GURL& url,
+                                                     int data_size) const {
+  if (!enable_url_matcher_ || !disable_url_matcher_)
+    return true;
+
+  if (data_size < min_data_size_)
+    return true;
+
+  // The copy is allowed in the following scenarios:
+  // 1. The URL doesn't match a pattern in the enable list
+  // or
+  // 2. The URL matches a pattern in the enable list but also matches a pattern
+  //    in the disable list
+  // Conversely, it is blocked iff it matches a pattern in the enable list and
+  // doesn't match a pattern in the disable list.
+  return enable_url_matcher_->MatchURL(url).empty() ||
+         disable_url_matcher_->MatchURL(url).size() > 0;
+}
+
+void ClipboardRestrictionService::UpdateSettings() {
+  // This is infrequent enough that this code can teardown the url matcher
+  // entirely and rebuild it. There's also no state that should be carried over
+  // from the previous values, so doing it this way makes that semantic clearer.
+  enable_url_matcher_ = nullptr;
+  disable_url_matcher_ = nullptr;
+
+  if (!pref_service_->IsManagedPreference(
+          enterprise::content::kCopyPreventionSettings)) {
+    return;
+  }
+
+  const base::DictionaryValue* settings = pref_service_->GetDictionary(
+      enterprise::content::kCopyPreventionSettings);
+  const base::Value* enable = settings->FindListKey(
+      enterprise::content::kCopyPreventionSettingsEnableFieldName);
+  const base::Value* disable = settings->FindListKey(
+      enterprise::content::kCopyPreventionSettingsDisableFieldName);
+
+  DCHECK(enable);
+  DCHECK(disable);
+
+  enable_url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
+  disable_url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
+
+  // Convert the |base::Value|s to |base::ListValue|s because that's what
+  // AddFilters expects.
+  const base::ListValue* enable_list = &base::Value::AsListValue(*enable);
+  const base::ListValue* disable_list = &base::Value::AsListValue(*disable);
+
+  // For the following 2 calls, the second param is a bool called |allow|. In
+  // this context, we're not concerned about a URL being "allowed" or not, but
+  // rather with this prevention feature being enabled on a given URL. Because
+  // of this, pass |true| for patterns in the |enable| list and false for
+  // patterns in the |disable| list. If the URL Matcher subsequently matches a
+  // URL as "allowed", it means the prevention feature is active for that URL
+  // and the copy will be blocked. While confusing, this is mostly to map to the
+  // same policy format as the content analysis connector, which also has
+  // "enable" and "disable" lists used in this way.
+  policy::url_util::AddFilters(enable_url_matcher_.get(), true, &next_id_,
+                               enable_list);
+  policy::url_util::AddFilters(disable_url_matcher_.get(), false, &next_id_,
+                               disable_list);
+
+  absl::optional<int> min_data_size = settings->FindIntKey(
+      enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName);
+  DCHECK(min_data_size);
+  min_data_size_ = *min_data_size;
+}
+
+// static
+ClipboardRestrictionServiceFactory*
+ClipboardRestrictionServiceFactory::GetInstance() {
+  return base::Singleton<ClipboardRestrictionServiceFactory>::get();
+}
+
+// static
+ClipboardRestrictionService*
+ClipboardRestrictionServiceFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<ClipboardRestrictionService*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+ClipboardRestrictionServiceFactory::ClipboardRestrictionServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "PolicyClipboardRestriction",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+ClipboardRestrictionServiceFactory::~ClipboardRestrictionServiceFactory() =
+    default;
+
+KeyedService* ClipboardRestrictionServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new ClipboardRestrictionService(user_prefs::UserPrefs::Get(context));
+}
\ No newline at end of file
diff --git a/components/enterprise/content/clipboard_restriction_service.h b/components/enterprise/content/clipboard_restriction_service.h
new file mode 100644
index 0000000..6eb25c8
--- /dev/null
+++ b/components/enterprise/content/clipboard_restriction_service.h
@@ -0,0 +1,74 @@
+// 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 COMPONENTS_ENTERPRISE_CONTENT_CLIPBOARD_RESTRICTION_SERVICE_H_
+#define COMPONENTS_ENTERPRISE_CONTENT_CLIPBOARD_RESTRICTION_SERVICE_H_
+
+#include <map>
+#include <memory>
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/policy/core/browser/url_util.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/url_matcher/url_matcher.h"
+
+namespace content {
+class BrowserContext;
+}
+
+class PrefService;
+
+class ClipboardRestrictionService : KeyedService {
+ public:
+  ClipboardRestrictionService(const ClipboardRestrictionService&) = delete;
+  ClipboardRestrictionService& operator=(const ClipboardRestrictionService&) =
+      delete;
+
+  ~ClipboardRestrictionService() override;
+
+  bool IsUrlAllowedToCopy(const GURL& url, int data_size) const;
+
+ private:
+  friend class ClipboardRestrictionServiceTest;
+  friend class ClipboardRestrictionServiceFactory;
+
+  explicit ClipboardRestrictionService(PrefService* pref_service);
+
+  void UpdateSettings();
+
+  PrefChangeRegistrar pref_change_registrar_;
+  PrefService* pref_service_;
+
+  url_matcher::URLMatcherConditionSet::ID next_id_;
+  std::unique_ptr<url_matcher::URLMatcher> enable_url_matcher_;
+  std::unique_ptr<url_matcher::URLMatcher> disable_url_matcher_;
+
+  int min_data_size_;
+};
+
+class ClipboardRestrictionServiceFactory : BrowserContextKeyedServiceFactory {
+ public:
+  ClipboardRestrictionServiceFactory(
+      const ClipboardRestrictionServiceFactory&) = delete;
+  ClipboardRestrictionServiceFactory& operator=(
+      const ClipboardRestrictionServiceFactory&) = delete;
+
+  static ClipboardRestrictionServiceFactory* GetInstance();
+  static ClipboardRestrictionService* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  ClipboardRestrictionServiceFactory();
+  ~ClipboardRestrictionServiceFactory() override;
+  friend struct base::DefaultSingletonTraits<
+      ClipboardRestrictionServiceFactory>;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+#endif  // COMPONENTS_ENTERPRISE_CONTENT_CLIPBOARD_RESTRICTION_SERVICE_H_
diff --git a/components/enterprise/content/clipboard_restriction_service_unittest.cc b/components/enterprise/content/clipboard_restriction_service_unittest.cc
new file mode 100644
index 0000000..c15f132
--- /dev/null
+++ b/components/enterprise/content/clipboard_restriction_service_unittest.cc
@@ -0,0 +1,146 @@
+// 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 "components/enterprise/content/clipboard_restriction_service.h"
+
+#include "components/enterprise/content/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+const char kTestUrl[] = "https://www.example.com";
+const char kTestPatternAllSubdomains[] = "example.com";
+const char kTestPatternWildcard[] = "*";
+const int kLargeDataSize = 1024;
+}  // namespace
+
+class ClipboardRestrictionServiceTest : public testing::Test {
+ public:
+  ClipboardRestrictionService* service() { return service_.get(); }
+
+ protected:
+  void SetPolicy(absl::optional<std::vector<std::string>> enable_patterns,
+                 absl::optional<std::vector<std::string>> disable_patterns,
+                 int min_data_size = 100) {
+    base::Value::DictStorage pref_storage;
+
+    if (enable_patterns) {
+      base::Value::ListStorage enable_storage;
+      for (const auto& p : *enable_patterns) {
+        enable_storage.push_back(base::Value(p));
+      }
+      pref_storage["enable"] = base::Value(enable_storage);
+    }
+
+    if (disable_patterns) {
+      base::Value::ListStorage disable_storage;
+      for (const auto& p : *disable_patterns) {
+        disable_storage.push_back(base::Value(p));
+      }
+      pref_storage["disable"] = base::Value(disable_storage);
+    }
+
+    pref_storage["minimum_data_size"] = base::Value(min_data_size);
+
+    pref_service_.SetManagedPref(enterprise::content::kCopyPreventionSettings,
+                                 std::make_unique<base::Value>(pref_storage));
+  }
+
+  void CreateService() {
+    service_ = std::unique_ptr<ClipboardRestrictionService>(
+        new ClipboardRestrictionService(&pref_service_));
+  }
+
+ private:
+  void SetUp() override {
+    pref_service_.registry()->RegisterDictionaryPref(
+        enterprise::content::kCopyPreventionSettings);
+  }
+
+  TestingPrefServiceSimple pref_service_;
+  std::unique_ptr<ClipboardRestrictionService> service_;
+};
+
+TEST_F(ClipboardRestrictionServiceTest, TestNoPolicySet) {
+  CreateService();
+  // All copies are allowed if the policy is unset.
+  EXPECT_TRUE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), kLargeDataSize));
+}
+
+TEST_F(ClipboardRestrictionServiceTest, BlockPatternIfMatchingEnable) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternAllSubdomains};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns);
+  EXPECT_FALSE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), kLargeDataSize));
+}
+
+TEST_F(ClipboardRestrictionServiceTest, BlockPatternIfMatchingEnableWildcard) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternWildcard};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns);
+  EXPECT_FALSE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), kLargeDataSize));
+}
+
+TEST_F(ClipboardRestrictionServiceTest, DontBlockPatternIfMatchingDisable) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternWildcard};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(empty_patterns, patterns);
+  EXPECT_TRUE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), kLargeDataSize));
+}
+
+TEST_F(ClipboardRestrictionServiceTest, DontBlockPatternIfMatchingBoth) {
+  CreateService();
+  // The service's contract is that it blocks any copy for which the URL matches
+  // a pattern in the enable list AND doesn't match a pattern in the disable
+  // list. On the admin console side, admins only specify "ON by default" or
+  // "OFF by default" and a single list of exceptions, and the enable and
+  // disable lists are generated from that.
+  std::vector<std::string> wildcard_patterns{kTestPatternWildcard};
+  std::vector<std::string> subdomain_wildcard_pattern{
+      kTestPatternAllSubdomains};
+  SetPolicy(wildcard_patterns, subdomain_wildcard_pattern);
+  EXPECT_TRUE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), kLargeDataSize));
+}
+
+TEST_F(ClipboardRestrictionServiceTest,
+       BlockPatternIfMatchingEnableAndDataSizeLargerThanMin) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternAllSubdomains};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns, 10);
+  EXPECT_FALSE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), 50));
+}
+
+TEST_F(ClipboardRestrictionServiceTest,
+       DontBlockPatternIfMatchingEnableAndDataSizeSmallerThanMin) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternAllSubdomains};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns, 50);
+  EXPECT_TRUE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), 10));
+}
+
+TEST_F(ClipboardRestrictionServiceTest,
+       DontBlockPatternIfMatchingEnableAndDataSizeSmallerThanDefaultMin) {
+  CreateService();
+  std::vector<std::string> patterns{kTestPatternAllSubdomains};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns);
+  EXPECT_TRUE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), 10));
+}
+
+TEST_F(ClipboardRestrictionServiceTest, ServiceCreatedAfterPrefValueSet) {
+  std::vector<std::string> patterns{kTestPatternAllSubdomains};
+  std::vector<std::string> empty_patterns{};
+  SetPolicy(patterns, empty_patterns, 10);
+
+  CreateService();
+
+  EXPECT_FALSE(service()->IsUrlAllowedToCopy(GURL(kTestUrl), 50));
+}
\ No newline at end of file
diff --git a/components/enterprise/content/copy_prevention_settings_policy_handler.cc b/components/enterprise/content/copy_prevention_settings_policy_handler.cc
new file mode 100644
index 0000000..c4e2ad00
--- /dev/null
+++ b/components/enterprise/content/copy_prevention_settings_policy_handler.cc
@@ -0,0 +1,83 @@
+// 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 "components/enterprise/content/copy_prevention_settings_policy_handler.h"
+
+#include "components/enterprise/content/pref_names.h"
+#include "components/policy/core/browser/policy_error_map.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/prefs/pref_value_map.h"
+#include "components/strings/grit/components_strings.h"
+
+namespace {
+const int kMinDataSizeDefault = 100;
+}
+
+CopyPreventionSettingsPolicyHandler::CopyPreventionSettingsPolicyHandler(
+    const char* policy_name,
+    const char* pref_path,
+    policy::Schema schema)
+    : SchemaValidatingPolicyHandler(
+          policy_name,
+          schema.GetKnownProperty(policy_name),
+          policy::SchemaOnErrorStrategy::SCHEMA_ALLOW_UNKNOWN),
+      pref_path_(pref_path) {}
+
+CopyPreventionSettingsPolicyHandler::~CopyPreventionSettingsPolicyHandler() =
+    default;
+
+// ConfigurationPolicyHandler:
+bool CopyPreventionSettingsPolicyHandler::CheckPolicySettings(
+    const policy::PolicyMap& policies,
+    policy::PolicyErrorMap* errors) {
+  const base::Value* value = policies.GetValue(policy_name());
+  if (!value)
+    return true;
+
+  if (!SchemaValidatingPolicyHandler::CheckPolicySettings(policies, errors))
+    return false;
+
+  const base::Value* enable = value->FindListKey(
+      enterprise::content::kCopyPreventionSettingsEnableFieldName);
+  const base::Value* disable = value->FindListKey(
+      enterprise::content::kCopyPreventionSettingsDisableFieldName);
+  if (!enable || !disable) {
+    errors->AddError(policy_name(),
+                     IDS_ENTERPRISE_COPY_PREVENTION_MISSING_LIST_ERROR);
+    return false;
+  }
+
+  for (auto& pattern : disable->GetList()) {
+    if (pattern.GetString() == "*") {
+      errors->AddError(
+          policy_name(),
+          IDS_ENTERPRISE_COPY_PREVENTION_DISABLE_CONTAINS_WILDCARD_ERROR);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void CopyPreventionSettingsPolicyHandler::ApplyPolicySettings(
+    const policy::PolicyMap& policies,
+    PrefValueMap* prefs) {
+  const base::Value* value = policies.GetValue(policy_name());
+  if (!value)
+    return;
+
+  base::Value processed_value = value->Clone();
+
+  // The min data size field is optional. Default to 100 bytes if it's not
+  // present.
+  absl::optional<int> min_data_size = value->FindIntKey(
+      enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName);
+  if (!min_data_size) {
+    processed_value.SetIntKey(
+        enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName,
+        kMinDataSizeDefault);
+  }
+
+  prefs->SetValue(pref_path_, std::move(processed_value));
+}
\ No newline at end of file
diff --git a/components/enterprise/content/copy_prevention_settings_policy_handler.h b/components/enterprise/content/copy_prevention_settings_policy_handler.h
new file mode 100644
index 0000000..7ef6a962
--- /dev/null
+++ b/components/enterprise/content/copy_prevention_settings_policy_handler.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_ENTERPRISE_CONTENT_COPY_PREVENTION_SETTINGS_POLICY_HANDLER_H_
+#define COMPONENTS_ENTERPRISE_CONTENT_COPY_PREVENTION_SETTINGS_POLICY_HANDLER_H_
+
+#include <string>
+
+#include "components/policy/core/browser/configuration_policy_handler.h"
+
+class CopyPreventionSettingsPolicyHandler
+    : public policy::SchemaValidatingPolicyHandler {
+ public:
+  CopyPreventionSettingsPolicyHandler(const char* policy_name,
+                                      const char* pref_path,
+                                      policy::Schema schema);
+  CopyPreventionSettingsPolicyHandler(CopyPreventionSettingsPolicyHandler&) =
+      delete;
+  CopyPreventionSettingsPolicyHandler& operator=(
+      CopyPreventionSettingsPolicyHandler&) = delete;
+  ~CopyPreventionSettingsPolicyHandler() override;
+
+  // ConfigurationPolicyHandler:
+  bool CheckPolicySettings(const policy::PolicyMap& policies,
+                           policy::PolicyErrorMap* errors) override;
+  void ApplyPolicySettings(const policy::PolicyMap& policies,
+                           PrefValueMap* prefs) override;
+
+ private:
+  std::string pref_path_;
+};
+
+#endif  // COMPONENTS_ENTERPRISE_CONTENT_COPY_PREVENTION_SETTINGS_POLICY_HANDLER_H_
diff --git a/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc b/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc
new file mode 100644
index 0000000..80fe0799
--- /dev/null
+++ b/components/enterprise/content/copy_prevention_settings_policy_handler_unittests.cc
@@ -0,0 +1,235 @@
+// 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 "components/enterprise/content/copy_prevention_settings_policy_handler.h"
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "components/enterprise/content/pref_names.h"
+#include "components/policy/core/browser/policy_error_map.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "components/prefs/pref_value_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/logging.h"
+
+const char kPolicyName[] = "CopyPreventionSettings";
+
+const char kSchema[] = R"(
+  {
+    "type": "object",
+    "properties": {
+      "CopyPreventionSettings": {
+        "type": "object",
+        "properties": {
+          "disable": {
+            "items": {
+              "type": "string"
+            },
+            "type": "array"
+          },
+          "enable": {
+            "items": {
+              "type": "string"
+            },
+            "type": "array"
+          },
+          "minimum_data_size": {
+            "minimum": 0,
+            "type": "integer"
+          }
+        }
+      }
+    }
+  }
+)";
+
+const char kValidPolicy[] = R"(
+  {
+    "enable": ["*"],
+    "disable": ["example.com"],
+    "minimum_data_size": 100,
+  }
+)";
+
+const char kValidWithoutMinDataSizePolicy[] = R"(
+  {
+    "enable": ["*"],
+    "disable": ["example.com"],
+  }
+)";
+
+const char kNegativeMinDataSizeInvalidPolicy[] = R"(
+  {
+    "enable": ["*"],
+    "disable": ["example.com"],
+    "minimum_data_size": -1,
+  }
+)";
+
+const char kMissingEnableListPolicy[] = R"(
+  {
+    "disable": ["example.com"],
+    "minimum_data_size": 100,
+  }
+)";
+
+const char kMissingDisableListPolicy[] = R"(
+  {
+    "enable": ["*"],
+    "minimum_data_size": 100,
+  }
+)";
+
+const char kDisableListWithWildcardInvalidPolicy[] = R"(
+  {
+    "enable": [],
+    "disable": ["*"],
+    "minimum_data_size": 100,
+  }
+)";
+
+class CopyPreventionSettingsPolicyHandlerTest : public testing::Test {
+ protected:
+  policy::Schema& schema() { return schema_; }
+
+ private:
+  void SetUp() override {
+    std::string error;
+    schema_ = policy::Schema::Parse(kSchema, &error);
+
+    ASSERT_TRUE(error.empty());
+    ASSERT_TRUE(schema_.valid());
+  }
+
+  policy::Schema schema_;
+};
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest, TestValidPolicy) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(
+      kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+      policy::PolicyScope::POLICY_SCOPE_MACHINE,
+      policy::PolicySource::POLICY_SOURCE_CLOUD,
+      base::JSONReader::Read(kValidPolicy, base::JSON_ALLOW_TRAILING_COMMAS),
+      nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_TRUE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_TRUE(errors.empty());
+
+  PrefValueMap prefs;
+  handler->ApplyPolicySettings(policy_map, &prefs);
+
+  base::Value* value_in_pref;
+  ASSERT_TRUE(prefs.GetValue(enterprise::content::kCopyPreventionSettings,
+                             &value_in_pref));
+
+  const base::Value* value_in_map = policy_map.GetValue(kPolicyName);
+  ASSERT_TRUE(value_in_pref->Equals(value_in_map));
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest,
+       TestValidPolicyWithoutMinDataSizeDefaultsTo100) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+                 policy::PolicyScope::POLICY_SCOPE_MACHINE,
+                 policy::PolicySource::POLICY_SOURCE_CLOUD,
+                 base::JSONReader::Read(kValidWithoutMinDataSizePolicy,
+                                        base::JSON_ALLOW_TRAILING_COMMAS),
+                 nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_TRUE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_TRUE(errors.empty());
+
+  PrefValueMap prefs;
+  handler->ApplyPolicySettings(policy_map, &prefs);
+
+  base::Value* value_in_pref;
+  ASSERT_TRUE(prefs.GetValue(enterprise::content::kCopyPreventionSettings,
+                             &value_in_pref));
+
+  absl::optional<int> min_data_size = value_in_pref->FindIntKey(
+      enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName);
+  ASSERT_TRUE(min_data_size);
+  ASSERT_EQ(100, *min_data_size);
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest, TestMissingEnableListInvalid) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+                 policy::PolicyScope::POLICY_SCOPE_MACHINE,
+                 policy::PolicySource::POLICY_SOURCE_CLOUD,
+                 base::JSONReader::Read(kMissingEnableListPolicy,
+                                        base::JSON_ALLOW_TRAILING_COMMAS),
+                 nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_FALSE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_FALSE(errors.empty());
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest, TestMissingDisableListInvalid) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+                 policy::PolicyScope::POLICY_SCOPE_MACHINE,
+                 policy::PolicySource::POLICY_SOURCE_CLOUD,
+                 base::JSONReader::Read(kMissingDisableListPolicy,
+                                        base::JSON_ALLOW_TRAILING_COMMAS),
+                 nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_FALSE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_FALSE(errors.empty());
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest,
+       TestDisableListContainingWildcardInvalid) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+                 policy::PolicyScope::POLICY_SCOPE_MACHINE,
+                 policy::PolicySource::POLICY_SOURCE_CLOUD,
+                 base::JSONReader::Read(kDisableListWithWildcardInvalidPolicy,
+                                        base::JSON_ALLOW_TRAILING_COMMAS),
+                 nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_FALSE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_FALSE(errors.empty());
+}
+
+TEST_F(CopyPreventionSettingsPolicyHandlerTest,
+       TestNegativeMinDataSizeInvalid) {
+  policy::PolicyMap policy_map;
+  policy_map.Set(kPolicyName, policy::PolicyLevel::POLICY_LEVEL_MANDATORY,
+                 policy::PolicyScope::POLICY_SCOPE_MACHINE,
+                 policy::PolicySource::POLICY_SOURCE_CLOUD,
+                 base::JSONReader::Read(kNegativeMinDataSizeInvalidPolicy,
+                                        base::JSON_ALLOW_TRAILING_COMMAS),
+                 nullptr);
+
+  auto handler = std::make_unique<CopyPreventionSettingsPolicyHandler>(
+      kPolicyName, enterprise::content::kCopyPreventionSettings, schema());
+
+  policy::PolicyErrorMap errors;
+  ASSERT_FALSE(handler->CheckPolicySettings(policy_map, &errors));
+  ASSERT_FALSE(errors.empty());
+}
\ No newline at end of file
diff --git a/components/enterprise/content/pref_names.cc b/components/enterprise/content/pref_names.cc
new file mode 100644
index 0000000..a398e95
--- /dev/null
+++ b/components/enterprise/content/pref_names.cc
@@ -0,0 +1,18 @@
+// 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 "components/enterprise/content/pref_names.h"
+
+namespace enterprise {
+namespace content {
+
+// Dictionary policy describing a set of URL patterns where copying to the
+// clipboard is not allowed.
+const char kCopyPreventionSettings[] = "policy.copy_prevention_settings";
+const char kCopyPreventionSettingsEnableFieldName[] = "enable";
+const char kCopyPreventionSettingsDisableFieldName[] = "disable";
+const char kCopyPreventionSettingsMinDataSizeFieldName[] = "minimum_data_size";
+
+}  // namespace content
+}  // namespace enterprise
\ No newline at end of file
diff --git a/components/enterprise/content/pref_names.h b/components/enterprise/content/pref_names.h
new file mode 100644
index 0000000..1c91480
--- /dev/null
+++ b/components/enterprise/content/pref_names.h
@@ -0,0 +1,19 @@
+// 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 COMPONENTS_ENTERPRISE_CONTENT_PREF_NAMES_H_
+#define COMPONENTS_ENTERPRISE_CONTENT_PREF_NAMES_H_
+
+namespace enterprise {
+namespace content {
+
+extern const char kCopyPreventionSettings[];
+extern const char kCopyPreventionSettingsEnableFieldName[];
+extern const char kCopyPreventionSettingsDisableFieldName[];
+extern const char kCopyPreventionSettingsMinDataSizeFieldName[];
+
+}  // namespace content
+}  // namespace enterprise
+
+#endif  // COMPONENTS_ENTERPRISE_CONTENT_PREF_NAMES_H_
diff --git a/components/enterprise_strings.grdp b/components/enterprise_strings.grdp
new file mode 100644
index 0000000..b628dfc
--- /dev/null
+++ b/components/enterprise_strings.grdp
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+  <message name="IDS_ENTERPRISE_COPY_PREVENTION_MISSING_LIST_ERROR" desc="Message indicating that the supplied value for the CopyPreventionSettings policy is missing one of the list fields">
+      Ignored because either the "enable" or "disable" list is missing.
+  </message>
+  <message name="IDS_ENTERPRISE_COPY_PREVENTION_DISABLE_CONTAINS_WILDCARD_ERROR" desc="Message indicating that the supplied value for the CopyPreventionSettings policy contains the wildcard character ('*') in the disable list, which is equivalent to disabling the policy completely">
+      Ignored because the disable list contains a pattern equal to '*', which is equivalent to disabling the policy.
+  </message>
+</grit-part>
\ No newline at end of file
diff --git a/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_DISABLE_CONTAINS_WILDCARD_ERROR.png.sha1 b/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_DISABLE_CONTAINS_WILDCARD_ERROR.png.sha1
new file mode 100644
index 0000000..63f7f1b
--- /dev/null
+++ b/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_DISABLE_CONTAINS_WILDCARD_ERROR.png.sha1
@@ -0,0 +1 @@
+76c7df62f2f087b1edc3350b57d36a1b704bcbba
\ No newline at end of file
diff --git a/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_MISSING_LIST_ERROR.png.sha1 b/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_MISSING_LIST_ERROR.png.sha1
new file mode 100644
index 0000000..e800c84b
--- /dev/null
+++ b/components/enterprise_strings_grdp/IDS_ENTERPRISE_COPY_PREVENTION_MISSING_LIST_ERROR.png.sha1
@@ -0,0 +1 @@
+c56b0349c64768a5c94f49f53aed9bded32935be
\ No newline at end of file
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc
index 2acd349..c19423d 100644
--- a/components/policy/core/common/policy_pref_names.cc
+++ b/components/policy/core/common/policy_pref_names.cc
@@ -79,9 +79,5 @@
 const char kUserAgentClientHintsGREASEUpdateEnabled[] =
     "policy.user_agent_client_hints_grease_update_enabled";
 
-// Dictionary policy describing a set of URL patterns where copying to the
-// clipboard is not allowed.
-const char kCopyPreventionSettings[] = "policy.copy_prevention_settings";
-
 }  // namespace policy_prefs
 }  // namespace policy
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h
index f542de9..84c1b6bd 100644
--- a/components/policy/core/common/policy_pref_names.h
+++ b/components/policy/core/common/policy_pref_names.h
@@ -30,7 +30,6 @@
 POLICY_EXPORT extern const char kBackForwardCacheEnabled[];
 #endif  // defined(OS_ANDROID)
 POLICY_EXPORT extern const char kWebSQLInThirdPartyContextEnabled[];
-POLICY_EXPORT extern const char kCopyPreventionSettings[];
 
 }  // namespace policy_prefs
 }  // namespace policy
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 21ceebf4..0d90faf 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -41,7 +41,7 @@
   // Invalid unique position.
   // kDeprecatedInvalidUniquePosition = 2,
   // Permanent node creation in an incremental update.
-  kPermanentNodeCreationAfterMerge = 3,
+  // kDeprecatedPermanentNodeCreationAfterMerge = 3,
   // Parent entity not found in server.
   kMissingParentEntity = 4,
   // Parent node not found locally.
@@ -68,7 +68,7 @@
   base::UmaHistogramEnumeration("Sync.ProblematicServerSideBookmarks", problem);
 }
 
-// Recursive method to traverse a forest created by ReorderUpdates() to to
+// Recursive method to traverse a forest created by ReorderValidUpdates() to
 // emit updates in top-down order. |ordered_updates| must not be null because
 // traversed updates are appended to |*ordered_updates|.
 void TraverseAndAppendChildren(
@@ -129,6 +129,40 @@
   return iter - parent->children().begin();
 }
 
+bool IsPermanentNodeUpdate(const syncer::EntityData& update_entity) {
+  return update_entity.parent_id == "0" ||
+         !update_entity.server_defined_unique_tag.empty();
+}
+
+// Checks that the |update_entity| is valid and returns false otherwise. It is
+// used to verify non-deletion updates. |update| must not be a deletion and a
+// permanent node (they are processed in a different way).
+bool IsValidUpdate(const syncer::EntityData& update_entity) {
+  DCHECK(!update_entity.is_deleted());
+  DCHECK(!IsPermanentNodeUpdate(update_entity));
+
+  if (!IsValidBookmarkSpecifics(update_entity.specifics.bookmark())) {
+    // Ignore updates with invalid specifics.
+    DLOG(ERROR)
+        << "Couldn't process an update bookmark with an invalid specifics.";
+    LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidSpecifics);
+    return false;
+  }
+
+  if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(),
+                               update_entity.client_tag_hash,
+                               update_entity.originator_cache_guid,
+                               update_entity.originator_client_item_id)) {
+    // Ignore updates with an unexpected GUID.
+    DLOG(ERROR) << "Couldn't process an update bookmark with unexpected GUID: "
+                << update_entity.specifics.bookmark().guid();
+    LogProblematicBookmark(RemoteBookmarkUpdateError::kUnexpectedGuid);
+    return false;
+  }
+
+  return true;
+}
+
 void ApplyRemoteUpdate(
     const syncer::UpdateResponseData& update,
     const SyncedBookmarkTracker::Entity* tracked_entity,
@@ -206,42 +240,12 @@
   // re-encryption phase at the end.
   std::unordered_set<std::string> entities_with_up_to_date_encryption;
 
-  for (const syncer::UpdateResponseData* update : ReorderUpdates(&updates)) {
+  for (const syncer::UpdateResponseData* update :
+       ReorderValidUpdates(&updates)) {
     const syncer::EntityData& update_entity = update->entity;
 
-    // Ignore changes to the permanent nodes (e.g. bookmarks bar). We only
-    // care about their children.
-    if (!update_entity.server_defined_unique_tag.empty()) {
-      if (bookmark_tracker_->GetEntityForSyncId(update_entity.id) == nullptr) {
-        DLOG(ERROR)
-            << "Permanent nodes should have been merged during intial sync.";
-        LogProblematicBookmark(
-            RemoteBookmarkUpdateError::kPermanentNodeCreationAfterMerge);
-      }
-      continue;
-    }
-
-    // Only non-deletions should have valid specifics and unique positions.
-    if (!update_entity.is_deleted()) {
-      if (!IsValidBookmarkSpecifics(update_entity.specifics.bookmark())) {
-        // Ignore updates with invalid specifics.
-        DLOG(ERROR)
-            << "Couldn't process an update bookmark with an invalid specifics.";
-        LogProblematicBookmark(RemoteBookmarkUpdateError::kInvalidSpecifics);
-        continue;
-      }
-      if (!HasExpectedBookmarkGuid(update_entity.specifics.bookmark(),
-                                   update_entity.client_tag_hash,
-                                   update_entity.originator_cache_guid,
-                                   update_entity.originator_client_item_id)) {
-        // Ignore updates with an unexpected GUID.
-        DLOG(ERROR)
-            << "Couldn't process an update bookmark with unexpected GUID: "
-            << update_entity.specifics.bookmark().guid();
-        LogProblematicBookmark(RemoteBookmarkUpdateError::kUnexpectedGuid);
-        continue;
-      }
-    }
+    DCHECK(!IsPermanentNodeUpdate(update_entity));
+    DCHECK(update_entity.is_deleted() || IsValidUpdate(update_entity));
 
     bool should_ignore_update = false;
     const SyncedBookmarkTracker::Entity* tracked_entity =
@@ -365,9 +369,9 @@
 
 // static
 std::vector<const syncer::UpdateResponseData*>
-BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(
+BookmarkRemoteUpdatesHandler::ReorderValidUpdatesForTest(
     const syncer::UpdateResponseDataList* updates) {
-  return ReorderUpdates(updates);
+  return ReorderValidUpdates(updates);
 }
 
 // static
@@ -380,7 +384,7 @@
 
 // static
 std::vector<const syncer::UpdateResponseData*>
-BookmarkRemoteUpdatesHandler::ReorderUpdates(
+BookmarkRemoteUpdatesHandler::ReorderValidUpdates(
     const syncer::UpdateResponseDataList* updates) {
   // This method sorts the remote updates according to the following rules:
   // 1. Creations and updates come before deletions.
@@ -408,16 +412,23 @@
                      base::StringPieceHash>
       parent_to_children;
 
-  // Add only non-deletions to |id_to_updates|.
+  // Add only valid, non-deletions to |id_to_updates|.
+  int invalid_updates_count = 0;
+  int root_node_updates_count = 0;
   for (const syncer::UpdateResponseData& update : *updates) {
     const syncer::EntityData& update_entity = update.entity;
     // Ignore updates to root nodes.
-    if (update_entity.parent_id == "0") {
+    if (IsPermanentNodeUpdate(update_entity)) {
+      ++root_node_updates_count;
       continue;
     }
     if (update_entity.is_deleted()) {
       continue;
     }
+    if (!IsValidUpdate(update_entity)) {
+      ++invalid_updates_count;
+      continue;
+    }
     id_to_updates[update_entity.id] = &update;
   }
   // Iterate over |id_to_updates| and construct |roots| and
@@ -439,14 +450,11 @@
     TraverseAndAppendChildren(root, id_to_updates, parent_to_children,
                               &ordered_updates);
   }
-
-  int root_node_updates_count = 0;
   // Add deletions.
   for (const syncer::UpdateResponseData& update : *updates) {
     const syncer::EntityData& update_entity = update.entity;
     // Ignore updates to root nodes.
-    if (update_entity.parent_id == "0") {
-      root_node_updates_count++;
+    if (IsPermanentNodeUpdate(update_entity)) {
       continue;
     }
     if (update_entity.is_deleted()) {
@@ -454,7 +462,8 @@
     }
   }
   // All non root updates should have been included in |ordered_updates|.
-  DCHECK_EQ(updates->size(), ordered_updates.size() + root_node_updates_count);
+  DCHECK_EQ(updates->size(), ordered_updates.size() + root_node_updates_count +
+                                 invalid_updates_count);
   return ordered_updates;
 }
 
@@ -525,7 +534,7 @@
     const syncer::UpdateResponseData& update) {
   const syncer::EntityData& update_entity = update.entity;
   DCHECK(!update_entity.is_deleted());
-  DCHECK(update_entity.server_defined_unique_tag.empty());
+  DCHECK(!IsPermanentNodeUpdate(update_entity));
   DCHECK(IsValidBookmarkSpecifics(update_entity.specifics.bookmark()));
 
   const bookmarks::BookmarkNode* parent_node = GetParentNode(update_entity);
@@ -576,7 +585,7 @@
             bookmark_tracker_->GetEntityForSyncId(update_entity.id));
   // Must not be a deletion.
   DCHECK(!update_entity.is_deleted());
-  DCHECK(update_entity.server_defined_unique_tag.empty());
+  DCHECK(!IsPermanentNodeUpdate(update_entity));
   DCHECK(IsValidBookmarkSpecifics(update_entity.specifics.bookmark()));
   DCHECK(!tracked_entity->IsUnsynced());
 
@@ -661,7 +670,7 @@
             bookmark_tracker_->GetEntityForSyncId(update_entity.id));
   DCHECK(!tracked_entity->bookmark_node() ||
          !tracked_entity->bookmark_node()->is_permanent_node());
-  DCHECK(update_entity.server_defined_unique_tag.empty());
+  DCHECK(!IsPermanentNodeUpdate(update_entity));
 
   if (tracked_entity->metadata()->is_deleted() && update_entity.is_deleted()) {
     // Both have been deleted, delete the corresponding entity from the tracker.
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h
index a27db4d..277f38b 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.h
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -46,8 +46,8 @@
                bool got_new_encryption_requirements);
 
   // Public for testing.
-  static std::vector<const syncer::UpdateResponseData*> ReorderUpdatesForTest(
-      const syncer::UpdateResponseDataList* updates);
+  static std::vector<const syncer::UpdateResponseData*>
+  ReorderValidUpdatesForTest(const syncer::UpdateResponseDataList* updates);
 
   static size_t ComputeChildNodeIndexForTest(
       const bookmarks::BookmarkNode* parent,
@@ -58,8 +58,8 @@
   // Reorders incoming updates such that parent creation is before child
   // creation and child deletion is before parent deletion, and deletions should
   // come last. The returned pointers point to the elements in the original
-  // |updates|.
-  static std::vector<const syncer::UpdateResponseData*> ReorderUpdates(
+  // |updates|. In this process, invalid updates are filtered out.
+  static std::vector<const syncer::UpdateResponseData*> ReorderValidUpdates(
       const syncer::UpdateResponseDataList* updates);
 
   // Returns the tracked entity that should be affected by a remote change, or
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index 7f87d02e..8c7e7c4 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -60,7 +60,7 @@
   kConflictingTypes = 0,
   kInvalidSpecifics = 1,
   // kDeprecatedInvalidUniquePosition = 2,
-  kPermanentNodeCreationAfterMerge = 3,
+  // kDeprecatedPermanentNodeCreationAfterMerge = 3,
   kMissingParentEntity = 4,
   kMissingParentNode = 5,
   kMissingParentEntityInConflict = 6,
@@ -239,12 +239,43 @@
   syncer::UpdateResponseDataList updates;
   updates.push_back(CreateBookmarkRootUpdateData());
   std::vector<const syncer::UpdateResponseData*> ordered_updates =
-      BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(&updates);
+      BookmarkRemoteUpdatesHandler::ReorderValidUpdatesForTest(&updates);
   // Root node update should be filtered out.
   EXPECT_THAT(ordered_updates.size(), Eq(0U));
 }
 
 TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldIgnoreInvalidSpecifics) {
+  const std::string kId = "id";
+  const std::string kTitle = "title";
+  const syncer::UniquePosition kPosition = RandomUniquePosition();
+
+  syncer::UpdateResponseDataList updates;
+
+  // Create update with an invalid GUID.
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/kId,
+      /*parent_id=*/kBookmarkBarId,
+      /*guid=*/base::GUID(),
+      /*title=*/kTitle,
+      /*is_deletion=*/false,
+      /*version=*/0,
+      /*unique_position=*/kPosition));
+
+  base::HistogramTester histogram_tester;
+  std::vector<const syncer::UpdateResponseData*> ordered_updates =
+      BookmarkRemoteUpdatesHandler::ReorderValidUpdatesForTest(&updates);
+
+  // The update should be filtered out.
+  EXPECT_THAT(ordered_updates.size(), Eq(0U));
+
+  histogram_tester.ExpectBucketCount(
+      "Sync.ProblematicServerSideBookmarks",
+      /*sample=*/ExpectedRemoteBookmarkUpdateError::kInvalidSpecifics,
+      /*expected_count=*/1);
+}
+
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
      ShouldReorderParentsUpdateBeforeChildrenAndBothBeforeDeletions) {
   // Prepare creation updates to build this structure:
   // bookmark_bar
@@ -297,7 +328,7 @@
                                /*is_deletion=*/false));
 
   std::vector<const syncer::UpdateResponseData*> ordered_updates =
-      BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(&updates);
+      BookmarkRemoteUpdatesHandler::ReorderValidUpdatesForTest(&updates);
 
   // No update should be dropped.
   ASSERT_THAT(ordered_updates.size(), Eq(6U));
diff --git a/content/browser/accessibility/accessibility_event_recorder_mac.mm b/content/browser/accessibility/accessibility_event_recorder_mac.mm
index bb03059..783ce3a 100644
--- a/content/browser/accessibility/accessibility_event_recorder_mac.mm
+++ b/content/browser/accessibility/accessibility_event_recorder_mac.mm
@@ -155,6 +155,9 @@
 std::string
 AccessibilityEventRecorderMac::SerializeTextSelectionChangedProperties(
     CFDictionaryRef user_info) {
+  if (user_info == nil)
+    return {};
+
   std::vector<std::string> serialized_info;
   CFDictionaryApplyFunction(
       user_info,
diff --git a/content/browser/child_process_launcher_helper.cc b/content/browser/child_process_launcher_helper.cc
index f32a9d3..812839c 100644
--- a/content/browser/child_process_launcher_helper.cc
+++ b/content/browser/child_process_launcher_helper.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task/lazy_thread_pool_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/single_thread_task_runner.h"
@@ -119,6 +120,13 @@
   DCHECK(CurrentlyOnProcessLauncherTaskRunner());
 
   begin_launch_time_ = base::TimeTicks::Now();
+  if (GetProcessType() == switches::kRendererProcess &&
+      base::TimeTicks::IsConsistentAcrossProcesses()) {
+    const base::TimeDelta ticks_as_delta = begin_launch_time_.since_origin();
+    command_line_->AppendSwitchASCII(
+        switches::kRendererProcessLaunchTimeTicks,
+        base::NumberToString(ticks_as_delta.InMicroseconds()));
+  }
 
   std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap();
 
diff --git a/content/browser/cross_origin_opener_policy_browsertest.cc b/content/browser/cross_origin_opener_policy_browsertest.cc
index 32be26e..f9c2c4e 100644
--- a/content/browser/cross_origin_opener_policy_browsertest.cc
+++ b/content/browser/cross_origin_opener_policy_browsertest.cc
@@ -1296,6 +1296,100 @@
   }
 }
 
+// https://crbug.com/1266819 suggested that navigating to a cross-origin page
+// from a cross-origin isolated page is a good reproducer for potential
+// speculative RFHs + crossOriginIsolated issues. Tests from both a regular and
+// a crashed frame to also verify with the crash optimization commit.
+IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest,
+                       SpeculativeSiteInstanceAndCrossOriginIsolation) {
+  GURL coop_page_a =
+      https_server()->GetURL("a.test",
+                             "/set-header?"
+                             "Cross-Origin-Opener-Policy: same-origin&"
+                             "Cross-Origin-Embedder-Policy: require-corp");
+  GURL page_b(https_server()->GetURL("b.test", "/title1.html"));
+
+  // Usual navigation.
+  {
+    // Start on a COI page.
+    EXPECT_TRUE(NavigateToURL(shell(), coop_page_a));
+    scoped_refptr<SiteInstanceImpl> main_site_instance(
+        current_frame_host()->GetSiteInstance());
+    EXPECT_TRUE(main_site_instance->IsCrossOriginIsolated());
+
+    // Popup to a cross-origin page.
+    ShellAddedObserver shell_observer;
+    EXPECT_TRUE(ExecJs(current_frame_host(),
+                       JsReplace("window.open($1, 'windowName')", page_b)));
+    WebContents* popup = shell_observer.GetShell()->web_contents();
+    WaitForLoadStop(popup);
+
+    RenderFrameHostImpl* popup_frame_host = static_cast<WebContentsImpl*>(popup)
+                                                ->GetPrimaryFrameTree()
+                                                .root()
+                                                ->current_frame_host();
+    scoped_refptr<SiteInstanceImpl> popup_site_instance(
+        popup_frame_host->GetSiteInstance());
+    EXPECT_FALSE(popup_site_instance->IsCrossOriginIsolated());
+
+    // Verify that COOP enforcement was done properly.
+    EXPECT_FALSE(
+        main_site_instance->IsRelatedSiteInstance(popup_site_instance.get()));
+    EXPECT_EQ(true, EvalJs(popup_frame_host, "window.opener == null;"));
+    EXPECT_EQ("", EvalJs(popup_frame_host, "window.name"));
+    popup->Close();
+  }
+
+  // Navigation from a crashed page.
+  {
+    // Start on a COI page.
+    EXPECT_TRUE(NavigateToURL(shell(), coop_page_a));
+    scoped_refptr<SiteInstanceImpl> main_site_instance(
+        current_frame_host()->GetSiteInstance());
+    EXPECT_TRUE(main_site_instance->IsCrossOriginIsolated());
+
+    // Open an empty popup.
+    ShellAddedObserver shell_observer;
+    EXPECT_TRUE(ExecJs(current_frame_host(),
+                       "window.open('about:blank', 'windowName')"));
+    WebContents* popup = shell_observer.GetShell()->web_contents();
+    WaitForLoadStop(popup);
+    RenderFrameHostImpl* popup_frame_host = static_cast<WebContentsImpl*>(popup)
+                                                ->GetPrimaryFrameTree()
+                                                .root()
+                                                ->current_frame_host();
+    scoped_refptr<SiteInstanceImpl> popup_site_instance(
+        popup_frame_host->GetSiteInstance());
+
+    // Crash it.
+    {
+      RenderProcessHost* process = popup_site_instance->GetProcess();
+      ASSERT_TRUE(process);
+      auto crash_observer = std::make_unique<RenderProcessHostWatcher>(
+          process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+      process->Shutdown(0);
+      crash_observer->Wait();
+    }
+
+    // Navigate it to a cross-origin page.
+    EXPECT_TRUE(NavigateToURL(popup, page_b));
+    WaitForLoadStop(popup);
+    popup_frame_host = static_cast<WebContentsImpl*>(popup)
+                           ->GetPrimaryFrameTree()
+                           .root()
+                           ->current_frame_host();
+    popup_site_instance = popup_frame_host->GetSiteInstance();
+    EXPECT_FALSE(popup_site_instance->IsCrossOriginIsolated());
+
+    // Verify that COOP enforcement was done properly.
+    EXPECT_FALSE(
+        main_site_instance->IsRelatedSiteInstance(popup_site_instance.get()));
+    EXPECT_EQ(true, EvalJs(popup_frame_host, "window.opener == null;"));
+    EXPECT_EQ("", EvalJs(popup_frame_host, "window.name"));
+    popup->Close();
+  }
+}
+
 // Try to host into the same cross-origin isolated process, two cross-origin
 // documents. The second's response sets CSP:sandbox, so its origin is opaque
 // and derived from the first.
diff --git a/content/browser/loader/web_transport_browsertest.cc b/content/browser/loader/web_transport_browsertest.cc
index f1bd2fbe..ef7968d4 100644
--- a/content/browser/loader/web_transport_browsertest.cc
+++ b/content/browser/loader/web_transport_browsertest.cc
@@ -196,7 +196,8 @@
   ASSERT_TRUE(WaitForTitle(u"PASS", {u"FAIL"}));
 }
 
-IN_PROC_BROWSER_TEST_F(WebTransportBrowserTest, ReceiveStream) {
+// Disabled due to flakes; see https://crbug.com/1140193.
+IN_PROC_BROWSER_TEST_F(WebTransportBrowserTest, DISABLED_ReceiveStream) {
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(
       NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 795b6ca..a9e2cbc9 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -1417,6 +1417,10 @@
   GURL url = embedded_test_server()->GetURL("a.com", "/title2.html");
   CreatePortalToUrl(web_contents_impl, url);
 
+  // Install a beforeunload handler.
+  main_frame->SuddenTerminationDisablerChanged(
+      true, blink::mojom::SuddenTerminationDisablerType::kBeforeUnloadHandler);
+
   // Have the outer page try to navigate away but stop it early in the request,
   // where it is still possible to stop.
   GURL destination =
@@ -1459,6 +1463,10 @@
   GURL url = embedded_test_server()->GetURL("a.com", "/title2.html");
   CreatePortalToUrl(web_contents_impl, url);
 
+  // Install a beforeunload handler.
+  main_frame->SuddenTerminationDisablerChanged(
+      true, blink::mojom::SuddenTerminationDisablerType::kBeforeUnloadHandler);
+
   // Have the outer page try to navigate away and reach the point where it's
   // about to process the response (after which it will commit). It is too late
   // to abort the navigation.
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 87bcd42c..a7c6553 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -696,6 +696,9 @@
 // Causes the process to run as renderer instead of as browser.
 const char kRendererProcess[]               = "renderer";
 
+// Time the browser launched the renderer process (in TimeTicks).
+const char kRendererProcessLaunchTimeTicks[] = "launch-time-ticks";
+
 // Overrides the default/calculated limit to the number of renderer processes.
 // Very high values for this setting can lead to high memory/resource usage
 // or instability.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index ea855ee9..b26a40b8 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -192,6 +192,7 @@
 CONTENT_EXPORT extern const char kRendererClientId[];
 extern const char kRendererCmdPrefix[];
 CONTENT_EXPORT extern const char kRendererProcess[];
+CONTENT_EXPORT extern const char kRendererProcessLaunchTimeTicks[];
 CONTENT_EXPORT extern const char kRendererProcessLimit[];
 CONTENT_EXPORT extern const char kRendererStartupDialog[];
 CONTENT_EXPORT extern const char kRunManualTestsFlag[];
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 59bec88..625c984f 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -12,6 +12,7 @@
 #include "base/i18n/rtl.h"
 #include "base/message_loop/message_pump.h"
 #include "base/message_loop/message_pump_type.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/pending_task.h"
 #include "base/run_loop.h"
@@ -103,6 +104,24 @@
 #endif
 }
 
+void LogTimeToStartRunLoop(const base::CommandLine& command_line,
+                           base::TimeTicks run_loop_start_time) {
+  if (!command_line.HasSwitch(switches::kRendererProcessLaunchTimeTicks))
+    return;
+
+  const std::string launch_time_delta_micro_as_string =
+      command_line.GetSwitchValueASCII(
+          switches::kRendererProcessLaunchTimeTicks);
+  int64_t launch_time_delta_micro;
+  if (!base::StringToInt64(launch_time_delta_micro_as_string,
+                           &launch_time_delta_micro)) {
+    return;
+  }
+  const base::TimeDelta delta = run_loop_start_time.since_origin() -
+                                base::Microseconds(launch_time_delta_micro);
+  base::UmaHistogramTimes("Renderer.BrowserLaunchToRunLoopStart", delta);
+}
+
 }  // namespace
 
 // mainline routine for running as the Renderer process
@@ -258,8 +277,9 @@
 #endif
       TRACE_EVENT_INSTANT0("toplevel", "RendererMain.START_MSG_LOOP",
                            TRACE_EVENT_SCOPE_THREAD);
-      RenderThreadImpl::current()->set_run_loop_start_time(
-          base::TimeTicks::Now());
+      const base::TimeTicks run_loop_start_time = base::TimeTicks::Now();
+      RenderThreadImpl::current()->set_run_loop_start_time(run_loop_start_time);
+      LogTimeToStartRunLoop(command_line, run_loop_start_time);
       run_loop.Run();
     }
 
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn
index cd3221c..b3556fdd 100644
--- a/content/shell/android/BUILD.gn
+++ b/content/shell/android/BUILD.gn
@@ -223,6 +223,7 @@
   apk_name = "ContentShellTest"
   android_manifest = content_shell_test_manifest
   android_manifest_dep = ":content_shell_test_manifest"
+  use_vpython3 = false
   shared_libraries = [ ":libcontent_native_test" ]
   deps = [
     "//base:base_java_test_support",
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_screen_space_antialiasing.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_screen_space_antialiasing.txt
deleted file mode 100644
index df7d699..0000000
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_screen_space_antialiasing.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-Name
-
-    CHROMIUM_screen_space_antialiasing
-
-Name Strings
-
-    GL_CHROMIUM_screen_space_antialiasing
-
-Version
-
-    Last Modifed Date: August 27, 2015
-
-Dependencies
-
-    OpenGL ES 2.0 is required.
-
-Overview
-
-    This extension performs the antialiasing to all color attachments of
-    the currently bound draw framebuffer. Reference GL_INTEL_framebuffer_CMAA
-    for more details.
-
-New Tokens
-
-    None
-
-New Procedures and Functions
-
-    void ApplyScreenSpaceAntialiasingCHROMIUM(void);
-
-    Apply antialiasing to all color attachments of the currently bound draw framebuffer.
-
-    INVALID_OPERATION is generated if any of the current draw buffers is multisampled.
-
-    INVALID_OPERATION is generated if any framebuffer object is not bound.
-
-    OUT_OF_MEMORY may be generated if fail to allocate internal resources necessary to 
-    perform the requested operation.
-
-Errors
-
-    None.
-
-New State
-
-    None.
-
-Revision History
-
-    27/8/2015    Documented the extension
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index 245abee..4938021 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -453,15 +453,6 @@
 #endif
 #endif  /* GL_CHROMIUM_command_buffer_latency_query */
 
-/* GL_CHROMIUM_screen_space_antialiasing */
-#ifndef GL_CHROMIUM_screen_space_antialiasing
-#define GL_CHROMIUM_screen_space_antialiasing 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glApplyScreenSpaceAntialiasingCHROMIUM();
-#endif
-typedef void(GL_APIENTRYP PFNGLAPPLYSCREENSPACEANTIALIASINGCHROMIUMPROC)();
-#endif /* GL_CHROMIUM_screen_space_antialiasing */
-
 /* GL_ARB_robustness */
 #ifndef GL_ARB_robustness
 #define GL_ARB_robustness 1
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index fb30ec87..bc65d0f 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -359,6 +359,11 @@
       "//gpu/vulkan",
     ]
 
+    sources += [
+      "shared_image_backing_factory_angle_vulkan.cc",
+      "shared_image_backing_factory_angle_vulkan.h",
+    ]
+
     if (is_linux || is_chromeos || is_fuchsia || is_android || is_win) {
       sources += [
         "external_semaphore.cc",
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
new file mode 100644
index 0000000..f11cf27
--- /dev/null
+++ b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
@@ -0,0 +1,370 @@
+// 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 "gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.h"
+
+#include "base/logging.h"
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/shared_image_backing.h"
+#include "gpu/command_buffer/service/shared_image_backing_gl_common.h"
+#include "gpu/command_buffer/service/shared_image_backing_gl_image.h"
+#include "gpu/command_buffer/service/shared_image_representation.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "third_party/skia/include/core/SkPromiseImageTexture.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image_egl_angle_vulkan.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/progress_reporter.h"
+
+namespace gpu {
+
+namespace {
+
+size_t EstimatedSize(viz::ResourceFormat format, const gfx::Size& size) {
+  size_t estimated_size = 0;
+  viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size);
+  return estimated_size;
+}
+
+GrVkImageInfo CreateGrVkImageInfo(
+    VkImage vk_image,
+    const VkImageCreateInfo& info,
+    const raw_ptr<SharedContextState>& context_state) {
+  DCHECK_NE(vk_image, VK_NULL_HANDLE);
+
+  bool is_protected = info.flags & VK_IMAGE_CREATE_PROTECTED_BIT;
+
+  GrVkImageInfo image_info;
+  image_info.fImage = vk_image;
+  image_info.fAlloc = {};
+  image_info.fImageTiling = info.tiling;
+  image_info.fImageLayout = info.initialLayout;
+  image_info.fFormat = info.format;
+  image_info.fImageUsageFlags = info.usage;
+  image_info.fSampleCount = info.samples;
+  image_info.fLevelCount = info.mipLevels;
+  image_info.fCurrentQueueFamily = context_state->vk_context_provider()
+                                       ->GetDeviceQueue()
+                                       ->GetVulkanQueueIndex();
+  image_info.fProtected = is_protected ? GrProtected::kYes : GrProtected::kNo;
+  image_info.fYcbcrConversionInfo = {};
+
+  return image_info;
+}
+
+using ScopedResetAndRestoreUnpackState =
+    SharedImageBackingGLCommon::ScopedResetAndRestoreUnpackState;
+
+using ScopedRestoreTexture = SharedImageBackingGLCommon::ScopedRestoreTexture;
+
+class AngleVulkanBacking : public ClearTrackingSharedImageBacking {
+ public:
+  AngleVulkanBacking(const raw_ptr<SharedContextState>& context_state,
+                     const Mailbox& mailbox,
+                     viz::ResourceFormat format,
+                     const gfx::Size& size,
+                     const gfx::ColorSpace& color_space,
+                     GrSurfaceOrigin surface_origin,
+                     SkAlphaType alpha_type,
+                     uint32_t usage)
+      : ClearTrackingSharedImageBacking(mailbox,
+                                        format,
+                                        size,
+                                        color_space,
+                                        surface_origin,
+                                        alpha_type,
+                                        usage,
+                                        EstimatedSize(format, size),
+                                        false /* is_thread_safe */),
+        context_state_(context_state) {}
+
+  ~AngleVulkanBacking() override {
+    if (passthrough_texture_ && !have_context())
+      passthrough_texture_->MarkContextLost();
+    passthrough_texture_.reset();
+  }
+
+  // SharedImageBacking implementation.
+  bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override {
+    NOTREACHED() << "Not supported.";
+    return false;
+  }
+
+  void Update(std::unique_ptr<gfx::GpuFence> in_fence) override {
+    NOTREACHED() << "Not supported.";
+  }
+
+  void OnMemoryDump(const std::string& dump_name,
+                    base::trace_event::MemoryAllocatorDump* dump,
+                    base::trace_event::ProcessMemoryDump* pmd,
+                    uint64_t client_tracing_id) override {}
+
+  void InitializeGLTexture() {
+    SharedImageBackingGLCommon::MakeTextureAndSetParameters(
+        GL_TEXTURE_2D, /*service_id=*/0, /*framebuffer_attachment_angle=*/true,
+        &passthrough_texture_, nullptr);
+    passthrough_texture_->SetEstimatedSize(estimated_size());
+  }
+  GLenum GetGLTarget() const { return GL_TEXTURE_2D; }
+  GLuint GetGLServiceId() const { return passthrough_texture_->service_id(); }
+
+ protected:
+  std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+  ProduceGLTexturePassthrough(SharedImageManager* manager,
+                              MemoryTypeTracker* tracker) override;
+  std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
+      SharedImageManager* manager,
+      MemoryTypeTracker* tracker,
+      scoped_refptr<SharedContextState> context_state) override;
+
+ private:
+  class SkiaRepresentation;
+
+  bool BeginAccess() {
+    if (!image_) {
+      auto image = base::MakeRefCounted<gl::GLImageEGLAngleVulkan>(size());
+      if (!image->Initialize(passthrough_texture_->service_id())) {
+        return false;
+      }
+      image_ = std::move(image);
+    }
+
+    // TODO(penghaung): use glReleaseTextures() to get image layout from ANGLE.
+
+    VkImageCreateInfo info;
+    VkImage vk_image = image_->ExportVkImage(&info);
+    // Check whether VkImage is re-created in ANGLE.
+    if (vk_image != vk_image_) {
+      vk_image_ = vk_image;
+      backend_texture_ = GrBackendTexture(
+          size().width(), size().height(),
+          CreateGrVkImageInfo(vk_image_, info, context_state_));
+    }
+    return true;
+  }
+
+  void EndAccess() {
+    // TODO(penghaung): use glAcquireTextures() to update image layout in
+    // ANGLE.
+  }
+
+  raw_ptr<SharedContextState> context_state_;
+  scoped_refptr<gl::GLImageEGLAngleVulkan> image_;
+  scoped_refptr<gles2::TexturePassthrough> passthrough_texture_;
+  GrBackendTexture backend_texture_{};
+  VkImage vk_image_ = VK_NULL_HANDLE;
+};  // namespace
+
+class AngleVulkanBacking::SkiaRepresentation
+    : public SharedImageRepresentationSkia {
+ public:
+  SkiaRepresentation(SharedImageManager* manager,
+                     AngleVulkanBacking* backing,
+                     MemoryTypeTracker* tracker)
+      : SharedImageRepresentationSkia(manager, backing, tracker) {}
+
+  ~SkiaRepresentation() override = default;
+
+  // SharedImageRepresentationSkia implementation.
+  sk_sp<SkPromiseImageTexture> BeginReadAccess(
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
+    if (!backing_impl()->BeginAccess())
+      return nullptr;
+    return SkPromiseImageTexture::Make(backing_impl()->backend_texture_);
+  }
+
+  void EndReadAccess() override { backing_impl()->EndAccess(); }
+
+  sk_sp<SkPromiseImageTexture> BeginWriteAccess(
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores,
+      std::unique_ptr<GrBackendSurfaceMutableState>* end_state) override {
+    // TODO(penghuang): support it for OOP-C.
+    NOTIMPLEMENTED();
+    return nullptr;
+  }
+  void EndWriteAccess(sk_sp<SkSurface> surface) override {}
+
+ private:
+  AngleVulkanBacking* backing_impl() const {
+    return static_cast<AngleVulkanBacking*>(backing());
+  }
+
+  sk_sp<SkPromiseImageTexture> BeginAccess(
+      bool readonly,
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores);
+
+  void EndAccess(bool readonly);
+  int surface_msaa_count_ = 0;
+};
+
+std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
+AngleVulkanBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
+                                                MemoryTypeTracker* tracker) {
+  DCHECK(passthrough_texture_);
+  return std::make_unique<SharedImageRepresentationGLTexturePassthroughImpl>(
+      manager, this, nullptr, tracker, passthrough_texture_);
+}
+
+std::unique_ptr<SharedImageRepresentationSkia> AngleVulkanBacking::ProduceSkia(
+    SharedImageManager* manager,
+    MemoryTypeTracker* tracker,
+    scoped_refptr<SharedContextState> context_state) {
+  DCHECK_EQ(context_state_, context_state.get());
+  return std::make_unique<SkiaRepresentation>(manager, this, tracker);
+}
+
+}  // namespace
+
+SharedImageBackingFactoryAngleVulkan::SharedImageBackingFactoryAngleVulkan(
+    const GpuPreferences& gpu_preferences,
+    const GpuDriverBugWorkarounds& workarounds,
+    const GpuFeatureInfo& gpu_feature_info,
+    SharedContextState* context_state)
+    : SharedImageBackingFactoryGLCommon(gpu_preferences,
+                                        workarounds,
+                                        gpu_feature_info,
+                                        context_state->progress_reporter()),
+      context_state_(context_state) {
+  DCHECK(gl::GLSurfaceEGL::IsANGLEVulkanImageClientBufferSupported());
+}
+
+SharedImageBackingFactoryAngleVulkan::~SharedImageBackingFactoryAngleVulkan() =
+    default;
+
+std::unique_ptr<SharedImageBacking>
+SharedImageBackingFactoryAngleVulkan::CreateSharedImage(
+    const Mailbox& mailbox,
+    viz::ResourceFormat format,
+    SurfaceHandle surface_handle,
+    const gfx::Size& size,
+    const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
+    uint32_t usage,
+    bool is_thread_safe) {
+  const FormatInfo& format_info = format_info_[format];
+  if (!CanCreateSharedImage(size, /*pixel_data=*/{}, format_info,
+                            GL_TEXTURE_2D)) {
+    return nullptr;
+  }
+
+  auto result = std::make_unique<AngleVulkanBacking>(
+      context_state_, mailbox, format, size, color_space, surface_origin,
+      alpha_type, usage);
+  result->InitializeGLTexture();
+
+  gl::GLApi* api = gl::g_current_gl_context;
+  auto target = result->GetGLTarget();
+  ScopedRestoreTexture scoped_restore(api, target);
+  api->glBindTextureFn(target, result->GetGLServiceId());
+
+  if (format_info.supports_storage) {
+    {
+      gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
+      api->glTexStorage2DEXTFn(target, 1, format_info.storage_internal_format,
+                               size.width(), size.height());
+    }
+
+  } else {
+    ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs_, false);
+    gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
+    api->glTexImage2DFn(target, 0, format_info.image_internal_format,
+                        size.width(), size.height(), 0,
+                        format_info.adjusted_format, format_info.gl_type,
+                        nullptr);
+  }
+
+  if (gl::g_current_gl_driver->ext.b_GL_KHR_debug) {
+    const std::string label =
+        "SharedImage_AngleVulkan" + CreateLabelForSharedImageUsage(usage);
+    api->glObjectLabelFn(GL_TEXTURE, result->GetGLServiceId(), -1,
+                         label.c_str());
+  }
+
+  return std::move(result);
+}
+
+std::unique_ptr<SharedImageBacking>
+SharedImageBackingFactoryAngleVulkan::CreateSharedImage(
+    const Mailbox& mailbox,
+    viz::ResourceFormat format,
+    const gfx::Size& size,
+    const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
+    uint32_t usage,
+    base::span<const uint8_t> data) {
+  NOTREACHED() << "Not supported";
+  return nullptr;
+}
+
+std::unique_ptr<SharedImageBacking>
+SharedImageBackingFactoryAngleVulkan::CreateSharedImage(
+    const Mailbox& mailbox,
+    int client_id,
+    gfx::GpuMemoryBufferHandle handle,
+    gfx::BufferFormat buffer_format,
+    gfx::BufferPlane plane,
+    SurfaceHandle surface_handle,
+    const gfx::Size& size,
+    const gfx::ColorSpace& color_space,
+    GrSurfaceOrigin surface_origin,
+    SkAlphaType alpha_type,
+    uint32_t usage) {
+  NOTREACHED() << "Not supported";
+  return nullptr;
+}
+
+bool SharedImageBackingFactoryAngleVulkan::CanUseAngleVulkanBacking(
+    uint32_t usage,
+    GrContextType gr_context_type) const {
+  // Ignore for mipmap usage.
+  usage &= ~SHARED_IMAGE_USAGE_MIPMAP;
+
+  constexpr auto kSupportedUsages =
+      SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
+      SHARED_IMAGE_USAGE_RASTER | SHARED_IMAGE_USAGE_DISPLAY |
+      SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
+
+  if (usage & ~kSupportedUsages)
+    return false;
+
+  // AngleVulkan backing is used for GL & Vulkan interop, so the usage must
+  // contain GLES2
+  return usage & SHARED_IMAGE_USAGE_GLES2;
+}
+
+bool SharedImageBackingFactoryAngleVulkan::IsSupported(
+    uint32_t usage,
+    viz::ResourceFormat format,
+    bool thread_safe,
+    gfx::GpuMemoryBufferType gmb_type,
+    GrContextType gr_context_type,
+    bool* allow_legacy_mailbox,
+    bool is_pixel_used) {
+  DCHECK_EQ(gr_context_type, GrContextType::kVulkan);
+  if (!CanUseAngleVulkanBacking(usage, gr_context_type)) {
+    return false;
+  }
+
+  if (is_pixel_used) {
+    return false;
+  }
+
+  if (gmb_type != gfx::EMPTY_BUFFER) {
+    return false;
+  }
+
+  *allow_legacy_mailbox = false;
+  return true;
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.h b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.h
new file mode 100644
index 0000000..e4f5f19
--- /dev/null
+++ b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.h
@@ -0,0 +1,76 @@
+// 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 GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_ANGLE_VULKAN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_ANGLE_VULKAN_H_
+
+#include <memory>
+
+#include "gpu/command_buffer/service/shared_image_backing_factory_gl_common.h"
+#include "gpu/gpu_gles2_export.h"
+
+namespace gpu {
+
+class SharedContextState;
+
+class GPU_GLES2_EXPORT SharedImageBackingFactoryAngleVulkan
+    : public SharedImageBackingFactoryGLCommon {
+ public:
+  SharedImageBackingFactoryAngleVulkan(
+      const GpuPreferences& gpu_preferences,
+      const GpuDriverBugWorkarounds& workarounds,
+      const GpuFeatureInfo& gpu_feature_info,
+      SharedContextState* context_state);
+  ~SharedImageBackingFactoryAngleVulkan() override;
+
+  // SharedImageBackingFactory implementation:
+  std::unique_ptr<SharedImageBacking> CreateSharedImage(
+      const Mailbox& mailbox,
+      viz::ResourceFormat format,
+      SurfaceHandle surface_handle,
+      const gfx::Size& size,
+      const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
+      uint32_t usage,
+      bool is_thread_safe) override;
+  std::unique_ptr<SharedImageBacking> CreateSharedImage(
+      const Mailbox& mailbox,
+      viz::ResourceFormat format,
+      const gfx::Size& size,
+      const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
+      uint32_t usage,
+      base::span<const uint8_t> pixel_data) override;
+  std::unique_ptr<SharedImageBacking> CreateSharedImage(
+      const Mailbox& mailbox,
+      int client_id,
+      gfx::GpuMemoryBufferHandle handle,
+      gfx::BufferFormat format,
+      gfx::BufferPlane plane,
+      SurfaceHandle surface_handle,
+      const gfx::Size& size,
+      const gfx::ColorSpace& color_space,
+      GrSurfaceOrigin surface_origin,
+      SkAlphaType alpha_type,
+      uint32_t usage) override;
+  bool IsSupported(uint32_t usage,
+                   viz::ResourceFormat format,
+                   bool thread_safe,
+                   gfx::GpuMemoryBufferType gmb_type,
+                   GrContextType gr_context_type,
+                   bool* allow_legacy_mailbox,
+                   bool is_pixel_used) override;
+
+ private:
+  bool CanUseAngleVulkanBacking(uint32_t usage,
+                                GrContextType gr_context_type) const;
+
+  raw_ptr<SharedContextState> context_state_;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_ANGLE_VULKAN_H_
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index e99f3f6..0a4bf25 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -31,6 +31,7 @@
 #include "gpu/config/gpu_preferences.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_switches.h"
 #include "ui/gl/trace_util.h"
 
 #if defined(OS_LINUX) && defined(USE_OZONE) && BUILDFLAG(ENABLE_VULKAN)
@@ -40,6 +41,7 @@
 #if (defined(OS_LINUX) || defined(OS_FUCHSIA) || defined(OS_WIN)) && \
     BUILDFLAG(ENABLE_VULKAN)
 #include "gpu/command_buffer/service/external_vk_image_factory.h"
+#include "gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.h"
 #elif defined(OS_ANDROID) && BUILDFLAG(ENABLE_VULKAN)
 #include "gpu/command_buffer/service/external_vk_image_factory.h"
 #include "gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h"
@@ -174,7 +176,11 @@
 #if defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
     !BUILDFLAG(IS_CHROMEOS_LACROS) && !BUILDFLAG(IS_CHROMECAST)
     // Desktop Linux, not ChromeOS.
-    if (ShouldUseExternalVulkanImageFactory()) {
+    if (base::FeatureList::IsEnabled(features::kVulkanFromANGLE)) {
+      auto factory = std::make_unique<SharedImageBackingFactoryAngleVulkan>(
+          gpu_preferences, workarounds, gpu_feature_info, context_state);
+      factories_.push_back(std::move(factory));
+    } else if (ShouldUseExternalVulkanImageFactory()) {
       auto external_vk_image_factory =
           std::make_unique<ExternalVkImageFactory>(context_state);
       factories_.push_back(std::move(external_vk_image_factory));
diff --git "a/infra/config/generated/builders/ci/Win x64 Builder \050reclient compare\051/properties.textpb" "b/infra/config/generated/builders/ci/Win x64 Builder \050reclient compare\051/properties.textpb"
index dc74b7db..a0c5439d 100644
--- "a/infra/config/generated/builders/ci/Win x64 Builder \050reclient compare\051/properties.textpb"
+++ "b/infra/config/generated/builders/ci/Win x64 Builder \050reclient compare\051/properties.textpb"
@@ -23,7 +23,8 @@
               "legacy_gclient_config": {
                 "apply_configs": [
                   "use_clang_coverage",
-                  "enable_reclient"
+                  "enable_reclient",
+                  "reclient_test"
                 ],
                 "config": "chromium"
               }
diff --git a/infra/config/generated/builders/try/android-marshmallow-arm64-rel-compilator/properties.textpb b/infra/config/generated/builders/try/android-marshmallow-arm64-rel-compilator/properties.textpb
new file mode 100644
index 0000000..08e81d1
--- /dev/null
+++ b/infra/config/generated/builders/try/android-marshmallow-arm64-rel-compilator/properties.textpb
@@ -0,0 +1,29 @@
+{
+  "$build/code_coverage": {
+    "coverage_test_types": [
+      "unit",
+      "overall"
+    ],
+    "use_java_coverage": true
+  },
+  "$build/goma": {
+    "enable_ats": true,
+    "jobs": 300,
+    "rpc_extra_params": "?prod",
+    "server_host": "goma.chromium.org",
+    "use_luci_auth": true
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.android",
+  "orchestrator": {
+    "builder_group": "tryserver.chromium.android",
+    "builder_name": "android-marshmallow-arm64-rel"
+  },
+  "recipe": "chromium/compilator"
+}
\ No newline at end of file
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 0a3767c..c2420dd 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -346,6 +346,10 @@
         location_regexp_exclude: ".+/[+]/infra/config/.+"
       }
       builders {
+        name: "chromium/try/android-marshmallow-arm64-rel-compilator"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/android-marshmallow-arm64-rel-rts"
         experiment_percentage: 5
         location_regexp: ".*"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 97964c5a..4fc74c8 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -52562,6 +52562,109 @@
       }
     }
     builders {
+      name: "android-marshmallow-arm64-rel-compilator"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builder:android-marshmallow-arm64-rel-compilator"
+      dimensions: "cores:64"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:1"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/code_coverage": {'
+        '    "coverage_test_types": ['
+        '      "unit",'
+        '      "overall"'
+        '    ],'
+        '    "use_java_coverage": true'
+        '  },'
+        '  "$build/goma": {'
+        '    "enable_ats": true,'
+        '    "jobs": 300,'
+        '    "rpc_extra_params": "?prod",'
+        '    "server_host": "goma.chromium.org",'
+        '    "use_luci_auth": true'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "tryserver.chromium.android",'
+        '  "orchestrator": {'
+        '    "builder_group": "tryserver.chromium.android",'
+        '    "builder_name": "android-marshmallow-arm64-rel"'
+        '  },'
+        '  "recipe": "chromium/compilator"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium.chromium_tests.use_rdb_results"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 1
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "android-marshmallow-arm64-rel-rts"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:android-marshmallow-arm64-rel-rts"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index d1a9fba..70f123b 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -14248,6 +14248,9 @@
     name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel-compilator"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel-rts"
   }
   builders {
@@ -15368,6 +15371,9 @@
     name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel-compilator"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-marshmallow-arm64-rel-rts"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 447ff93..3ba0d63 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -4232,7 +4232,7 @@
         ),
         gclient_config = builder_config.gclient_config(
             config = "chromium",
-            apply_configs = ["use_clang_coverage", "enable_reclient"],
+            apply_configs = ["use_clang_coverage", "enable_reclient", "reclient_test"],
         ),
     ),
     console_view_entry = consoles.console_view_entry(
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index efffbd3..f583692 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -428,6 +428,23 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-marshmallow-arm64-rel-compilator",
+    builderless = False,
+    cores = 64,
+    goma_jobs = goma.jobs.J300,
+    ssd = True,
+    use_java_coverage = True,
+    coverage_test_types = ["unit", "overall"],
+    properties = {
+        "orchestrator": {
+            "builder_group": "tryserver.chromium.android",
+            "builder_name": "android-marshmallow-arm64-rel",
+        },
+    },
+    executable = "recipe:chromium/compilator",
+)
+
+try_.chromium_android_builder(
     name = "android-marshmallow-arm64-rel-rts",
     builderless = not settings.is_main,
     cores = 32 if settings.is_main else 16,
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index 9efb503..ff0c3ed 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -281,7 +281,8 @@
       'build': The Xcode build version.
   """
   try:
-    out = subprocess.check_output(['xcodebuild', '-version']).splitlines()
+    out = subprocess.check_output(['xcodebuild',
+                                   '-version']).decode('utf-8').splitlines()
     version, build_version = out[0].split(' ')[-1], out[1].split(' ')[-1]
     path = subprocess.check_output(['xcode-select',
                                     '--print-path']).decode('utf-8').rstrip()
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
index 449e2e97..caf34e3 100644
--- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -470,7 +470,10 @@
       filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(
                                                    id object,
                                                    NSDictionary* bindings) {
-        // All destinations are displayed in regular mode.
+        if (object == self.siteInfoDestination) {
+          return [self currentWebPageSupportsSiteInfo];
+        }
+        // All other destinations are displayed in regular mode.
         if (!self.isIncognito) {
           return true;
         }
diff --git a/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h b/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h
index 0c386630..c05cb2a 100644
--- a/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h
+++ b/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h
@@ -19,9 +19,9 @@
 // enable or disable web usage for all the WebStates in a WebStateList.
 class WebUsageEnablerBrowserAgent
     : public BrowserUserData<WebUsageEnablerBrowserAgent>,
-      BrowserObserver,
-      web::WebStateObserver,
-      WebStateListObserver {
+      public BrowserObserver,
+      public web::WebStateObserver,
+      public WebStateListObserver {
  public:
   // Not copyable or moveable
   WebUsageEnablerBrowserAgent(const WebUsageEnablerBrowserAgent&) = delete;
diff --git a/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.mm b/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.mm
index cd4e76b..6d8e2738 100644
--- a/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.mm
+++ b/ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.mm
@@ -63,6 +63,8 @@
     web_state->SetWebUsageEnabled(web_usage_enabled_);
     if (web_usage_enabled_ && triggers_initial_load)
       web_state->GetNavigationManager()->LoadIfNecessary();
+  } else {
+    web_state_observations_.AddObservation(web_state);
   }
 }
 
@@ -77,7 +79,6 @@
     web::WebState* web_state,
     int index,
     bool activating) {
-  web_state_observations_.AddObservation(web_state);
   UpdateWebUsageForAddedWebState(web_state, triggers_initial_load_);
 }
 
@@ -86,8 +87,10 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int index) {
-  web_state_observations_.RemoveObservation(old_web_state);
-  web_state_observations_.AddObservation(new_web_state);
+  if (web_state_observations_.IsObservingSource(old_web_state)) {
+    web_state_observations_.RemoveObservation(old_web_state);
+  }
+
   UpdateWebUsageForAddedWebState(new_web_state, triggers_initial_load_);
 }
 
@@ -95,11 +98,14 @@
     WebStateList* web_state_list,
     web::WebState* web_state,
     int index) {
-  web_state_observations_.RemoveObservation(web_state);
+  if (web_state_observations_.IsObservingSource(web_state)) {
+    web_state_observations_.RemoveObservation(web_state);
+  }
 }
 
 void WebUsageEnablerBrowserAgent::WebStateRealized(web::WebState* web_state) {
   UpdateWebUsageForAddedWebState(web_state, triggers_initial_load_);
+  web_state_observations_.RemoveObservation(web_state);
 }
 
 void WebUsageEnablerBrowserAgent::WebStateDestroyed(web::WebState* web_state) {
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 3486699..500b1208 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d38d55e8b5ebe72d7b6e64d910e30682ab150cb7
\ No newline at end of file
+f1f225c579a6f730ec8c2ce83fa2ca1872ac85b7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 959d880ba..9113c3dc3 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-f90731a466ec4b24e092b64149881d575caeb5e0
\ No newline at end of file
+aeada587d7d0b8bf295b8eb9e78eeb73d36b9e36
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index cfb0bb1f..7e2db9c 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3ef43cae87df515fa3da5c17cd0a6a8c011fffa3
\ No newline at end of file
+7ab24b952a4852bcda9d3d64a773db024d60e0b5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index d448859..f90f764 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-570cf0beb17bc7b34c0594968a59dcef6070d3f2
\ No newline at end of file
+15cff84dbebc587dc60ae39d35142f03f4344036
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index 2c25ed8..c38363d 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-8f9470678c8398ba41d78013265fdaf19de2f879
\ No newline at end of file
+8deaca4b1a3f155359e6fe5f4f7b2d5b0e2c23fc
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 73225e34..90785e2b 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fb5fb40a0738c0b019c1ac4c1fffdce9a1402de2
\ No newline at end of file
+13e21c99ee7169d63f17c9f2187c317abdee8bf9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 5e5247db..ecf2fd1 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-2820be47a753620dd6e52356a275c45c75f4359a
\ No newline at end of file
+608c85daa07459d1a45dac03c4a203b459a2fb2d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index d5652a6..6be0547 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b1d6475ceefa6507e0db7e471061d8baf1504ffb
\ No newline at end of file
+1cad47898ee3c41f80872218067f08d2cb24d6e2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index f2206f6..73d91b90 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-922566b30572eb040cbf424d829e955b91794069
\ No newline at end of file
+c31be3f5af6d12009758f28ed02b6cdbfb14381d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index f828d6d..5a3e80c 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-935c9882e2203be77678ea27f5a5a570cdca684e
\ No newline at end of file
+7d40dc47217c8883b9110da84c9a715bcc225046
\ No newline at end of file
diff --git a/media/audio/mac/coreaudio_dispatch_override.cc b/media/audio/mac/coreaudio_dispatch_override.cc
index 57a700e..e5204f5 100644
--- a/media/audio/mac/coreaudio_dispatch_override.cc
+++ b/media/audio/mac/coreaudio_dispatch_override.cc
@@ -149,6 +149,10 @@
 }  // namespace
 
 bool InitializeCoreAudioDispatchOverride() {
+  // Apple reports this issue is fixed in 11+.
+  if (base::mac::IsAtLeastOS11())
+    return true;
+
   if (g_dispatch_override_installed)
     return true;
 
diff --git a/mojo/public/java/system/BUILD.gn b/mojo/public/java/system/BUILD.gn
index db12c20..8eafeae2 100644
--- a/mojo/public/java/system/BUILD.gn
+++ b/mojo/public/java/system/BUILD.gn
@@ -157,6 +157,9 @@
 }
 
 instrumentation_test_apk("mojo_test_apk") {
+  apk_name = "MojoTest"
+  android_manifest = "javatests/AndroidManifest.xml"
+  use_vpython3 = false
   deps = [
     ":mojo_javatests",
     ":system_impl_java",
@@ -167,6 +170,4 @@
     "//third_party/androidx:androidx_test_runner_java",
   ]
   shared_libraries = [ ":mojo_java_unittests" ]
-  apk_name = "MojoTest"
-  android_manifest = "javatests/AndroidManifest.xml"
 }
diff --git a/mojo/public/tools/mojom/mojom_parser.py b/mojo/public/tools/mojom/mojom_parser.py
index 74beb077..6a4770a 100755
--- a/mojo/public/tools/mojom/mojom_parser.py
+++ b/mojo/public/tools/mojom/mojom_parser.py
@@ -486,10 +486,10 @@
   _ParseMojoms(mojom_files, input_roots, output_root, module_roots,
                args.enabled_features, module_metadata, allowed_imports)
   logging.info('Finished')
-  # Exit without running GC, which can save multiple seconds due the large
-  # number of object created.
-  os._exit(0)
 
 
 if __name__ == '__main__':
   Run(sys.argv[1:])
+  # Exit without running GC, which can save multiple seconds due to the large
+  # number of object created.
+  os._exit(0)
diff --git a/net/tools/cert_verify_tool/cert_verify_tool.cc b/net/tools/cert_verify_tool/cert_verify_tool.cc
index 5381177..f0dafef6 100644
--- a/net/tools/cert_verify_tool/cert_verify_tool.cc
+++ b/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -255,6 +255,15 @@
   std::cout << "\n";
 }
 
+void PrintAdditionalRoots(const std::vector<CertInput>& root_der_certs) {
+  std::cout << "Additional roots:\n";
+  for (const auto& cert : root_der_certs) {
+    PrintCertHashAndSubject(
+        net::x509_util::CreateCryptoBuffer(cert.der_cert).get());
+  }
+  std::cout << "\n";
+}
+
 const char kUsage[] =
     " [flags] <target/chain>\n"
     "\n"
@@ -426,6 +435,8 @@
   }
 
   PrintInputChain(target_der_cert, intermediate_der_certs);
+  if (!root_der_certs.empty())
+    PrintAdditionalRoots(root_der_certs);
 
   // Create a network thread to be used for AIA fetches, and wait for a
   // CertNetFetcher to be constructed on that thread.
diff --git a/net/tools/cert_verify_tool/cert_verify_tool_util.cc b/net/tools/cert_verify_tool/cert_verify_tool_util.cc
index a2e1608..dcecc9a 100644
--- a/net/tools/cert_verify_tool/cert_verify_tool_util.cc
+++ b/net/tools/cert_verify_tool/cert_verify_tool_util.cc
@@ -35,7 +35,6 @@
 void ExtractCertificatesFromData(const std::string& data_string,
                                  const base::FilePath& file_path,
                                  std::vector<CertInput>* certs) {
-  // TODO(mattm): support PKCS #7 (.p7b) files.
   net::PEMTokenizer pem_tokenizer(data_string, {kCertificateHeader});
   int block = 0;
   while (pem_tokenizer.GetNext()) {
@@ -52,6 +51,22 @@
   if (block)
     return;
 
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> pkcs7_cert_buffers;
+  if (net::x509_util::CreateCertBuffersFromPKCS7Bytes(
+          base::as_bytes(base::make_span(data_string)), &pkcs7_cert_buffers)) {
+    int n = 0;
+    for (const auto& cert_buffer : pkcs7_cert_buffers) {
+      CertInput cert;
+      cert.der_cert = std::string(
+          net::x509_util::CryptoBufferAsStringPiece(cert_buffer.get()));
+      cert.source_file_path = file_path;
+      cert.source_details = base::StringPrintf("PKCS #7 cert %i", n);
+      certs->push_back(cert);
+      ++n;
+    }
+    return;
+  }
+
   // Otherwise, assume it is a single DER cert.
   CertInput cert;
   cert.der_cert = data_string;
@@ -196,4 +211,4 @@
   if (!cert)
     return std::string();
   return SubjectFromX509Certificate(cert.get());
-}
\ No newline at end of file
+}
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ec7a79d..81e42c5 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1062,137 +1062,65 @@
             ],
             "experiments": [
                 {
-                    "name": "CombinedDevCanary_2021_11_05",
-                    "enable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "BetaAndStableFeatures_2021-11-05",
-                    "enable_features": [
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers"
-                    ]
-                },
-                {
-                    "name": "Control_2021-11-05",
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "AutofillEnableProfileDeduplication_2021-11-05",
-                    "enable_features": [
-                        "AutofillEnableProfileDeduplication"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "AutofillEnableSupportForParsingWithSharedLabels_2021-11-05",
-                    "enable_features": [
-                        "AutofillEnableSupportForParsingWithSharedLabels"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "AutofillRetrieveOverallPredictionsFromCache_2021-11-05",
-                    "enable_features": [
-                        "AutofillRetrieveOverallPredictionsFromCache"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "AutofillLabelAffixRemoval_2021-11-05",
-                    "enable_features": [
-                        "AutofillLabelAffixRemoval"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillShadowDOM",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "AutofillShadowDOM_2021-11-05",
-                    "enable_features": [
-                        "AutofillShadowDOM"
-                    ],
-                    "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
-                        "AutofillEnableProfileDeduplication",
-                        "AutofillEnableSupportForParsingWithSharedLabels",
-                        "AutofillLabelAffixRemoval",
-                        "AutofillRetrieveOverallPredictionsFromCache",
-                        "AutofillUseAlternativeStateNameMap"
-                    ]
-                },
-                {
-                    "name": "StableFeatures_2021-11-05",
+                    "name": "AutofillUseAlternativeStateNameMap_2021-08-10",
                     "enable_features": [
                         "AutofillUseAlternativeStateNameMap"
                     ],
                     "disable_features": [
-                        "AutofillEnableDependentLocalityParsing",
-                        "AutofillEnableImportWhenMultiplePhoneNumbers",
                         "AutofillEnableProfileDeduplication",
                         "AutofillEnableSupportForParsingWithSharedLabels",
                         "AutofillLabelAffixRemoval",
                         "AutofillRetrieveOverallPredictionsFromCache",
                         "AutofillShadowDOM"
                     ]
+                },
+                {
+                    "name": "AutofillShadowDOM_2021-08-10",
+                    "enable_features": [
+                        "AutofillShadowDOM"
+                    ],
+                    "disable_features": [
+                        "AutofillEnableProfileDeduplication",
+                        "AutofillEnableSupportForParsingWithSharedLabels",
+                        "AutofillLabelAffixRemoval",
+                        "AutofillRetrieveOverallPredictionsFromCache",
+                        "AutofillUseAlternativeStateNameMap"
+                    ]
+                },
+                {
+                    "name": "StableFeatures_2021-08-10",
+                    "enable_features": [
+                        "AutofillUseAlternativeStateNameMap"
+                    ],
+                    "disable_features": [
+                        "AutofillEnableProfileDeduplication",
+                        "AutofillEnableSupportForParsingWithSharedLabels",
+                        "AutofillLabelAffixRemoval",
+                        "AutofillRetrieveOverallPredictionsFromCache",
+                        "AutofillShadowDOM"
+                    ]
+                }
+            ]
+        }
+    ],
+    "AutofillDisplaceRemovedForms": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillDisplaceRemovedForms"
+                    ]
                 }
             ]
         }
diff --git a/third_party/blink/API_OWNERS b/third_party/blink/API_OWNERS
index ca1730a..f3ac21c6 100644
--- a/third_party/blink/API_OWNERS
+++ b/third_party/blink/API_OWNERS
@@ -11,3 +11,4 @@
 slightlyoff@chromium.org
 tkent@chromium.org
 yoavweiss@chromium.org
+miketaylr@chromium.org
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index c1b83a9..5e595eb4 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -145,7 +145,7 @@
 
 // Enable `sec-ch-ua-full-version-list` client hint.
 const base::Feature kUserAgentClientHintFullVersionList{
-    "UserAgentClientHintFullVersionList", base::FEATURE_DISABLED_BY_DEFAULT};
+    "UserAgentClientHintFullVersionList", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Handle prefers-color-scheme user preference media feature via client hints.
 const base::Feature kPrefersColorSchemeClientHintHeader{
diff --git a/third_party/blink/renderer/bindings/core/v8/script_function.h b/third_party/blink/renderer/bindings/core/v8/script_function.h
index a1b6f75..8c07471 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_function.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_function.h
@@ -98,7 +98,7 @@
     virtual void CallRaw(ScriptState*,
                          const v8::FunctionCallbackInfo<v8::Value>&);
 
-    // The length of the aosociated JavaScript function. Implement this only
+    // The length of the associated JavaScript function. Implement this only
     // when the function is exposed to scripts.
     virtual int Length() const { return 0; }
 
diff --git a/third_party/blink/renderer/core/animation/animation_utils_test.cc b/third_party/blink/renderer/core/animation/animation_utils_test.cc
index d4212b0..9be2610 100644
--- a/third_party/blink/renderer/core/animation/animation_utils_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_utils_test.cc
@@ -122,10 +122,10 @@
   SetBodyInnerHTML(R"HTML(
     <style>
       #container { container-type: inline-size; }
-      @container (min-width: 1px) {
+      @container size(min-width: 1px) {
         #target { left: 10px; }
       }
-      @container (min-width: 99999px) {
+      @container size(min-width: 99999px) {
         #target { left: 10000px; }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
index 745b60d..25871dd 100644
--- a/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
+++ b/third_party/blink/renderer/core/css/container_query_evaluator_test.cc
@@ -59,7 +59,7 @@
 
 TEST_F(ContainerQueryEvaluatorTest, ContainmentMatch) {
   {
-    String query = "(min-width: 100px)";
+    String query = "size(min-width: 100px)";
     EXPECT_TRUE(Eval(query, 100.0, 100.0, horizontal));
     EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
     EXPECT_FALSE(Eval(query, 100.0, 100.0, vertical));
@@ -68,7 +68,7 @@
   }
 
   {
-    String query = "(min-height: 100px)";
+    String query = "size(min-height: 100px)";
     EXPECT_TRUE(Eval(query, 100.0, 100.0, vertical));
     EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
     EXPECT_FALSE(Eval(query, 100.0, 100.0, horizontal));
@@ -77,7 +77,7 @@
   }
 
   {
-    String query = "(min-width: 100px) and (min-height: 100px)";
+    String query = "size((min-width: 100px) and (min-height: 100px))";
     EXPECT_TRUE(Eval(query, 100.0, 100.0, both));
     EXPECT_FALSE(Eval(query, 100.0, 100.0, vertical));
     EXPECT_FALSE(Eval(query, 100.0, 100.0, horizontal));
@@ -91,8 +91,10 @@
   PhysicalSize size_100(LayoutUnit(100), LayoutUnit(100));
   PhysicalSize size_200(LayoutUnit(200), LayoutUnit(200));
 
-  ContainerQuery* container_query_100 = ParseContainer("(min-width: 100px)");
-  ContainerQuery* container_query_200 = ParseContainer("(min-width: 200px)");
+  ContainerQuery* container_query_100 =
+      ParseContainer("size(min-width: 100px)");
+  ContainerQuery* container_query_200 =
+      ParseContainer("size(min-width: 200px)");
   ASSERT_TRUE(container_query_100);
   ASSERT_TRUE(container_query_200);
 
@@ -131,7 +133,7 @@
         width: 500px;
         height: 500px;
       }
-      @container (min-width: 500px) {
+      @container size(min-width: 500px) {
         div { z-index:1; }
       }
     </style>
@@ -188,8 +190,8 @@
   PhysicalSize size_300(LayoutUnit(300), LayoutUnit(300));
   PhysicalSize size_400(LayoutUnit(400), LayoutUnit(400));
 
-  ContainerQuery* query_min_200px = ParseContainer("(min-width: 200px)");
-  ContainerQuery* query_max_300px = ParseContainer("(max-width: 300px)");
+  ContainerQuery* query_min_200px = ParseContainer("size(min-width: 200px)");
+  ContainerQuery* query_max_300px = ParseContainer("size(max-width: 300px)");
   ASSERT_TRUE(query_min_200px);
 
   auto* evaluator = MakeGarbageCollected<ContainerQueryEvaluator>();
@@ -233,7 +235,7 @@
       main.none {
         display: none;
       }
-      @container (min-width: 500px) {
+      @container size(min-width: 500px) {
         div { --x:test; }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/container_query_test.cc b/third_party/blink/renderer/core/css/container_query_test.cc
index cb7c293..9503376 100644
--- a/third_party/blink/renderer/core/css/container_query_test.cc
+++ b/third_party/blink/renderer/core/css/container_query_test.cc
@@ -101,35 +101,40 @@
 
 TEST_F(ContainerQueryTest, PreludeParsing) {
   // Valid:
-  EXPECT_EQ(
-      "(min-width: 300px)",
-      SerializeCondition(ParseAtContainer("@container (min-width: 300px) {}")));
-  EXPECT_EQ(
-      "(max-width: 500px)",
-      SerializeCondition(ParseAtContainer("@container (max-width: 500px) {}")));
-  EXPECT_EQ("(not (max-width: 500px))",
+  EXPECT_EQ("size(min-width: 300px)",
             SerializeCondition(
-                ParseAtContainer("@container (not (max-width: 500px)) {}")));
-  EXPECT_EQ("(max-width: 500px) and (max-height: 500px)",
+                ParseAtContainer("@container size(min-width: 300px) {}")));
+  EXPECT_EQ("size(max-width: 500px)",
+            SerializeCondition(
+                ParseAtContainer("@container size(max-width: 500px) {}")));
+  EXPECT_EQ("(not size(max-width: 500px))",
             SerializeCondition(ParseAtContainer(
-                "@container (max-width: 500px) and (max-height: 500px) {}")));
-  EXPECT_EQ("(max-width: 500px) or (max-height: 500px)",
-            SerializeCondition(ParseAtContainer(
-                "@container (max-width: 500px) or (max-height: 500px) {}")));
+                "@container (not size(max-width: 500px)) {}")));
   EXPECT_EQ(
-      "(width < 300px)",
-      SerializeCondition(ParseAtContainer("@container (width < 300px) {}")));
+      "(size(max-width: 500px) and size(max-height: 500px))",
+      SerializeCondition(ParseAtContainer("@container (size(max-width: 500px) "
+                                          "and size(max-height: 500px)) {}")));
+  EXPECT_EQ(
+      "(size(max-width: 500px) or size(max-height: 500px))",
+      SerializeCondition(ParseAtContainer("@container (size(max-width: 500px) "
+                                          "or size(max-height: 500px)) {}")));
+  EXPECT_EQ("size(width < 300px)", SerializeCondition(ParseAtContainer(
+                                       "@container size(width < 300px) {}")));
 
   // Invalid:
   EXPECT_FALSE(ParseAtContainer("@container 100px {}"));
   EXPECT_FALSE(ParseAtContainer("@container calc(1) {}"));
   EXPECT_FALSE(ParseAtContainer("@container {}"));
-  EXPECT_FALSE(ParseAtContainer("@container (min-width: 300px) nonsense {}"));
+  EXPECT_FALSE(
+      ParseAtContainer("@container size(min-width: 300px) nonsense {}"));
+  EXPECT_FALSE(ParseAtContainer("@container somename not size(width) {}"));
+  EXPECT_FALSE(ParseAtContainer("@container size(width) and size(height) {}"));
+  EXPECT_FALSE(ParseAtContainer("@container size(width) or size(height) {}"));
 }
 
 TEST_F(ContainerQueryTest, RuleParsing) {
   StyleRuleContainer* container = ParseAtContainer(R"CSS(
-    @container (min-width: 100px) {
+    @container size(min-width: 100px) {
       div { width: 100px; }
       span { height: 100px; }
     }
@@ -153,7 +158,7 @@
 
 TEST_F(ContainerQueryTest, RuleCopy) {
   StyleRuleContainer* container = ParseAtContainer(R"CSS(
-    @container (min-width: 100px) {
+    @container size(min-width: 100px) {
       div { width: 100px; }
     }
   )CSS");
@@ -196,11 +201,11 @@
 
       div { z-index:1; }
       /* Should apply: */
-      @container (min-width: 500px) {
+      @container size(min-width: 500px) {
         div { z-index:2; }
       }
       /* Should initially not apply: */
-      @container (min-width: 600px) {
+      @container size(min-width: 600px) {
         div { z-index:3; }
       }
     </style>
@@ -230,16 +235,16 @@
   auto both = PhysicalAxes(kPhysicalAxisBoth);
   auto none = PhysicalAxes(kPhysicalAxisNone);
 
-  EXPECT_EQ(horizontal, QueriedAxes("(min-width: 1px)"));
-  EXPECT_EQ(horizontal, QueriedAxes("(max-width: 1px)"));
-  EXPECT_EQ(horizontal, QueriedAxes("(width: 1px)"));
+  EXPECT_EQ(horizontal, QueriedAxes("size(min-width: 1px)"));
+  EXPECT_EQ(horizontal, QueriedAxes("size(max-width: 1px)"));
+  EXPECT_EQ(horizontal, QueriedAxes("size(width: 1px)"));
 
-  EXPECT_EQ(vertical, QueriedAxes("(min-height: 1px)"));
-  EXPECT_EQ(vertical, QueriedAxes("(max-height: 1px)"));
-  EXPECT_EQ(vertical, QueriedAxes("(height: 1px)"));
+  EXPECT_EQ(vertical, QueriedAxes("size(min-height: 1px)"));
+  EXPECT_EQ(vertical, QueriedAxes("size(max-height: 1px)"));
+  EXPECT_EQ(vertical, QueriedAxes("size(height: 1px)"));
 
-  EXPECT_EQ(both, QueriedAxes("(width: 1px) and (height: 1px)"));
-  EXPECT_EQ(both, QueriedAxes("(min-width: 1px) and (max-height: 1px)"));
+  EXPECT_EQ(both, QueriedAxes("size((width: 1px) and (height: 1px))"));
+  EXPECT_EQ(both, QueriedAxes("size((min-width: 1px) and (max-height: 1px))"));
 
   // TODO(crbug.com/1145970): We want to test the case where no axes are
   // queried (kPhysicalAxisNone). This can (for now) be achieved by using
@@ -247,7 +252,7 @@
   // "resolution" will not be allowed in @container: we will then need to find
   // another way to author a container query that queries no axes (or make it
   // illegal altogether).
-  EXPECT_EQ(none, QueriedAxes("(resolution: 150dpi)"));
+  EXPECT_EQ(none, QueriedAxes("size(resolution: 150dpi)"));
 }
 
 TEST_F(ContainerQueryTest, QueryZoom) {
@@ -265,16 +270,16 @@
         height: 400px;
         container-type: size;
       }
-      @container (width: 100px) {
+      @container size(width: 100px) {
         div { --w100:1; }
       }
-      @container (width: 200px) {
+      @container size(width: 200px) {
         div { --w200:1; }
       }
-      @container (height: 200px) {
+      @container size(height: 200px) {
         div { --h200:1; }
       }
-      @container (height: 400px) {
+      @container size(height: 400px) {
         div { --h400:1; }
       }
     </style>
@@ -322,13 +327,13 @@
         width: 10ch;
         container-type: inline-size;
       }
-      @container (width: 10em) {
+      @container size(width: 10em) {
         #em-target { --em:1; }
       }
-      @container (width: 10ex) {
+      @container size(width: 10ex) {
         #ex-target { --ex:1; }
       }
-      @container (width: 10ch) {
+      @container size(width: 10ch) {
         #ch-target { --ch:1; }
       }
     </style>
@@ -456,13 +461,13 @@
         height: 10px;
         transition: height steps(2, start) 100s;
       }
-      @container (width: 120px) {
+      @container size(width: 120px) {
         #target { height: 20px; }
       }
-      @container (width: 130px) {
+      @container size(width: 130px) {
         #target { height: 30px; }
       }
-      @container (width: 140px) {
+      @container size(width: 140px) {
         #target { height: 40px; }
       }
     </style>
@@ -526,13 +531,13 @@
       #target {
         height: 10px;
       }
-      @container (width: 120px) {
+      @container size(width: 120px) {
         #target { height: 20px; }
       }
-      @container (width: 130px) {
+      @container size(width: 130px) {
         #target { height: 30px; }
       }
-      @container (width: 140px) {
+      @container size(width: 140px) {
         #target {
           height: 40px;
           transition: height steps(2, start) 100s;
@@ -599,16 +604,16 @@
       #target {
         height: 10px;
       }
-      @container (width: 120px) {
+      @container size(width: 120px) {
         #target { height: 20px; }
       }
-      @container (width: 130px) {
+      @container size(width: 130px) {
         #target {
           height: 90px;
           transition: height steps(2, start) 100s;
         }
       }
-      @container (width: 140px) {
+      @container size(width: 140px) {
         #target { height: 40px; }
       }
     </style>
@@ -670,17 +675,17 @@
         container: inline-size;
         width: 10px;
       }
-      @container (width: 120px) {
+      @container size(width: 120px) {
         #target {
           animation: anim 10s -2s linear paused;
         }
       }
-      @container (width: 130px) {
+      @container size(width: 130px) {
         #target {
           animation: anim 10s -3s linear paused;
         }
       }
-      @container (width: 140px) {
+      @container size(width: 140px) {
         #target {
           animation: anim 10s -4s linear paused;
         }
@@ -749,7 +754,7 @@
       #target {
         animation: anim 10s -2s linear paused;
       }
-      @container (width: 130px) {
+      @container size(width: 130px) {
         #target {
           animation: unset;
         }
@@ -848,7 +853,7 @@
         container-type: inline-size;
         width: 100px;
       }
-      @container (width: 100px) {
+      @container size(width: 100px) {
         #target {
           color: green;
         }
@@ -867,7 +872,7 @@
         container-type: inline-size;
         width: 100px;
       }
-      @container (width: 200px) {
+      @container size(width: 200px) {
         #target {
           color: green;
         }
@@ -905,7 +910,7 @@
         width: 100px;
         container-type: inline-size;
       }
-      @container (width: 100px) {
+      @container size(width: 100px) {
         #target {
           animation: anim 1s linear;
         }
@@ -924,7 +929,7 @@
         width: 100px;
         container-type: inline-size;
       }
-      @container (width: 200px) {
+      @container size(width: 200px) {
         #target {
           animation: anim 1s linear;
         }
@@ -971,7 +976,7 @@
     StringBuilder builder;
     builder.Append("<style>");
     builder.Append("#container { container-type: inline-size; }");
-    builder.Append("@container (width: 100px) {");
+    builder.Append("@container size(width: 100px) {");
     builder.Append("  #target {");
     builder.Append(String::Format(
         "%s:unset;", property.GetPropertyNameString().Utf8().c_str()));
@@ -1002,7 +1007,7 @@
   SetBodyInnerHTML(R"HTML(
     <style>
       #container { container-type: inline-size }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         .locked { content-visibility: hidden }
       }
     </style>
@@ -1042,7 +1047,7 @@
       #container {
         container-type: size;
       }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         span { color: pink; }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/css_selector_watch_test.cc b/third_party/blink/renderer/core/css/css_selector_watch_test.cc
index fdeba84..d53fb8a 100644
--- a/third_party/blink/renderer/core/css/css_selector_watch_test.cc
+++ b/third_party/blink/renderer/core/css/css_selector_watch_test.cc
@@ -99,7 +99,7 @@
         container-type: inline-size;
       }
       .c #inner { display: none; }
-      @container c1 (min-width: 200px) {
+      @container c1 size(min-width: 200px) {
         .c #inner { display: inline }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index 4eb22b2..bcf700f 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -147,6 +147,8 @@
                                       Results results) const {
   if (auto* n = DynamicTo<MediaQueryNestedExpNode>(node))
     return Eval(n->Operand(), results);
+  if (auto* n = DynamicTo<MediaQueryFunctionExpNode>(node))
+    return Eval(n->Operand(), results);
   if (auto* n = DynamicTo<MediaQueryNotExpNode>(node))
     return EvalNot(n->Operand(), results);
   if (auto* n = DynamicTo<MediaQueryAndExpNode>(node))
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc
index 7df7da80..a979a5dc 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -576,6 +576,14 @@
   return std::make_unique<MediaQueryNestedExpNode>(std::move(operand));
 }
 
+std::unique_ptr<MediaQueryExpNode> MediaQueryExpNode::Function(
+    std::unique_ptr<MediaQueryExpNode> operand,
+    const AtomicString& name) {
+  if (!operand)
+    return nullptr;
+  return std::make_unique<MediaQueryFunctionExpNode>(std::move(operand), name);
+}
+
 std::unique_ptr<MediaQueryExpNode> MediaQueryExpNode::And(
     std::unique_ptr<MediaQueryExpNode> left,
     std::unique_ptr<MediaQueryExpNode> right) {
@@ -645,6 +653,17 @@
   return std::make_unique<MediaQueryNestedExpNode>(Operand().Copy());
 }
 
+void MediaQueryFunctionExpNode::SerializeTo(StringBuilder& builder) const {
+  builder.Append(name_);
+  builder.Append("(");
+  Operand().SerializeTo(builder);
+  builder.Append(")");
+}
+
+std::unique_ptr<MediaQueryExpNode> MediaQueryFunctionExpNode::Copy() const {
+  return std::make_unique<MediaQueryFunctionExpNode>(Operand().Copy(), name_);
+}
+
 void MediaQueryNotExpNode::SerializeTo(StringBuilder& builder) const {
   builder.Append("not ");
   Operand().SerializeTo(builder);
diff --git a/third_party/blink/renderer/core/css/media_query_exp.h b/third_party/blink/renderer/core/css/media_query_exp.h
index 0605d78..b352edb8 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.h
+++ b/third_party/blink/renderer/core/css/media_query_exp.h
@@ -289,7 +289,7 @@
  public:
   virtual ~MediaQueryExpNode() = default;
 
-  enum class Type { kFeature, kNested, kNot, kAnd, kOr, kUnknown };
+  enum class Type { kFeature, kNested, kFunction, kNot, kAnd, kOr, kUnknown };
 
   String Serialize() const;
 
@@ -305,6 +305,9 @@
       std::unique_ptr<MediaQueryExpNode>);
   static std::unique_ptr<MediaQueryExpNode> Nested(
       std::unique_ptr<MediaQueryExpNode>);
+  static std::unique_ptr<MediaQueryExpNode> Function(
+      std::unique_ptr<MediaQueryExpNode>,
+      const AtomicString& name);
   static std::unique_ptr<MediaQueryExpNode> And(
       std::unique_ptr<MediaQueryExpNode>,
       std::unique_ptr<MediaQueryExpNode>);
@@ -362,6 +365,22 @@
   std::unique_ptr<MediaQueryExpNode> Copy() const override;
 };
 
+class CORE_EXPORT MediaQueryFunctionExpNode : public MediaQueryUnaryExpNode {
+  USING_FAST_MALLOC(MediaQueryFunctionExpNode);
+
+ public:
+  explicit MediaQueryFunctionExpNode(std::unique_ptr<MediaQueryExpNode> operand,
+                                     const AtomicString& name)
+      : MediaQueryUnaryExpNode(std::move(operand)), name_(name) {}
+
+  Type GetType() const override { return Type::kFunction; }
+  void SerializeTo(StringBuilder&) const override;
+  std::unique_ptr<MediaQueryExpNode> Copy() const override;
+
+ private:
+  AtomicString name_;
+};
+
 class CORE_EXPORT MediaQueryNotExpNode : public MediaQueryUnaryExpNode {
   USING_FAST_MALLOC(MediaQueryNotExpNode);
 
@@ -454,6 +473,13 @@
 };
 
 template <>
+struct DowncastTraits<MediaQueryFunctionExpNode> {
+  static bool AllowFrom(const MediaQueryExpNode& node) {
+    return node.GetType() == MediaQueryExpNode::Type::kFunction;
+  }
+};
+
+template <>
 struct DowncastTraits<MediaQueryNotExpNode> {
   static bool AllowFrom(const MediaQueryExpNode& node) {
     return node.GetType() == MediaQueryExpNode::Type::kNot;
diff --git a/third_party/blink/renderer/core/css/media_query_exp_test.cc b/third_party/blink/renderer/core/css/media_query_exp_test.cc
index b5029de..d09a74b5 100644
--- a/third_party/blink/renderer/core/css/media_query_exp_test.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp_test.cc
@@ -407,6 +407,7 @@
   MediaQueryExp exp = RightExp("width", LtCmp(PxValue(10)));
 
   EXPECT_FALSE(MediaQueryExpNode::Nested(nullptr));
+  EXPECT_FALSE(MediaQueryExpNode::Function(nullptr, "test"));
   EXPECT_FALSE(MediaQueryExpNode::Not(nullptr));
   EXPECT_FALSE(MediaQueryExpNode::And(nullptr, FeatureNode(exp)));
   EXPECT_FALSE(MediaQueryExpNode::And(FeatureNode(exp), nullptr));
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.cc b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
index 3cd3e3d..9a5e55c 100644
--- a/third_party/blink/renderer/core/css/parser/container_query_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser.cc
@@ -14,6 +14,9 @@
 
 namespace blink {
 
+using css_parsing_utils::AtIdent;
+using css_parsing_utils::ConsumeIfIdent;
+
 namespace {
 
 bool IsNone(const CSSValue& value) {
@@ -39,6 +42,31 @@
   return result;
 }
 
+// not <func> | <func> [ and <func> ]* | <func> [ or <func> ]*
+//
+// For example, if <func> is a function that can parse <container-query>,
+// then ConsumeNotAndOr can be used to parse <container-condition>:
+//
+// https://drafts.csswg.org/css-contain-3/#typedef-container-condition
+template <typename Func>
+std::unique_ptr<MediaQueryExpNode> ConsumeNotAndOr(Func func,
+                                                   CSSParserTokenRange& range) {
+  if (ConsumeIfIdent(range, "not"))
+    return MediaQueryExpNode::Not(func(range));
+
+  std::unique_ptr<MediaQueryExpNode> result = func(range);
+
+  if (AtIdent(range.Peek(), "and")) {
+    while (result && ConsumeIfIdent(range, "and"))
+      result = MediaQueryExpNode::And(std::move(result), func(range));
+  } else if (AtIdent(range.Peek(), "or")) {
+    while (ConsumeIfIdent(range, "or"))
+      result = MediaQueryExpNode::Or(std::move(result), func(range));
+  }
+
+  return result;
+}
+
 }  // namespace
 
 ContainerQueryParser::ContainerQueryParser(const CSSParserContext& context)
@@ -94,10 +122,91 @@
 std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ParseQuery(
     CSSParserTokenRange range) {
   range.ConsumeWhitespace();
-  auto node = media_query_parser_.ConsumeCondition(range);
+  auto node = ConsumeContainerQuery(range);
   if (!range.AtEnd())
     return nullptr;
   return node;
 }
 
+std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ConsumeContainerQuery(
+    CSSParserTokenRange& range) {
+  CSSParserTokenRange original_range = range;
+
+  // ( <container-condition> ) | size( <size-query> )
+  if (range.Peek().GetType() == kLeftParenthesisToken) {
+    auto block = range.ConsumeBlock();
+    block.ConsumeWhitespace();
+    range.ConsumeWhitespace();
+    auto condition = ConsumeContainerCondition(block);
+    if (condition && block.AtEnd())
+      return MediaQueryExpNode::Nested(std::move(condition));
+  } else if (range.Peek().GetType() == kFunctionToken &&
+             range.Peek().FunctionId() == CSSValueID::kSize) {
+    auto block = range.ConsumeBlock();
+    block.ConsumeWhitespace();
+    range.ConsumeWhitespace();
+    auto query = ConsumeFeatureQuery(block);
+    if (query && block.AtEnd())
+      return MediaQueryExpNode::Function(std::move(query), "size");
+  }
+  range = original_range;
+
+  // <general-enclosed>
+  return media_query_parser_.ConsumeGeneralEnclosed(range);
+}
+
+std::unique_ptr<MediaQueryExpNode>
+ContainerQueryParser::ConsumeContainerCondition(CSSParserTokenRange& range) {
+  return ConsumeNotAndOr(
+      [this](CSSParserTokenRange& range) {
+        return this->ConsumeContainerQuery(range);
+      },
+      range);
+}
+
+std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ConsumeFeatureQuery(
+    CSSParserTokenRange& range) {
+  CSSParserTokenRange original_range = range;
+
+  if (auto feature = ConsumeFeature(range))
+    return feature;
+  range = original_range;
+
+  if (auto node = ConsumeFeatureCondition(range))
+    return node;
+
+  return nullptr;
+}
+
+std::unique_ptr<MediaQueryExpNode>
+ContainerQueryParser::ConsumeFeatureQueryInParens(CSSParserTokenRange& range) {
+  CSSParserTokenRange original_range = range;
+
+  if (range.Peek().GetType() == kLeftParenthesisToken) {
+    auto block = range.ConsumeBlock();
+    block.ConsumeWhitespace();
+    range.ConsumeWhitespace();
+    auto query = ConsumeFeatureQuery(block);
+    if (query && block.AtEnd())
+      return MediaQueryExpNode::Nested(std::move(query));
+  }
+  range = original_range;
+
+  return media_query_parser_.ConsumeGeneralEnclosed(range);
+}
+
+std::unique_ptr<MediaQueryExpNode>
+ContainerQueryParser::ConsumeFeatureCondition(CSSParserTokenRange& range) {
+  return ConsumeNotAndOr(
+      [this](CSSParserTokenRange& range) {
+        return this->ConsumeFeatureQueryInParens(range);
+      },
+      range);
+}
+
+std::unique_ptr<MediaQueryExpNode> ContainerQueryParser::ConsumeFeature(
+    CSSParserTokenRange& range) {
+  return media_query_parser_.ConsumeFeature(range);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser.h b/third_party/blink/renderer/core/css/parser/container_query_parser.h
index 40f42f9d..bae1ff4 100644
--- a/third_party/blink/renderer/core/css/parser/container_query_parser.h
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser.h
@@ -29,6 +29,17 @@
   std::unique_ptr<MediaQueryExpNode> ParseQuery(CSSParserTokenRange);
 
  private:
+  std::unique_ptr<MediaQueryExpNode> ConsumeContainerQuery(
+      CSSParserTokenRange&);
+  std::unique_ptr<MediaQueryExpNode> ConsumeContainerCondition(
+      CSSParserTokenRange&);
+  std::unique_ptr<MediaQueryExpNode> ConsumeFeatureQuery(CSSParserTokenRange&);
+  std::unique_ptr<MediaQueryExpNode> ConsumeFeatureQueryInParens(
+      CSSParserTokenRange&);
+  std::unique_ptr<MediaQueryExpNode> ConsumeFeatureCondition(
+      CSSParserTokenRange&);
+  std::unique_ptr<MediaQueryExpNode> ConsumeFeature(CSSParserTokenRange&);
+
   const CSSParserContext& context_;
   MediaQueryParser media_query_parser_;
 };
diff --git a/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
index 951cb13..fe305ab 100644
--- a/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/container_query_parser_test.cc
@@ -25,6 +25,19 @@
       return g_null_atom;
     return selector->ToString();
   }
+
+  String ParseQuery(String string) {
+    const auto* context = MakeGarbageCollected<CSSParserContext>(GetDocument());
+    std::unique_ptr<MediaQueryExpNode> node =
+        ContainerQueryParser(*context).ParseQuery(string);
+    if (!node)
+      return g_null_atom;
+    if (node->HasUnknown())
+      return "<unknown>";
+    StringBuilder builder;
+    node->SerializeTo(builder);
+    return builder.ReleaseString();
+  }
 };
 
 TEST_F(ContainerQueryParserTest, ConsumeSelector) {
@@ -56,4 +69,46 @@
   EXPECT_EQ(g_null_atom, ParseSelector("name(foo) name(bar)"));
 }
 
+TEST_F(ContainerQueryParserTest, ParseQuery) {
+  struct {
+    const char* input;
+    const char* output;
+  } tests[] = {
+      {"size(width)", nullptr},
+      {"size(width: 100px)", nullptr},
+      {"(not size(width))", nullptr},
+      {"((not size(width)) and size(width))", nullptr},
+      {"size((not (width)) and (width))", nullptr},
+      {"(size(width) and size(width))", nullptr},
+      {"(size(width) or (size(width) and (not size(width))))", nullptr},
+      {"size((width > 100px) and (width > 200px))", nullptr},
+      {"size((width) and (width) and (width))", nullptr},
+      {"size((width) or (width) or (width))", nullptr},
+  };
+
+  for (const auto& test : tests) {
+    String actual = ParseQuery(test.input);
+    String expected(test.output ? test.output : test.input);
+    EXPECT_EQ(expected, actual);
+  }
+
+  // Invalid:
+  EXPECT_EQ("<unknown>", ParseQuery("(width)"));
+  EXPECT_EQ("<unknown>", ParseQuery("(min-width)"));
+  EXPECT_EQ("<unknown>", ParseQuery("(min-width: 100px)"));
+  EXPECT_EQ("<unknown>", ParseQuery("(width > 100px)"));
+  EXPECT_EQ(g_null_atom, ParseQuery("size(width) and size(height)"));
+  EXPECT_EQ(g_null_atom, ParseQuery("size(width) or size(height)"));
+  EXPECT_EQ("<unknown>", ParseQuery("size((width) or (width) and (width))"));
+  EXPECT_EQ("<unknown>", ParseQuery("size((width) and (width) or (width))"));
+  EXPECT_EQ("<unknown>",
+            ParseQuery("(size(width) or size(height) and size(width))"));
+  EXPECT_EQ("<unknown>",
+            ParseQuery("(size(width) and size(height) or size(width))"));
+  EXPECT_EQ("<unknown>", ParseQuery("(size(width) and size(height) 50px)"));
+  EXPECT_EQ("<unknown>", ParseQuery("(size(width) and size(height 50px))"));
+  EXPECT_EQ("<unknown>", ParseQuery("(size(width) and 50px size(height))"));
+  EXPECT_EQ("<unknown>", ParseQuery("foo(width)"));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
index bc5617e..c85ddad 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_impl_test.cc
@@ -214,7 +214,7 @@
 TEST(CSSParserImplTest, AtContainerOffsets) {
   ScopedCSSContainerQueriesForTest scoped_feature(true);
 
-  String sheet_text = "@container (max-width: 100px) { }";
+  String sheet_text = "@container size(max-width: 100px) { }";
 
   auto* context = MakeGarbageCollected<CSSParserContext>(
       kHTMLStandardMode, SecureContextMode::kInsecureContext);
@@ -226,13 +226,13 @@
   EXPECT_EQ(test_css_parser_observer.rule_type_,
             StyleRule::RuleType::kContainer);
   EXPECT_EQ(test_css_parser_observer.rule_header_start_, 11u);
-  EXPECT_EQ(test_css_parser_observer.rule_header_end_, 30u);
-  EXPECT_EQ(test_css_parser_observer.rule_body_start_, 31u);
-  EXPECT_EQ(test_css_parser_observer.rule_body_end_, 32u);
+  EXPECT_EQ(test_css_parser_observer.rule_header_end_, 34u);
+  EXPECT_EQ(test_css_parser_observer.rule_body_start_, 35u);
+  EXPECT_EQ(test_css_parser_observer.rule_body_end_, 36u);
 }
 
 TEST(CSSParserImplTest, AtContainerDisabled) {
-  String rule = "@container (max-width: 100px) { }";
+  String rule = "@container size(max-width: 100px) { }";
   {
     ScopedCSSContainerQueriesForTest scoped_feature(true);
     Document* document = Document::CreateForTest();
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
index b0e9f175..1096694 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -835,7 +835,7 @@
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
       #container { container-type: inline-size; }
-      @container (min-width: 1px) {
+      @container size(min-width: 1px) {
         #inner {
           top: 1em;
         }
@@ -867,7 +867,7 @@
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
       #container { container-type: inline-size; }
-      @container (min-width: 1px) {
+      @container size(min-width: 1px) {
         #inner::before {
           top: 1em;
         }
@@ -1330,7 +1330,7 @@
   GetDocument().documentElement()->setInnerHTML(R"HTML(
     <style>
       #a { color: red; }
-      @container (min-width: 0px) {
+      @container size(min-width: 0px) {
         #b { color: blue; }
         span { color: green; }
         #d { color: coral; }
@@ -1369,7 +1369,7 @@
     <style>
       main { container-type: size; width: 100px; }
       #a::before { content: "before"; }
-      @container (min-width: 0px) {
+      @container size(min-width: 0px) {
         #a::after { content: "after"; }
       }
     </style>
@@ -1398,7 +1398,7 @@
 TEST_F(StyleResolverTestCQ, DependsOnContainerQueriesMPC) {
   GetDocument().documentElement()->setInnerHTML(R"HTML(
     <style>
-      @container (min-width: 9999999px) {
+      @container size(min-width: 9999999px) {
         #a { color: green; }
       }
     </style>
@@ -2125,10 +2125,10 @@
   GetDocument().documentElement()->setInnerHTML(R"HTML(
     <style>
       #container { container-type: inline-size }
-      @container (min-width: 1px) {
+      @container size(min-width: 1px) {
         #target { }
       }
-      @container (min-width: 99999px) {
+      @container size(min-width: 99999px) {
         #target { color: red }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index d0cde96..bd0755a 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -3646,7 +3646,7 @@
         width: 100px;
         height: 100px;
       }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         .affected { background-color: green; }
       }
     </style>
@@ -3707,7 +3707,7 @@
         width: 100px;
         height: 100px;
       }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         .toggle { background-color: green; }
       }
     </style>
@@ -3767,7 +3767,7 @@
         width: 100px;
         height: 100px;
       }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         #container::before { content: " " }
         span::before { content: " " }
       }
@@ -3800,7 +3800,7 @@
         width: 100px;
         height: 100px;
       }
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         #input { background-color: green; }
       }
     </style>
@@ -3862,7 +3862,7 @@
   ASSERT_TRUE(late_style);
 
   late_style->setTextContent(R"CSS(
-      @container (min-width: 1px) {
+      @container size(min-width: 1px) {
         #a { color: green; }
       }
     )CSS");
@@ -3907,7 +3907,7 @@
         width: 200px;
       }
 
-      @container (min-width: 200px) {
+      @container size(min-width: 200px) {
         #a { z-index: 2; }
       }
     </style>
diff --git a/third_party/blink/renderer/core/css/style_recalc_test.cc b/third_party/blink/renderer/core/css/style_recalc_test.cc
index 8139426..8a717f8 100644
--- a/third_party/blink/renderer/core/css/style_recalc_test.cc
+++ b/third_party/blink/renderer/core/css/style_recalc_test.cc
@@ -53,10 +53,10 @@
       #outer.narrow { width: 200px; }
       #container { container-type: inline-size; }
       #container.narrow { width: 100px; }
-      @container (max-width: 200px) {
+      @container size(max-width: 200px) {
         #affected { color: red; }
       }
-      @container (max-width: 100px) {
+      @container size(max-width: 100px) {
         #affected { color: green; }
       }
       .flip { color: pink; }
@@ -186,7 +186,7 @@
     <style>
       #container { container-type: inline-size; }
       #container.narrow { width: 100px; }
-      @container (max-width: 100px) {
+      @container size(max-width: 100px) {
         #affected { color: green; }
       }
     </style>
@@ -219,7 +219,7 @@
         display: inline-block;
         color: pink; /* Make sure there's a recalc to skip. */
       }
-      @container (max-width: 100px) {
+      @container size(max-width: 100px) {
         #affected { color: green; }
       }
     </style>
diff --git a/third_party/blink/renderer/core/editing/build.gni b/third_party/blink/renderer/core/editing/build.gni
index d51c7e6d..a420e13c 100644
--- a/third_party/blink/renderer/core/editing/build.gni
+++ b/third_party/blink/renderer/core/editing/build.gni
@@ -217,6 +217,8 @@
   "markers/highlight_marker.h",
   "markers/highlight_marker_list_impl.cc",
   "markers/highlight_marker_list_impl.h",
+  "markers/highlight_pseudo_marker.cc",
+  "markers/highlight_pseudo_marker.h",
   "markers/sorted_document_marker_list_editor.cc",
   "markers/sorted_document_marker_list_editor.h",
   "markers/spell_check_marker.cc",
@@ -241,8 +243,6 @@
   "markers/text_fragment_marker.h",
   "markers/text_fragment_marker_list_impl.cc",
   "markers/text_fragment_marker_list_impl.h",
-  "markers/text_marker_base.cc",
-  "markers/text_marker_base.h",
   "markers/text_marker_base_list_impl.cc",
   "markers/text_marker_base_list_impl.h",
   "markers/text_match_marker.cc",
diff --git a/third_party/blink/renderer/core/editing/markers/highlight_marker.cc b/third_party/blink/renderer/core/editing/markers/highlight_marker.cc
index d65cb1f..0e38c32d 100644
--- a/third_party/blink/renderer/core/editing/markers/highlight_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/highlight_marker.cc
@@ -12,7 +12,7 @@
                                  unsigned end_offset,
                                  const String& highlight_name,
                                  const Member<Highlight> highlight)
-    : DocumentMarker(start_offset, end_offset),
+    : HighlightPseudoMarker(start_offset, end_offset),
       highlight_name_(highlight_name),
       highlight_(highlight) {}
 
@@ -20,6 +20,14 @@
   return DocumentMarker::kHighlight;
 }
 
+PseudoId HighlightMarker::GetPseudoId() const {
+  return kPseudoIdHighlight;
+}
+
+const AtomicString& HighlightMarker::GetPseudoArgument() const {
+  return GetHighlightName();
+}
+
 void HighlightMarker::Trace(blink::Visitor* visitor) const {
   visitor->Trace(highlight_);
   DocumentMarker::Trace(visitor);
diff --git a/third_party/blink/renderer/core/editing/markers/highlight_marker.h b/third_party/blink/renderer/core/editing/markers/highlight_marker.h
index 8ed97be2..1571216a 100644
--- a/third_party/blink/renderer/core/editing/markers/highlight_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/highlight_marker.h
@@ -5,14 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_HIGHLIGHT_MARKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_HIGHLIGHT_MARKER_H_
 
-#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
+#include "third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
 class Highlight;
 
-class CORE_EXPORT HighlightMarker final : public DocumentMarker {
+// A subclass of HighlightPseudoMarker for CSS custom highlights.
+// TODO(rego): Rename to CustomHighlightMarker to avoid misunderstandings.
+class CORE_EXPORT HighlightMarker final : public HighlightPseudoMarker {
  public:
   HighlightMarker(unsigned start_offset,
                   unsigned end_offset,
@@ -22,6 +24,9 @@
   HighlightMarker& operator=(const HighlightMarker&) = delete;
 
   MarkerType GetType() const final;
+  PseudoId GetPseudoId() const final;
+  const AtomicString& GetPseudoArgument() const final;
+
   const Highlight* GetHighlight() const { return highlight_; }
   const AtomicString& GetHighlightName() const { return highlight_name_; }
 
@@ -34,8 +39,11 @@
 
 template <>
 struct DowncastTraits<HighlightMarker> {
-  static bool AllowFrom(const DocumentMarker& document_marker) {
-    return document_marker.GetType() == DocumentMarker::kHighlight;
+  static bool AllowFrom(const DocumentMarker& marker) {
+    return marker.GetType() == DocumentMarker::kHighlight;
+  }
+  static bool AllowFrom(const HighlightPseudoMarker& marker) {
+    return marker.GetType() == DocumentMarker::kHighlight;
   }
 };
 
diff --git a/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.cc b/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.cc
new file mode 100644
index 0000000..6ab96e1
--- /dev/null
+++ b/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.cc
@@ -0,0 +1,13 @@
+// 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 "third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h"
+
+namespace blink {
+
+HighlightPseudoMarker::HighlightPseudoMarker(unsigned start_offset,
+                                             unsigned end_offset)
+    : DocumentMarker(start_offset, end_offset) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h b/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h
new file mode 100644
index 0000000..050cc3c
--- /dev/null
+++ b/third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h
@@ -0,0 +1,38 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_HIGHLIGHT_PSEUDO_MARKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_HIGHLIGHT_PSEUDO_MARKER_H_
+
+#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
+
+namespace blink {
+
+// DocumentMarker subclass that represent the CSS highlight pseudos-elements and
+// the CSS custom highlight pseudo-element:
+// * https://drafts.csswg.org/css-pseudo-4/#highlight-pseudos
+// * https://drafts.csswg.org/css-highlight-api/#custom-highlight-pseudo
+class CORE_EXPORT HighlightPseudoMarker : public DocumentMarker {
+ public:
+  HighlightPseudoMarker(unsigned start_offset, unsigned end_offset);
+  HighlightPseudoMarker(const HighlightPseudoMarker&) = delete;
+  HighlightPseudoMarker& operator=(const HighlightPseudoMarker&) = delete;
+
+  virtual PseudoId GetPseudoId() const = 0;
+  virtual const AtomicString& GetPseudoArgument() const = 0;
+};
+
+template <>
+struct DowncastTraits<HighlightPseudoMarker> {
+  static bool AllowFrom(const DocumentMarker& document_marker) {
+    return document_marker.GetType() == DocumentMarker::kHighlight ||
+           document_marker.GetType() == DocumentMarker::kTextFragment;
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_HIGHLIGHT_PSEUDO_MARKER_H_
diff --git a/third_party/blink/renderer/core/editing/markers/text_fragment_marker.cc b/third_party/blink/renderer/core/editing/markers/text_fragment_marker.cc
index ce8314318..89c68951 100644
--- a/third_party/blink/renderer/core/editing/markers/text_fragment_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/text_fragment_marker.cc
@@ -8,17 +8,18 @@
 
 TextFragmentMarker::TextFragmentMarker(unsigned start_offset,
                                        unsigned end_offset)
-    : TextMarkerBase(start_offset, end_offset) {
-  DCHECK_LT(start_offset, end_offset);
-}
+    : HighlightPseudoMarker(start_offset, end_offset) {}
 
 DocumentMarker::MarkerType TextFragmentMarker::GetType() const {
   return DocumentMarker::kTextFragment;
 }
 
-bool TextFragmentMarker::IsActiveMatch() const {
-  // The TextFragmentMarker is painted as an inactive text match marker.
-  return false;
+PseudoId TextFragmentMarker::GetPseudoId() const {
+  return kPseudoIdTargetText;
+}
+
+const AtomicString& TextFragmentMarker::GetPseudoArgument() const {
+  return g_null_atom;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/markers/text_fragment_marker.h b/third_party/blink/renderer/core/editing/markers/text_fragment_marker.h
index 4934f50..932797cc 100644
--- a/third_party/blink/renderer/core/editing/markers/text_fragment_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/text_fragment_marker.h
@@ -5,24 +5,25 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_FRAGMENT_MARKER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_FRAGMENT_MARKER_H_
 
-#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
+#include "third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
-// A subclass of TextMarkerBase used for indicating a text fragment on the
-// page. See blink/renderer/core/page/scrolling/text_fragment_anchor.h.
-class CORE_EXPORT TextFragmentMarker final : public TextMarkerBase {
+// A subclass of HighlightPseudoMarker used for indicating a text fragment on
+// the page. See blink/renderer/core/page/scrolling/text_fragment_anchor.h.
+class CORE_EXPORT TextFragmentMarker final : public HighlightPseudoMarker {
  public:
   TextFragmentMarker(unsigned start_offset, unsigned end_offset);
   TextFragmentMarker(const TextFragmentMarker&) = delete;
   TextFragmentMarker& operator=(const TextFragmentMarker&) = delete;
 
-  // DocumentMarker implementations
+  // DocumentMarker implementations.
   MarkerType GetType() const final;
 
-  // TextMarkerBase implementations
-  bool IsActiveMatch() const final;
+  // HighlightPseudoMarker implementations.
+  PseudoId GetPseudoId() const final;
+  const AtomicString& GetPseudoArgument() const final;
 };
 
 template <>
@@ -30,7 +31,7 @@
   static bool AllowFrom(const DocumentMarker& marker) {
     return marker.GetType() == DocumentMarker::kTextFragment;
   }
-  static bool AllowFrom(const TextMarkerBase& marker) {
+  static bool AllowFrom(const HighlightPseudoMarker& marker) {
     return marker.GetType() == DocumentMarker::kTextFragment;
   }
 };
diff --git a/third_party/blink/renderer/core/editing/markers/text_marker_base.cc b/third_party/blink/renderer/core/editing/markers/text_marker_base.cc
deleted file mode 100644
index 8057c46..0000000
--- a/third_party/blink/renderer/core/editing/markers/text_marker_base.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
-
-namespace blink {
-
-TextMarkerBase::TextMarkerBase(unsigned start_offset, unsigned end_offset)
-    : DocumentMarker(start_offset, end_offset) {}
-
-bool IsTextMarker(const DocumentMarker& marker) {
-  return marker.GetType() == DocumentMarker::kTextMatch ||
-         marker.GetType() == DocumentMarker::kTextFragment;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/markers/text_marker_base.h b/third_party/blink/renderer/core/editing/markers/text_marker_base.h
deleted file mode 100644
index c6f9b590..0000000
--- a/third_party/blink/renderer/core/editing/markers/text_marker_base.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_MARKER_BASE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_MARKER_BASE_H_
-
-#include "third_party/blink/renderer/core/editing/markers/document_marker.h"
-#include "third_party/blink/renderer/platform/wtf/casting.h"
-
-namespace blink {
-
-// A subclass of DocumentMarker used to implement functionality shared between
-// text match and text fragment markers, which share painting logic.
-class CORE_EXPORT TextMarkerBase : public DocumentMarker {
- public:
-  TextMarkerBase(unsigned start_offset, unsigned end_offset);
-  TextMarkerBase(const TextMarkerBase&) = delete;
-  TextMarkerBase& operator=(const TextMarkerBase&) = delete;
-
-  virtual bool IsActiveMatch() const = 0;
-};
-
-bool CORE_EXPORT IsTextMarker(const DocumentMarker&);
-
-template <>
-struct DowncastTraits<TextMarkerBase> {
-  static bool AllowFrom(const DocumentMarker& marker) {
-    return IsTextMarker(marker);
-  }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_MARKER_BASE_H_
diff --git a/third_party/blink/renderer/core/editing/markers/text_marker_base_list_impl.h b/third_party/blink/renderer/core/editing/markers/text_marker_base_list_impl.h
index cc30897..4ffbb95 100644
--- a/third_party/blink/renderer/core/editing/markers/text_marker_base_list_impl.h
+++ b/third_party/blink/renderer/core/editing/markers/text_marker_base_list_impl.h
@@ -14,6 +14,8 @@
 // Nearly-complete implementation of DocumentMarkerList for text match or text
 // fragment markers (subclassed by TextMatchMarkerListImpl and
 // TextFragmentMarkerListImpl to implement the MarkerType() method).
+// TODO(rego): Remove this class and add a HighlightPseudoMarkerListImpl instead
+// (to match HighlightPseudoMarker classes).
 class CORE_EXPORT TextMarkerBaseListImpl : public DocumentMarkerList {
  public:
   TextMarkerBaseListImpl(const TextMarkerBaseListImpl&) = delete;
diff --git a/third_party/blink/renderer/core/editing/markers/text_match_marker.cc b/third_party/blink/renderer/core/editing/markers/text_match_marker.cc
index f441819..276a5f1 100644
--- a/third_party/blink/renderer/core/editing/markers/text_match_marker.cc
+++ b/third_party/blink/renderer/core/editing/markers/text_match_marker.cc
@@ -9,7 +9,7 @@
 TextMatchMarker::TextMatchMarker(unsigned start_offset,
                                  unsigned end_offset,
                                  MatchStatus status)
-    : TextMarkerBase(start_offset, end_offset), match_status_(status) {}
+    : DocumentMarker(start_offset, end_offset), match_status_(status) {}
 
 DocumentMarker::MarkerType TextMatchMarker::GetType() const {
   return DocumentMarker::kTextMatch;
diff --git a/third_party/blink/renderer/core/editing/markers/text_match_marker.h b/third_party/blink/renderer/core/editing/markers/text_match_marker.h
index 0577ab9..62ed7ad 100644
--- a/third_party/blink/renderer/core/editing/markers/text_match_marker.h
+++ b/third_party/blink/renderer/core/editing/markers/text_match_marker.h
@@ -28,7 +28,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_TEXT_MATCH_MARKER_H_
 
 #include "third_party/blink/renderer/core/editing/markers/document_marker.h"
-#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 
@@ -38,7 +37,7 @@
 // markers. We store whether or not the match is active, a LayoutRect used for
 // rendering the marker, and whether or not the LayoutRect is currently
 // up-to-date.
-class CORE_EXPORT TextMatchMarker final : public TextMarkerBase {
+class CORE_EXPORT TextMatchMarker final : public DocumentMarker {
  private:
   enum class LayoutStatus { kInvalid, kValidNull, kValidNotNull };
 
@@ -52,10 +51,8 @@
   // DocumentMarker implementations
   MarkerType GetType() const final;
 
-  // TextMarkerBase implementations
-  bool IsActiveMatch() const final;
-
   // TextMatchMarker-specific
+  bool IsActiveMatch() const;
   void SetIsActiveMatch(bool active);
 
   bool IsRendered() const;
@@ -78,9 +75,6 @@
   static bool AllowFrom(const DocumentMarker& marker) {
     return marker.GetType() == DocumentMarker::kTextMatch;
   }
-  static bool AllowFrom(const TextMarkerBase& marker) {
-    return marker.GetType() == DocumentMarker::kTextMatch;
-  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight_test.cc b/third_party/blink/renderer/core/inspector/inspector_highlight_test.cc
index 9b80448..f7d6152 100644
--- a/third_party/blink/renderer/core/inspector/inspector_highlight_test.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_highlight_test.cc
@@ -195,7 +195,7 @@
         height: 500px;
         container-type: inline-size;
       }
-      @container (min-width: 100px) {
+      @container size(min-width: 100px) {
         .item {
           width: 100px;
           height: 100px;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index f6efe8a..3ac86895 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -116,6 +116,7 @@
 #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -4055,7 +4056,7 @@
 void LayoutObject::Destroy() {
   NOT_DESTROYED();
   CHECK(g_allow_destroying_layout_object_in_finalizer ||
-        !ThreadState::Current()->InAtomicSweepingPause());
+        !ThreadState::IsSweepingOnOwningThread(*ThreadStateStorage::Current()));
 
   // Mark as being destroyed to avoid trouble with merges in |RemoveChild()| and
   // other house keepings.
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
index b8a8f838..26812262 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -530,7 +530,7 @@
 
 void InlineTextBox::PaintTextMarkerForeground(const PaintInfo& paint_info,
                                               const PhysicalOffset& box_origin,
-                                              const TextMarkerBase& marker,
+                                              const DocumentMarker& marker,
                                               const ComputedStyle& style,
                                               const Font& font) const {
   InlineTextBoxPainter(*this).PaintTextMarkerForeground(paint_info, box_origin,
@@ -539,7 +539,7 @@
 
 void InlineTextBox::PaintTextMarkerBackground(const PaintInfo& paint_info,
                                               const PhysicalOffset& box_origin,
-                                              const TextMarkerBase& marker,
+                                              const DocumentMarker& marker,
                                               const ComputedStyle& style,
                                               const Font& font) const {
   InlineTextBoxPainter(*this).PaintTextMarkerBackground(paint_info, box_origin,
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.h b/third_party/blink/renderer/core/layout/line/inline_text_box.h
index e511701..c7ae410 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.h
@@ -35,7 +35,6 @@
 namespace blink {
 
 class DocumentMarker;
-class TextMarkerBase;
 
 class CORE_EXPORT InlineTextBox : public InlineBox {
  public:
@@ -145,12 +144,12 @@
                                    bool grammar) const;
   virtual void PaintTextMarkerForeground(const PaintInfo&,
                                          const PhysicalOffset& box_origin,
-                                         const TextMarkerBase&,
+                                         const DocumentMarker&,
                                          const ComputedStyle&,
                                          const Font&) const;
   virtual void PaintTextMarkerBackground(const PaintInfo&,
                                          const PhysicalOffset& box_origin,
-                                         const TextMarkerBase&,
+                                         const DocumentMarker&,
                                          const ComputedStyle&,
                                          const Font&) const;
 
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
index 046d9d9..f652eff 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h"
 
 #include "third_party/blink/renderer/core/editing/markers/document_marker.h"
-#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
 #include "third_party/blink/renderer/core/editing/markers/text_match_marker.h"
 #include "third_party/blink/renderer/core/layout/api/line_layout_svg_inline_text.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
@@ -243,7 +242,7 @@
 
 void SVGInlineTextBox::PaintTextMarkerForeground(const PaintInfo& paint_info,
                                                  const PhysicalOffset& point,
-                                                 const TextMarkerBase& marker,
+                                                 const DocumentMarker& marker,
                                                  const ComputedStyle& style,
                                                  const Font& font) const {
   SVGInlineTextBoxPainter(*this).PaintTextMarkerForeground(paint_info, point,
@@ -252,7 +251,7 @@
 
 void SVGInlineTextBox::PaintTextMarkerBackground(const PaintInfo& paint_info,
                                                  const PhysicalOffset& point,
-                                                 const TextMarkerBase& marker,
+                                                 const DocumentMarker& marker,
                                                  const ComputedStyle& style,
                                                  const Font& font) const {
   SVGInlineTextBoxPainter(*this).PaintTextMarkerBackground(paint_info, point,
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
index 1017e45..ecb9ff07 100644
--- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
@@ -27,7 +27,7 @@
 
 namespace blink {
 
-class TextMarkerBase;
+class DocumentMarker;
 
 class SVGInlineTextBox final : public InlineTextBox {
  public:
@@ -88,12 +88,12 @@
                            bool) const final;
   void PaintTextMarkerForeground(const PaintInfo&,
                                  const PhysicalOffset&,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&) const final;
   void PaintTextMarkerBackground(const PaintInfo&,
                                  const PhysicalOffset&,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&) const final;
 
diff --git a/third_party/blink/renderer/core/paint/document_marker_painter.cc b/third_party/blink/renderer/core/paint/document_marker_painter.cc
index f1f9ee7..30623b2 100644
--- a/third_party/blink/renderer/core/paint/document_marker_painter.cc
+++ b/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -283,13 +283,14 @@
     const Document& document,
     Node* node,
     const ComputedStyle& style,
-    const TextMarkerBase& marker,
+    const DocumentMarker& marker,
     const PaintInfo& paint_info) {
   Color text_color = style.VisitedDependentColor(GetCSSPropertyColor());
-  if (marker.GetType() != DocumentMarker::kTextFragment) {
+  if (marker.GetType() == DocumentMarker::kTextMatch) {
     const Color platform_text_color =
         LayoutTheme::GetTheme().PlatformTextSearchColor(
-            marker.IsActiveMatch(), style.UsedColorScheme());
+            To<TextMatchMarker>(marker).IsActiveMatch(),
+            style.UsedColorScheme());
     if (platform_text_color == text_color)
       return {};
     text_color = platform_text_color;
@@ -301,7 +302,7 @@
   text_style.stroke_width = style.TextStrokeWidth();
   text_style.color_scheme = style.UsedColorScheme();
   text_style.shadow = nullptr;
-  if (marker.GetType() != DocumentMarker::kTextFragment)
+  if (marker.GetType() == DocumentMarker::kTextMatch)
     return text_style;
   return HighlightPaintingUtils::HighlightPaintingStyle(
       document, style, node, kPseudoIdTargetText, text_style, paint_info);
diff --git a/third_party/blink/renderer/core/paint/document_marker_painter.h b/third_party/blink/renderer/core/paint/document_marker_painter.h
index 8530108e..264b2a0 100644
--- a/third_party/blink/renderer/core/paint/document_marker_painter.h
+++ b/third_party/blink/renderer/core/paint/document_marker_painter.h
@@ -18,7 +18,6 @@
 class LayoutUnit;
 class Node;
 class StyleableMarker;
-class TextMarkerBase;
 struct PaintInfo;
 struct PhysicalOffset;
 struct PhysicalRect;
@@ -49,7 +48,7 @@
   static TextPaintStyle ComputeTextPaintStyleFrom(const Document& document,
                                                   Node* node,
                                                   const ComputedStyle& style,
-                                                  const TextMarkerBase& marker,
+                                                  const DocumentMarker& marker,
                                                   const PaintInfo& paint_info);
   static bool ShouldPaintMarkerUnderline(const StyleableMarker& marker);
 };
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index dca1708..4c6da06 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -651,11 +651,11 @@
       case DocumentMarker::kTextFragment:
       case DocumentMarker::kTextMatch:
         if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
-          inline_text_box_.PaintTextMarkerBackground(
-              paint_info, box_origin, To<TextMarkerBase>(marker), style, font);
+          inline_text_box_.PaintTextMarkerBackground(paint_info, box_origin,
+                                                     marker, style, font);
         } else {
-          inline_text_box_.PaintTextMarkerForeground(
-              paint_info, box_origin, To<TextMarkerBase>(marker), style, font);
+          inline_text_box_.PaintTextMarkerForeground(paint_info, box_origin,
+                                                     marker, style, font);
         }
         break;
       case DocumentMarker::kComposition:
@@ -903,7 +903,7 @@
 void InlineTextBoxPainter::PaintTextMarkerForeground(
     const PaintInfo& paint_info,
     const PhysicalOffset& box_origin,
-    const TextMarkerBase& marker,
+    const DocumentMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   if (marker.GetType() == DocumentMarker::kTextMatch &&
@@ -951,7 +951,7 @@
 void InlineTextBoxPainter::PaintTextMarkerBackground(
     const PaintInfo& paint_info,
     const PhysicalOffset& box_origin,
-    const TextMarkerBase& marker,
+    const DocumentMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   if (marker.GetType() == DocumentMarker::kTextMatch &&
@@ -966,7 +966,10 @@
   TextRun run = inline_text_box_.ConstructTextRun(style);
 
   Color color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
-      marker.IsActiveMatch(), style.UsedColorScheme());
+      marker.GetType() == DocumentMarker::kTextMatch
+          ? To<TextMatchMarker>(marker).IsActiveMatch()
+          : false,
+      style.UsedColorScheme());
   GraphicsContext& context = paint_info.context;
   GraphicsContextStateSaver state_saver(context);
 
diff --git a/third_party/blink/renderer/core/paint/inline_text_box_painter.h b/third_party/blink/renderer/core/paint/inline_text_box_painter.h
index a9bb0b49..8ac51eb 100644
--- a/third_party/blink/renderer/core/paint/inline_text_box_painter.h
+++ b/third_party/blink/renderer/core/paint/inline_text_box_painter.h
@@ -22,7 +22,7 @@
 class LayoutObject;
 class LayoutTextCombine;
 class StyleableMarker;
-class TextMarkerBase;
+class DocumentMarker;
 struct PhysicalOffset;
 struct PhysicalRect;
 
@@ -57,12 +57,12 @@
                            bool grammar);
   void PaintTextMarkerForeground(const PaintInfo&,
                                  const PhysicalOffset& box_origin,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&);
   void PaintTextMarkerBackground(const PaintInfo&,
                                  const PhysicalOffset& box_origin,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&);
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
index 847ce90..b6a709c 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -8,9 +8,9 @@
 #include "third_party/blink/renderer/core/editing/editor.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
-#include "third_party/blink/renderer/core/editing/markers/highlight_marker.h"
+#include "third_party/blink/renderer/core/editing/markers/highlight_pseudo_marker.h"
 #include "third_party/blink/renderer/core/editing/markers/styleable_marker.h"
-#include "third_party/blink/renderer/core/editing/markers/text_marker_base.h"
+#include "third_party/blink/renderer/core/editing/markers/text_match_marker.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/highlight/highlight.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -330,22 +330,15 @@
                     : kPseudoIdGrammarError));
       } break;
 
-      case DocumentMarker::kTextFragment:
       case DocumentMarker::kTextMatch: {
         const Document& document = node_->GetDocument();
-        if (marker->GetType() == DocumentMarker::kTextMatch &&
-            !document.GetFrame()->GetEditor().MarkedTextMatchesAreHighlighted())
+        if (!document.GetFrame()->GetEditor().MarkedTextMatchesAreHighlighted())
           break;
-        const auto& text_marker = To<TextMarkerBase>(*marker);
+        const auto& text_match_marker = To<TextMatchMarker>(*marker);
         if (phase == kBackground) {
-          Color color;
-          if (marker->GetType() == DocumentMarker::kTextMatch) {
-            color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
-                text_marker.IsActiveMatch(), style_.UsedColorScheme());
-          } else {
-            color = HighlightPaintingUtils::HighlightBackgroundColor(
-                document, style_, node_, kPseudoIdTargetText);
-          }
+          Color color =
+              LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
+                  text_match_marker.IsActiveMatch(), style_.UsedColorScheme());
           PaintRect(paint_info_.context, PhysicalOffset(box_origin_),
                     fragment_item_.LocalRect(text, paint_start_offset,
                                              paint_end_offset),
@@ -356,13 +349,13 @@
         TextPaintStyle text_style;
         if (fragment_item_->Type() != NGFragmentItem::kSvgText) {
           text_style = DocumentMarkerPainter::ComputeTextPaintStyleFrom(
-              document, node_, style_, text_marker, paint_info_);
+              document, node_, style_, text_match_marker, paint_info_);
         } else {
           // DocumentMarkerPainter::ComputeTextPaintStyleFrom() doesn't work
           // well with SVG <text>, which doesn't apply 'color' CSS property.
           const Color platform_matched_color =
               LayoutTheme::GetTheme().PlatformTextSearchColor(
-                  text_marker.IsActiveMatch(), style_.UsedColorScheme());
+                  text_match_marker.IsActiveMatch(), style_.UsedColorScheme());
           text_painter_.SetSvgState(
               *To<LayoutSVGInlineText>(fragment_item_->GetLayoutObject()),
               style_, platform_matched_color);
@@ -399,16 +392,19 @@
         }
       } break;
 
+      case DocumentMarker::kTextFragment:
       case DocumentMarker::kHighlight: {
-        const auto& highlight_marker = To<HighlightMarker>(*marker);
+        const auto& highlight_pseudo_marker =
+            To<HighlightPseudoMarker>(*marker);
         const Document& document = node_->GetDocument();
 
         // Paint background
         if (phase == kBackground) {
           Color background_color =
               HighlightPaintingUtils::HighlightBackgroundColor(
-                  document, style_, node_, kPseudoIdHighlight,
-                  highlight_marker.GetHighlightName());
+                  document, style_, node_,
+                  highlight_pseudo_marker.GetPseudoId(),
+                  highlight_pseudo_marker.GetPseudoArgument());
 
           PaintRect(paint_info_.context, PhysicalOffset(box_origin_),
                     fragment_item_.LocalRect(text, paint_start_offset,
@@ -430,8 +426,9 @@
 
         const TextPaintStyle final_text_style =
             HighlightPaintingUtils::HighlightPaintingStyle(
-                document, style_, node_, kPseudoIdHighlight, text_style,
-                paint_info_, highlight_marker.GetHighlightName());
+                document, style_, node_, highlight_pseudo_marker.GetPseudoId(),
+                text_style, paint_info_,
+                highlight_pseudo_marker.GetPseudoArgument());
 
         text_painter_.Paint(paint_start_offset, paint_end_offset,
                             paint_end_offset - paint_start_offset,
diff --git a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
index a194c0ed9d..4ca5281 100644
--- a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
@@ -645,13 +645,12 @@
   const Vector<SVGTextFragmentWithRange> empty_text_match_list;
 
   // SVG does not support grammar or spellcheck markers, so skip anything but
-  // TextMarkerBase types.
+  // TextFragmentMarker and TextMatchMarker types.
   if (marker.GetType() != DocumentMarker::kTextMatch &&
       marker.GetType() != DocumentMarker::kTextFragment)
     return empty_text_match_list;
 
-  if (marker.GetType() == DocumentMarker::kTextMatch &&
-      !InlineLayoutObject()
+  if (!InlineLayoutObject()
            .GetFrame()
            ->GetEditor()
            .MarkedTextMatchesAreHighlighted())
@@ -690,7 +689,7 @@
 void SVGInlineTextBoxPainter::PaintTextMarkerForeground(
     const PaintInfo& paint_info,
     const PhysicalOffset& point,
-    const TextMarkerBase& marker,
+    const DocumentMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   const Vector<SVGTextFragmentWithRange> text_match_info_list =
@@ -699,7 +698,10 @@
     return;
 
   Color text_color = LayoutTheme::GetTheme().PlatformTextSearchColor(
-      marker.IsActiveMatch(), style.UsedColorScheme());
+      marker.GetType() == DocumentMarker::kTextMatch
+          ? To<TextMatchMarker>(marker).IsActiveMatch()
+          : false,
+      style.UsedColorScheme());
 
   PaintFlags fill_flags;
   fill_flags.setColor(text_color.Rgb());
@@ -733,7 +735,7 @@
 void SVGInlineTextBoxPainter::PaintTextMarkerBackground(
     const PaintInfo& paint_info,
     const PhysicalOffset& point,
-    const TextMarkerBase& marker,
+    const DocumentMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   const Vector<SVGTextFragmentWithRange> text_match_info_list =
@@ -742,7 +744,10 @@
     return;
 
   Color color = LayoutTheme::GetTheme().PlatformTextSearchHighlightColor(
-      marker.IsActiveMatch(), style.UsedColorScheme());
+      marker.GetType() == DocumentMarker::kTextMatch
+          ? To<TextMatchMarker>(marker).IsActiveMatch()
+          : false,
+      style.UsedColorScheme());
   for (const SVGTextFragmentWithRange& text_match_info : text_match_info_list) {
     const SVGTextFragment& fragment = text_match_info.fragment;
 
diff --git a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.h b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.h
index 9dd89f2..6f32a38 100644
--- a/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.h
+++ b/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.h
@@ -19,7 +19,6 @@
 class LayoutSVGInlineText;
 class SelectionBoundsRecorder;
 class SVGInlineTextBox;
-class TextMarkerBase;
 class TextRun;
 struct PaintInfo;
 struct PhysicalOffset;
@@ -47,12 +46,12 @@
   void PaintSelectionBackground(const PaintInfo&);
   void PaintTextMarkerForeground(const PaintInfo&,
                                  const PhysicalOffset&,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&);
   void PaintTextMarkerBackground(const PaintInfo&,
                                  const PhysicalOffset&,
-                                 const TextMarkerBase&,
+                                 const DocumentMarker&,
                                  const ComputedStyle&,
                                  const Font&);
 
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.cc b/third_party/blink/renderer/core/paint/text_decoration_info.cc
index b82ad289..13ec551 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.cc
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "third_party/blink/renderer/core/paint/text_decoration_info.h"
 #include "third_party/blink/renderer/core/paint/text_paint_style.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -142,8 +143,18 @@
 
   for (const AppliedTextDecoration& decoration :
        style_.AppliedTextDecorations()) {
-    applied_decorations_thickness_.push_back(ComputeUnderlineThickness(
-        decoration.Thickness(), decorating_box_style));
+    if (EnumHasFlags(decoration.Lines(), TextDecorationLine::kSpellingError) ||
+        EnumHasFlags(decoration.Lines(), TextDecorationLine::kGrammarError)) {
+      // Spelling and grammar error thickness doesn't depend on the font size.
+#if defined(OS_MAC)
+      applied_decorations_thickness_.push_back(2.f);
+#else
+      applied_decorations_thickness_.push_back(1.f);
+#endif
+    } else {
+      applied_decorations_thickness_.push_back(ComputeUnderlineThickness(
+          decoration.Thickness(), decorating_box_style));
+    }
   }
   DCHECK_EQ(style_.AppliedTextDecorations().size(),
             applied_decorations_thickness_.size());
@@ -162,6 +173,8 @@
   int wavy_offset_factor;
   switch (line) {
     case TextDecorationLine::kUnderline:
+    case TextDecorationLine::kSpellingError:
+    case TextDecorationLine::kGrammarError:
       double_offset = double_offset_from_thickness;
       wavy_offset_factor = 1;
       break;
@@ -183,6 +196,7 @@
       NOTREACHED();
   }
 
+  line_data_.line = line;
   line_data_.line_offset = line_offset;
   line_data_.double_offset = double_offset;
   line_data_.wavy_offset_factor = wavy_offset_factor;
@@ -201,10 +215,25 @@
 }
 
 ETextDecorationStyle TextDecorationInfo::DecorationStyle() const {
+  if (IsSpellingOrGrammarError()) {
+#if defined(OS_MAC)
+    return ETextDecorationStyle::kDotted;
+#else
+    return ETextDecorationStyle::kWavy;
+#endif
+  }
+
   return style_.AppliedTextDecorations()[decoration_index_].Style();
 }
 
 Color TextDecorationInfo::LineColor() const {
+  // TODO(rego): Allow customize the spelling and grammar error color with
+  // text-decoration-color property.
+  if (line_data_.line == TextDecorationLine::kSpellingError)
+    return LayoutTheme::GetTheme().PlatformSpellingMarkerUnderlineColor();
+  if (line_data_.line == TextDecorationLine::kGrammarError)
+    return LayoutTheme::GetTheme().PlatformGrammarMarkerUnderlineColor();
+
   // Find the matched normal and selection |AppliedTextDecoration|
   // and use the text-decoration-color from selection when it is.
   if (selection_text_decoration_ &&
@@ -316,6 +345,9 @@
   // Distance between decoration's axis and Bezier curve's control points. The
   // height of the curve is based on this distance. Increases the curve's height
   // as strokeThickness increases to make the curve look better.
+  if (IsSpellingOrGrammarError())
+    return 5;
+
   return 3.5 * WavyDecorationSizing();
 }
 
@@ -323,6 +355,9 @@
   // Increment used to form the diamond shape between start point (p1), control
   // points and end point (p2) along the axis of the decoration. Makes the curve
   // wider as strokeThickness increases to make the curve look better.
+  if (IsSpellingOrGrammarError())
+    return 3;
+
   return 2.5 * WavyDecorationSizing();
 }
 
@@ -366,6 +401,10 @@
   float wave_offset = DoubleOffset() * line_data_.wavy_offset_factor;
 
   float control_point_distance = ControlPointDistanceFromResolvedThickness();
+  // For spelling and grammar errors we invert the control_point_distance to get
+  // a result closer to Microsoft Word circa 2021.
+  if (IsSpellingOrGrammarError())
+    control_point_distance = -control_point_distance;
   float step = StepFromResolvedThickness();
 
   gfx::PointF start_point = StartPoint();
@@ -374,10 +413,15 @@
   // AppliedDecorationPainter::StrokeWavyTextDecoration().
   // Offset the start point, so the beizer curve starts before the current line,
   // that way we can clip it exactly the same way in both ends.
-  gfx::PointF p1(start_point + gfx::Vector2dF(-2 * step, wave_offset));
+  // For spelling and grammar errors we offset an extra half step, to get a
+  // result closer to Microsoft Word circa 2021.
+  float start_offset = (IsSpellingOrGrammarError() ? -2.5 : -2) * step;
+  gfx::PointF p1(start_point + gfx::Vector2dF(start_offset, wave_offset));
   // Increase the width including the previous offset, plus an extra wave to be
   // painted after the line.
-  gfx::PointF p2(start_point + gfx::Vector2dF(width_ + 4 * step, wave_offset));
+  float extra_width = (IsSpellingOrGrammarError() ? 4.5 : 4) * step;
+  gfx::PointF p2(start_point +
+                 gfx::Vector2dF(width_ + extra_width, wave_offset));
 
   GraphicsContext::AdjustLineToPixelBoundaries(p1, p2, ResolvedThickness());
 
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.h b/third_party/blink/renderer/core/paint/text_decoration_info.h
index 4c49dab2..a1c025be 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.h
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.h
@@ -114,6 +114,10 @@
   float StepFromResolvedThickness() const;
   Path PrepareDottedOrDashedStrokePath() const;
   Path PrepareWavyStrokePath() const;
+  bool IsSpellingOrGrammarError() const {
+    return line_data_.line == TextDecorationLine::kSpellingError ||
+           line_data_.line == TextDecorationLine::kGrammarError;
+  }
 
   const ComputedStyle& style_;
   const absl::optional<AppliedTextDecoration> selection_text_decoration_;
@@ -131,6 +135,7 @@
   int decoration_index_;
 
   struct LineData {
+    TextDecorationLine line;
     float line_offset;
     float double_offset;
     int wavy_offset_factor;
diff --git a/third_party/blink/renderer/core/paint/text_painter.cc b/third_party/blink/renderer/core/paint/text_painter.cc
index 93ad14b3..6a93fee1 100644
--- a/third_party/blink/renderer/core/paint/text_painter.cc
+++ b/third_party/blink/renderer/core/paint/text_painter.cc
@@ -93,6 +93,10 @@
     TextDecorationLine lines = decoration.Lines();
     bool has_underline = EnumHasFlags(lines, TextDecorationLine::kUnderline);
     bool has_overline = EnumHasFlags(lines, TextDecorationLine::kOverline);
+    bool is_spelling_error =
+        EnumHasFlags(lines, TextDecorationLine::kSpellingError);
+    bool is_grammar_error =
+        EnumHasFlags(lines, TextDecorationLine::kGrammarError);
     if (flip_underline_and_overline)
       std::swap(has_underline, has_overline);
 
@@ -101,6 +105,25 @@
     float resolved_thickness = decoration_info.ResolvedThickness();
     context.SetStrokeThickness(resolved_thickness);
 
+    if (is_spelling_error || is_grammar_error) {
+      DCHECK(!has_underline && !has_overline &&
+             !EnumHasFlags(lines, TextDecorationLine::kLineThrough));
+      const int paint_underline_offset =
+          decoration_offset.ComputeUnderlineOffset(
+              underline_position, decoration_info.Style().ComputedFontSize(),
+              decoration_info.FontData(), decoration.UnderlineOffset(),
+              resolved_thickness);
+      decoration_info.SetLineData(is_spelling_error
+                                      ? TextDecorationLine::kSpellingError
+                                      : TextDecorationLine::kGrammarError,
+                                  paint_underline_offset);
+      // We ignore "text-decoration-skip-ink: auto" for spelling and grammar
+      // error markers.
+      AppliedDecorationPainter decoration_painter(context, decoration_info);
+      decoration_painter.Paint();
+      continue;
+    }
+
     if (has_underline && decoration_info.FontData()) {
       // Don't apply text-underline-offset to overline.
       Length line_offset =
diff --git a/third_party/blink/renderer/core/paint/text_painter_base.cc b/third_party/blink/renderer/core/paint/text_painter_base.cc
index 103054b..55fb7ede 100644
--- a/third_party/blink/renderer/core/paint/text_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -252,6 +252,10 @@
     TextDecorationLine lines = decoration.Lines();
     bool has_underline = EnumHasFlags(lines, TextDecorationLine::kUnderline);
     bool has_overline = EnumHasFlags(lines, TextDecorationLine::kOverline);
+    bool is_spelling_error =
+        EnumHasFlags(lines, TextDecorationLine::kSpellingError);
+    bool is_grammar_error =
+        EnumHasFlags(lines, TextDecorationLine::kGrammarError);
     if (flip_underline_and_overline)
       std::swap(has_underline, has_overline);
 
@@ -260,6 +264,25 @@
     float resolved_thickness = decoration_info.ResolvedThickness();
     context.SetStrokeThickness(resolved_thickness);
 
+    if (is_spelling_error || is_grammar_error) {
+      DCHECK(!has_underline && !has_overline &&
+             !EnumHasFlags(lines, TextDecorationLine::kLineThrough));
+      const int paint_underline_offset =
+          decoration_offset.ComputeUnderlineOffset(
+              underline_position, decoration_info.ComputedFontSize(),
+              decoration_info.FontData(), decoration.UnderlineOffset(),
+              resolved_thickness);
+      decoration_info.SetLineData(is_spelling_error
+                                      ? TextDecorationLine::kSpellingError
+                                      : TextDecorationLine::kGrammarError,
+                                  paint_underline_offset);
+      // We ignore "text-decoration-skip-ink: auto" for spelling and grammar
+      // error markers.
+      AppliedDecorationPainter decoration_painter(context, decoration_info);
+      decoration_painter.Paint(flags);
+      continue;
+    }
+
     if (has_underline && decoration_info.FontData()) {
       // Don't apply text-underline-offset to overline.
       Length line_offset =
diff --git a/third_party/blink/renderer/core/svg/svg_element_test.cc b/third_party/blink/renderer/core/svg/svg_element_test.cc
index 223c55a..c2f11c4e 100644
--- a/third_party/blink/renderer/core/svg/svg_element_test.cc
+++ b/third_party/blink/renderer/core/svg/svg_element_test.cc
@@ -19,10 +19,10 @@
   GetDocument().body()->setInnerHTML(R"HTML(
     <style>
       #rect2 { display: none }
-      @container (max-width: 200px) {
+      @container size(max-width: 200px) {
         rect, g { color: green; }
       }
-      @container (min-width: 300px) {
+      @container size(min-width: 300px) {
         rect, g { background-color: red; }
       }
     </style>
diff --git a/third_party/blink/renderer/modules/breakout_box/OWNERS b/third_party/blink/renderer/modules/breakout_box/OWNERS
index 410637f..7c203f44 100644
--- a/third_party/blink/renderer/modules/breakout_box/OWNERS
+++ b/third_party/blink/renderer/modules/breakout_box/OWNERS
@@ -1,3 +1,4 @@
+benjaminwagner@google.com
 guidou@chromium.org
 hta@chromium.org
 tguilbert@chromium.org
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
index bf2ed9d..8ef2632f 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -353,92 +353,6 @@
   return result.ToString();
 }
 
-// Note: All of these strings need to be kept in sync with
-// peer_connection_update_table.js, in order to be displayed as friendly
-// strings on chrome://webrtc-internals.
-
-const char* GetSignalingStateString(
-    webrtc::PeerConnectionInterface::SignalingState state) {
-  const char* result = "";
-  switch (state) {
-    case webrtc::PeerConnectionInterface::SignalingState::kStable:
-      return "stable";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveLocalOffer:
-      return "have-local-offer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveRemoteOffer:
-      return "have-remote-offer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveLocalPrAnswer:
-      return "have-local-pranswer";
-    case webrtc::PeerConnectionInterface::SignalingState::kHaveRemotePrAnswer:
-      return "have-remote-pranswer";
-    case webrtc::PeerConnectionInterface::SignalingState::kClosed:
-      return "closed";
-    default:
-      NOTREACHED();
-      break;
-  }
-  return result;
-}
-
-const char* GetIceConnectionStateString(
-    webrtc::PeerConnectionInterface::IceConnectionState state) {
-  switch (state) {
-    case webrtc::PeerConnectionInterface::kIceConnectionNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::kIceConnectionChecking:
-      return "checking";
-    case webrtc::PeerConnectionInterface::kIceConnectionConnected:
-      return "connected";
-    case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
-      return "completed";
-    case webrtc::PeerConnectionInterface::kIceConnectionFailed:
-      return "failed";
-    case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
-      return "disconnected";
-    case webrtc::PeerConnectionInterface::kIceConnectionClosed:
-      return "closed";
-    default:
-      NOTREACHED();
-      return "";
-  }
-}
-
-const char* GetConnectionStateString(
-    webrtc::PeerConnectionInterface::PeerConnectionState state) {
-  switch (state) {
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting:
-      return "connecting";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
-      return "connected";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
-      return "disconnected";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
-      return "failed";
-    case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed:
-      return "closed";
-    default:
-      NOTREACHED();
-      return "";
-  }
-}
-
-const char* GetIceGatheringStateString(
-    webrtc::PeerConnectionInterface::IceGatheringState state) {
-  switch (state) {
-    case webrtc::PeerConnectionInterface::kIceGatheringNew:
-      return "new";
-    case webrtc::PeerConnectionInterface::kIceGatheringGathering:
-      return "gathering";
-    case webrtc::PeerConnectionInterface::kIceGatheringComplete:
-      return "complete";
-    default:
-      NOTREACHED();
-      return "";
-  }
-}
-
 const char* GetTransceiverUpdatedReasonString(
     PeerConnectionTracker::TransceiverUpdatedReason reason) {
   switch (reason) {
@@ -1120,8 +1034,9 @@
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
-  SendPeerConnectionUpdate(id, "signalingstatechange",
-                           GetSignalingStateString(state));
+  SendPeerConnectionUpdate(
+      id, "signalingstatechange",
+      webrtc::PeerConnectionInterface::AsString(state).data());
 }
 
 void PeerConnectionTracker::TrackLegacyIceConnectionStateChange(
@@ -1131,8 +1046,9 @@
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
-  SendPeerConnectionUpdate(id, "iceconnectionstatechange (legacy)",
-                           GetIceConnectionStateString(state));
+  SendPeerConnectionUpdate(
+      id, "iceconnectionstatechange (legacy)",
+      webrtc::PeerConnectionInterface::AsString(state).data());
 }
 
 void PeerConnectionTracker::TrackIceConnectionStateChange(
@@ -1142,8 +1058,9 @@
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
-  SendPeerConnectionUpdate(id, "iceconnectionstatechange",
-                           GetIceConnectionStateString(state));
+  SendPeerConnectionUpdate(
+      id, "iceconnectionstatechange",
+      webrtc::PeerConnectionInterface::AsString(state).data());
 }
 
 void PeerConnectionTracker::TrackConnectionStateChange(
@@ -1153,8 +1070,9 @@
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
-  SendPeerConnectionUpdate(id, "connectionstatechange",
-                           GetConnectionStateString(state));
+  SendPeerConnectionUpdate(
+      id, "connectionstatechange",
+      webrtc::PeerConnectionInterface::AsString(state).data());
 }
 
 void PeerConnectionTracker::TrackIceGatheringStateChange(
@@ -1164,8 +1082,9 @@
   int id = GetLocalIDForHandler(pc_handler);
   if (id == -1)
     return;
-  SendPeerConnectionUpdate(id, "icegatheringstatechange",
-                           GetIceGatheringStateString(state));
+  SendPeerConnectionUpdate(
+      id, "icegatheringstatechange",
+      webrtc::PeerConnectionInterface::AsString(state).data());
 }
 
 void PeerConnectionTracker::TrackSessionDescriptionCallback(
diff --git a/third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.cc b/third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.cc
index cf0ea2b5..e76c1a76 100644
--- a/third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.cc
@@ -73,21 +73,16 @@
   // Bind the read framebuffer to our image.
   StaticBitmapImage* static_image = static_cast<StaticBitmapImage*>(image);
   auto mailbox_holder = static_image->GetMailboxHolder();
+  DCHECK(mailbox_holder.mailbox.IsSharedImage());
 
   // Not strictly necessary since we are on the same context, but keeping
   // for cleanliness and in case we ever move off the same context.
   gl_->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetData());
 
-  GLuint source_texture_id;
-  if (mailbox_holder.mailbox.IsSharedImage()) {
-    source_texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM(
-        mailbox_holder.mailbox.name);
-    gl_->BeginSharedImageAccessDirectCHROMIUM(
-        source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
-  } else {
-    source_texture_id =
-        gl_->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
-  }
+  GLuint source_texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM(
+      mailbox_holder.mailbox.name);
+  gl_->BeginSharedImageAccessDirectCHROMIUM(
+      source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
 
   gl_->BindTexture(GL_TEXTURE_2D, 0);
 
@@ -97,8 +92,7 @@
 
   // Cleanup the read framebuffer, associated image and texture.
   gl_->BindTexture(GL_TEXTURE_2D, 0);
-  if (mailbox_holder.mailbox.IsSharedImage())
-    gl_->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
+  gl_->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
   gl_->DeleteTextures(1, &source_texture_id);
 
   gpu::SyncToken copy_done_sync_token;
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h
index 285bca3..8bcc969 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.h
+++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -44,6 +44,11 @@
     return &ThreadStateStorage::Current()->thread_state();
   }
 
+  // Returns true if the current thread is currently sweeping, i.e., whether the
+  // caller is invoked from a destructor.
+  static ALWAYS_INLINE bool IsSweepingOnOwningThread(
+      ThreadStateStorage& storage);
+
   // Attaches a ThreadState to the main-thread.
   static ThreadState* AttachMainThread();
   // Attaches a ThreadState to the currently running thread. Must not be the
@@ -68,12 +73,6 @@
 
   void NotifyGarbageCollection(v8::GCType, v8::GCCallbackFlags);
 
-  bool InAtomicSweepingPause() const {
-    auto& heap_handle = cpp_heap().GetHeapHandle();
-    return cppgc::subtle::HeapState::IsInAtomicPause(heap_handle) &&
-           cppgc::subtle::HeapState::IsSweeping(heap_handle);
-  }
-
   bool IsAllocationAllowed() const {
     return cppgc::subtle::DisallowGarbageCollectionScope::
         IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
@@ -110,6 +109,12 @@
   bool forced_scheduled_gc_for_testing_ = false;
 };
 
+// static
+bool ThreadState::IsSweepingOnOwningThread(ThreadStateStorage& storage) {
+  return cppgc::subtle::HeapState::IsSweepingOnOwningThread(
+      storage.heap_handle());
+}
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index e68a398..d63b622 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2327,7 +2327,7 @@
     },
     {
       name: "UserAgentClientHintFullVersionList",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "UserAgentReduction",
diff --git a/third_party/blink/web_tests/FlagExpectations/highdpi b/third_party/blink/web_tests/FlagExpectations/highdpi
index c63bf6e..98c3f99 100644
--- a/third_party/blink/web_tests/FlagExpectations/highdpi
+++ b/third_party/blink/web_tests/FlagExpectations/highdpi
@@ -240,7 +240,6 @@
 crbug.com/1179552 fragmentation/single-line-cells-repeating-thead-with-two-captions.html [ Failure ]
 crbug.com/1179552 fragmentation/table-row-page-break-collapsed-border.html [ Failure ]
 
-crbug.com/1179554 html/dialog/removed-element-is-removed-from-top-layer.html [ Failure ]
 crbug.com/1179554 http/tests/css/css-resources-referrer.html [ Failure ]
 crbug.com/1179554 http/tests/csspaint/entire-canvas-visible-zoom.html [ Failure ]
 crbug.com/1179554 http/tests/csspaint/geometry-background-image-zoom.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 46b8781..0c8550a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -916,6 +916,16 @@
 # `text-decoration-skip-ink: all` not implemented yet.
 crbug.com/1054656 external/wpt/css/css-text-decor/text-decoration-skip-ink-005.html [ Skip ]
 
+# `text-decoration: spelling|grammar-error`
+crbug.com/1163436 wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001.html [ Failure ]
+crbug.com/1163436 wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001.optional.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002.optional.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001.optional.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001.optional.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002.optional.html [ Failure ]
+crbug.com/1163436 external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001.optional.html [ Failure ]
+
 crbug.com/722825 media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Pass Skip Timeout ]
 
 #### crbug.com/783229 overflow
@@ -1496,7 +1506,6 @@
 virtual/layout_ng_flex_frag/external/wpt/css/css-break/flexbox/flex-container-fragmentation-004.html [ Pass ]
 virtual/layout_ng_flex_frag/external/wpt/css/css-break/flexbox/flex-container-fragmentation-007.tentative.html [ Pass ]
 virtual/layout_ng_flex_frag/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-012.html [ Pass ]
-virtual/layout_ng_flex_frag/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-013.html [ Pass ]
 virtual/layout_ng_flex_frag/external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-014.html [ Pass ]
 
 ### Tests failing with LayoutNGFlexFragmentation enabled:
@@ -4099,7 +4108,6 @@
 crbug.com/660611 external/wpt/css/css-break/flexbox/flex-container-fragmentation-004.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/flex-container-fragmentation-007.tentative.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-012.html [ Failure ]
-crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-013.html [ Failure ]
 crbug.com/660611 external/wpt/css/css-break/flexbox/single-line-column-flex-fragmentation-014.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/forced-break-at-fragmentainer-start-000.html [ Failure ]
 crbug.com/614667 external/wpt/css/css-break/grid/grid-item-fragmentation-020.html [ Failure ]
@@ -7345,6 +7353,9 @@
 # Flaky on mac 10.13
 crbug.com/1263709 [ Mac10.13 ] http/tests/devtools/elements/node-xpath.js [ Failure ]
 
+# Temporarily disable this test to allow DevTools CL to land: https://crrev.com/c/3306493
+crbug.com/1268754 http/tests/devtools/elements/styles-4/styles-formatting.js [ Failure Pass ]
+
 # Flaky on Mac and Windows
 crbug.com/1272199 external/wpt/websockets/stream/tentative/backpressure-receive.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
 crbug.com/1272203 external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wpt_flags=h2 [ Failure Pass ]
@@ -7375,3 +7386,4 @@
 
 # Sheriff 2021-11-29
 crbug.com/1274458 external/wpt/audio-output/selectAudioOutput-permissions-policy.https.sub.html [ Failure Pass ]
+crbug.com/1239485 [ Mac ] fast/frames/iframe-plugin-load-remove-document-crash.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index d9ff4b0..f1cbd17 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1116,5 +1116,10 @@
     "prefix": "change-service-worker-priority-when-client-foreground-state-change",
     "bases": ["external/wpt/service-workers"],
     "args": ["--enable-features=ChangeServiceWorkerPriorityForClientForegroundStateChange"]
+  },
+  {
+    "prefix": "private-network-access-preflights",
+    "bases": ["external/wpt/fetch/private-network-access"],
+    "args": ["--enable-features=PrivateNetworkAccessRespectPreflightResults"]
   }
 ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index b6b5f97..7d43d67 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -214665,6 +214665,19 @@
         {}
        ]
       ],
+      "multiple-textpaths.svg": [
+       "6df4ecc27bbddaa76709e041620dacdc5c1303bd",
+       [
+        null,
+        [
+         [
+          "/svg/text/reftests/multiple-textpaths-ref.svg",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "no-background.svg": [
        "117b5d6357ff48a3db742d0a5358c622e1e4757d",
        [
@@ -278247,7 +278260,7 @@
          []
         ],
         "drawing-text-to-the-canvas.yaml": [
-         "685946dce591c42dc79c84eddd8bcd5548559918",
+         "8f08c5ef1c70b6b230c14fe88300ccd7dcaa11db",
          []
         ],
         "fill-and-stroke-styles.yaml": [
@@ -278357,7 +278370,7 @@
          []
         ],
         "text.yaml": [
-         "32a45ff14e95a826300c8d777d7e67d45cc66d23",
+         "b65dbe68be73d974496bf43efd82865506f7a72c",
          []
         ],
         "the-canvas-state.yaml": [
@@ -304316,6 +304329,10 @@
       ]
      },
      "reftests": {
+      "multiple-textpaths-ref.svg": [
+       "a6dcd3c5d5e5fe1a9aa74d2539c14e66c95cbece",
+       []
+      ],
       "no-background-ref.svg": [
        "18c6ed4f1bd5905652d209007322dc394769665b",
        []
@@ -410319,6 +410336,20 @@
          {}
         ]
        ],
+       "2d.text.drawing.style.letterSpacing.change.font.html": [
+        "5b42b89e3254c560810e35f1f571d85111503407",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.html": [
+        "fadfaaf2015f4a8a3ec1f51e3def3b474833b409",
+        [
+         null,
+         {}
+        ]
+       ],
        "2d.text.drawing.style.nonfinite.spacing.html": [
         "f197d22afa45d02307b9a0324c64f5013eb3439e",
         [
@@ -410333,15 +410364,22 @@
          {}
         ]
        ],
-       "2d.text.drawing.style.spacing.measure.html": [
-        "9240a0835cdcdd779a75447d0d113e5cca298b11",
+       "2d.text.drawing.style.textRendering.settings.html": [
+        "f6634ee1a0d69b8749864479920e5c3a8f9e9671",
         [
          null,
          {}
         ]
        ],
-       "2d.text.drawing.style.textRendering.settings.html": [
-        "f6634ee1a0d69b8749864479920e5c3a8f9e9671",
+       "2d.text.drawing.style.wordSpacing.change.font.html": [
+        "d29bc8ec203880e7f56015cc94d0e00d96582b9e",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.html": [
+        "4cd3c237cd8db811f6c937d6518db021bd7b27c2",
         [
          null,
          {}
@@ -426623,6 +426661,34 @@
          {}
         ]
        ],
+       "2d.text.drawing.style.letterSpacing.change.font.html": [
+        "cb6b5e3e6030affd94c68791b128446fddf78c6c",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.change.font.worker.js": [
+        "c5f771eb05caa02f8b7ccaa708589e89e8d5f66c",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.change.font.worker.html",
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.html": [
+        "d35b328ad521684fb339bc396a6e551dd4f2e152",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.letterSpacing.measure.worker.js": [
+        "4ca6e3dc860fa406ee7150e631da5a7be55a3f0c",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.letterSpacing.measure.worker.html",
+         {}
+        ]
+       ],
        "2d.text.drawing.style.measure.direction.html": [
         "46355fbe18566aabc31054946e8947d07d7777c0",
         [
@@ -426686,20 +426752,6 @@
          {}
         ]
        ],
-       "2d.text.drawing.style.spacing.measure.html": [
-        "070c93633ab22d649d0ec194b3ccdd68c44d5d47",
-        [
-         null,
-         {}
-        ]
-       ],
-       "2d.text.drawing.style.spacing.measure.worker.js": [
-        "ef03ff52ea6dfeb0e99a771c409afe90f9cea1c0",
-        [
-         "html/canvas/offscreen/text/2d.text.drawing.style.spacing.measure.worker.html",
-         {}
-        ]
-       ],
        "2d.text.drawing.style.spacing.worker.js": [
         "5b5a417f52f7aa9a3cbd6297268988032680b8c0",
         [
@@ -426721,6 +426773,34 @@
          {}
         ]
        ],
+       "2d.text.drawing.style.wordSpacing.change.font.html": [
+        "883f41ccf52d4e8ed82dfb1403932d89b1ff4cc3",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.change.font.worker.js": [
+        "a787045c613dbe3eb05e551a9fd1a2a0e25eca82",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.change.font.worker.html",
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.html": [
+        "96833f53faa248c4155059c0e4424b5271960008",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.text.drawing.style.wordSpacing.measure.worker.js": [
+        "b30926e4e7810959f1eec47652bbeaf88ff6230a",
+        [
+         "html/canvas/offscreen/text/2d.text.drawing.style.wordSpacing.measure.worker.html",
+         {}
+        ]
+       ],
        "2d.text.font.default.html": [
         "0d355729a6bdc843915e4324f07ae26c11aca4f9",
         [
@@ -535434,7 +535514,7 @@
      ]
     ],
     "status-error.htm": [
-     "a9c15c4c51b3a8693ccae0d71acf1ffc4d0b50be",
+     "76709c23d10cfc77509a16a29783deec8a17480e",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001-ref.html
new file mode 100644
index 0000000..2592110
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  span {
+    text-decoration-line: grammar-error;
+  }
+</style>
+
+<p>The test passes if "quikc" has a grammar error marker that is not the default color (usually green).</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001.optional.html
new file mode 100644
index 0000000..6309d73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-001.optional.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: grammar-error color</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error">
+<meta name="assert" content="This test checks that it is possible to tweak the color of 'text-decoration-line: grammar-error' with 'text-decoration-color' property.">
+<link rel="mismatch" href="text-decoration-line-grammar-error-color-001-ref.html">
+<style>
+  span {
+    text-decoration-line: grammar-error;
+    text-decoration-color: rgba(200, 225, 50, 0.75);
+  }
+</style>
+
+<p>The test passes if "quikc" has a grammar error marker that is not the default color (usually green).</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002-ref.html
new file mode 100644
index 0000000..2416ba8d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  div {
+    padding: 10px;
+    background: cyan;
+  }
+</style>
+
+<p>The test passes if you cannot see a grammar error marker in the next sentence.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002.optional.html
new file mode 100644
index 0000000..1758933
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-002.optional.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: grammar-error color</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error">
+<meta name="assert" content="This test checks that it is possible to tweak the color of 'text-decoration-line: grammar-error' with 'text-decoration-color' property.">
+<link rel="match" href="text-decoration-line-grammar-error-color-002-ref.html">
+<style>
+  div {
+    padding: 10px;
+    background: cyan;
+  }
+
+  span {
+    text-decoration-line: grammar-error;
+    text-decoration-color: transparent;
+  }
+</style>
+
+<p>The test passes if you cannot see a grammar error marker in the next sentence.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001-ref.html
new file mode 100644
index 0000000..e54b6814
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  span {
+    text-decoration-line: grammar-error;
+    text-decoration-color: magenta;
+  }
+</style>
+
+<p>The test passes if "quikc" has a magenta grammar error marker.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001.optional.html
new file mode 100644
index 0000000..58ff6ae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-grammar-error-color-dynamic-001.optional.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: grammar-error color dynamic</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error">
+<meta name="assert" content="This test checks that it is possible to dinamically tweak the color of 'text-decoration-line: grammar-error' with 'text-decoration-color' property.">
+<link rel="match" href="text-decoration-line-grammar-error-color-dynamic-001-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  span {
+    text-decoration-line: grammar-error;
+    text-decoration-color: cyan;
+  }
+</style>
+
+<p>The test passes if "quikc" has a magenta grammar error marker.</p>
+<div>The <span id="target">quikc</span> brown fox.</div>
+
+<script>
+  requestAnimationFrame(() => requestAnimationFrame(() => {
+    target.style.textDecorationColor = "magenta";
+    takeScreenshot();
+  }));
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001-ref.html
new file mode 100644
index 0000000..9cd5199
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  span {
+    text-decoration-line: spelling-error;
+  }
+</style>
+
+<p>The test passes if "quikc" has a spelling error marker that is not the default color (usually red).</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001.optional.html
new file mode 100644
index 0000000..5e5475fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-001.optional.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: spelling-error color</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error">
+<meta name="assert" content="This test checks that it is possible to tweak the color of 'text-decoration-line: spelling-error' with 'text-decoration-color' property.">
+<link rel="mismatch" href="text-decoration-line-spelling-error-color-001-ref.html">
+<style>
+  span {
+    text-decoration-line: spelling-error;
+    text-decoration-color: rgba(200, 225, 50, 0.75);
+  }
+</style>
+
+<p>The test passes if "quikc" has a spelling error marker that is not the default color (usually red).</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002-ref.html
new file mode 100644
index 0000000..b8bd681
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  div {
+    padding: 10px;
+    background: cyan;
+  }
+</style>
+
+<p>The test passes if you cannot see a spelling error marker in the next sentence.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002.optional.html
new file mode 100644
index 0000000..3a87976
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-002.optional.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: spelling-error color</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error">
+<meta name="assert" content="This test checks that it is possible to tweak the color of 'text-decoration-line: spelling-error' with 'text-decoration-color' property.">
+<link rel="match" href="text-decoration-line-spelling-error-color-002-ref.html">
+<style>
+  div {
+    padding: 10px;
+    background: cyan;
+  }
+
+  span {
+    text-decoration-line: spelling-error;
+    text-decoration-color: transparent;
+  }
+</style>
+
+<p>The test passes if you cannot see a spelling error marker in the next sentence.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001-ref.html
new file mode 100644
index 0000000..e96898a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  span {
+    text-decoration-line: spelling-error;
+    text-decoration-color: magenta;
+  }
+</style>
+
+<p>The test passes if "quikc" has a magenta spelling error marker.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001.optional.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001.optional.html
new file mode 100644
index 0000000..d712e35
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-line-spelling-error-color-dynamic-001.optional.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: spelling-error color dynamic</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error">
+<meta name="assert" content="This test checks that it is possible to dinamically tweak the color of 'text-decoration-line: spelling-error' with 'text-decoration-color' property.">
+<link rel="match" href="text-decoration-line-spelling-error-color-dynamic-001-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+  span {
+    text-decoration-line: spelling-error;
+    text-decoration-color: cyan;
+  }
+</style>
+
+<p>The test passes if "quikc" has a magenta spelling error marker.</p>
+<div>The <span id="target">quikc</span> brown fox.</div>
+
+<script>
+  requestAnimationFrame(() => requestAnimationFrame(() => {
+    target.style.textDecorationColor = "magenta";
+    takeScreenshot();
+  }));
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt
index 1011609..b9730893 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window-expected.txt
@@ -1,22 +1,22 @@
 This is a testharness.js-based test.
-PASS Local non-secure context can fetch local subresource.
-PASS Local non-secure context can fetch private subresource.
-PASS Local non-secure context can fetch public subresource.
-PASS Private non-secure context cannot fetch local subresource.
-PASS Private non-secure context can fetch private subresource.
-PASS Private non-secure context can fetch public subresource.
-PASS Public non-secure context cannot fetch local subresource.
-PASS Public non-secure context cannot fetch private subresource.
-PASS Public non-secure context can fetch public subresource.
-PASS Treat-as-public-address non-secure context cannot fetch local subresource.
-PASS Treat-as-public-address non-secure context cannot fetch private subresource.
-PASS Treat-as-public-address non-secure context can fetch public subresource.
-PASS Private HTTPS non-secure context cannot fetch local subresource.
-PASS Public HTTPS non-secure context cannot fetch local subresource.
-PASS Public HTTPS non-secure context cannot fetch private subresource.
-PASS Local non-secure context can open connection to ws://localhost.
-FAIL Private non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
-FAIL Public non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
-FAIL Treat-as-public non-secure context cannot open connection to ws://localhost. assert_equals: expected "close: code 1006" but got "open"
+PASS local to local: no preflight required.
+PASS local to private: no preflight required.
+PASS local to public: no preflight required.
+PASS private to local: failure.
+PASS private to private: no preflight required.
+PASS private to public: no preflight required.
+PASS public to local: failure.
+PASS public to private: failure.
+PASS public to public: no preflight required.
+PASS treat-as-public-address to local: failure.
+PASS treat-as-public-address to private: failure.
+PASS treat-as-public-address to public: no preflight required.
+PASS private https to local: failure.
+PASS public https to local: failure.
+PASS public https to private: failure.
+PASS local to local: websocket success.
+FAIL private to local: websocket failure. assert_equals: expected "close: code 1006" but got "open"
+FAIL public to local: websocket failure. assert_equals: expected "close: code 1006" but got "open"
+FAIL treat-as-public to local: websocket failure. assert_equals: expected "close: code 1006" but got "open"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
index 6b2b6be..e81dfb61 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/non-secure-context.window.js
@@ -1,3 +1,4 @@
+// META: script=/common/utils.js
 // META: script=resources/support.js
 // META: script=resources/ports.sub.js
 //
@@ -18,55 +19,85 @@
   source: { port: kPorts.httpLocal },
   target: { port: kPorts.httpLocal },
   expected: kFetchTestResult.success,
-}), "Local non-secure context can fetch local subresource.");
+}), "local to local: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpLocal },
-  target: { port: kPorts.httpPrivate },
+  target: {
+    port: kPorts.httpPrivate,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Local non-secure context can fetch private subresource.");
+}), "local to private: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpLocal },
-  target: { port: kPorts.httpPublic },
+  target: {
+    port: kPorts.httpPublic,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Local non-secure context can fetch public subresource.");
+}), "local to public: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPrivate },
-  target: { port: kPorts.httpLocal },
+  target: {
+    port: kPorts.httpLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.failure,
-}), "Private non-secure context cannot fetch local subresource.");
+}), "private to local: failure.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPrivate },
   target: { port: kPorts.httpPrivate },
   expected: kFetchTestResult.success,
-}), "Private non-secure context can fetch private subresource.");
+}), "private to private: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPrivate },
-  target: { port: kPorts.httpPublic },
+  target: {
+    port: kPorts.httpPublic,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Private non-secure context can fetch public subresource.");
+}), "private to public: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPublic },
-  target: { port: kPorts.httpLocal },
+  target: {
+    port: kPorts.httpLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.failure,
-}), "Public non-secure context cannot fetch local subresource.");
+}), "public to local: failure.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPublic },
-  target: { port: kPorts.httpPrivate },
+  target: {
+    port: kPorts.httpPrivate,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.failure,
-}), "Public non-secure context cannot fetch private subresource.");
+}), "public to private: failure.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpPublic },
   target: { port: kPorts.httpPublic },
   expected: kFetchTestResult.success,
-}), "Public non-secure context can fetch public subresource.");
+}), "public to public: no preflight required.");
 
 // These tests verify that documents fetched from the `local` address space yet
 // carrying the `treat-as-public-address` CSP directive are treated as if they
@@ -75,29 +106,46 @@
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
-  target: { port: kPorts.httpLocal },
+  target: {
+    port: kPorts.httpLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.failure,
-}), "Treat-as-public-address non-secure context cannot fetch local subresource.");
+}), "treat-as-public-address to local: failure.");
 
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
-  target: { port: kPorts.httpPrivate },
+  target: {
+    port: kPorts.httpPrivate,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.failure,
-}), "Treat-as-public-address non-secure context cannot fetch private subresource.");
+}), "treat-as-public-address to private: failure.");
 
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
-  target: { port: kPorts.httpPublic },
+  target: {
+    port: kPorts.httpPublic,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Treat-as-public-address non-secure context can fetch public subresource.");
+}), "treat-as-public-address to public: no preflight required.");
 
 // These tests verify that HTTPS iframes embedded in an HTTP top-level document
 // cannot fetch subresources from less-public address spaces. Indeed, even
@@ -112,9 +160,14 @@
   target: {
     protocol: "https:",
     port: kPorts.httpsLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
   },
   expected: kFetchTestResult.failure,
-}), "Private HTTPS non-secure context cannot fetch local subresource.");
+}), "private https to local: failure.");
 
 promise_test(t => fetchTest(t, {
   source: {
@@ -124,9 +177,14 @@
   target: {
     protocol: "https:",
     port: kPorts.httpsLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
   },
   expected: kFetchTestResult.failure,
-}), "Public HTTPS non-secure context cannot fetch local subresource.");
+}), "public https to local: failure.");
 
 promise_test(t => fetchTest(t, {
   source: {
@@ -136,9 +194,14 @@
   target: {
     protocol: "https:",
     port: kPorts.httpsPrivate,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
   },
   expected: kFetchTestResult.failure,
-}), "Public HTTPS non-secure context cannot fetch private subresource.");
+}), "public https to private: failure.");
 
 // These tests verify that websocket connections behave similarly to fetches.
 
@@ -151,7 +214,7 @@
     port: kPorts.wsLocal,
   },
   expected: kWebsocketTestResult.success,
-}), "Local non-secure context can open connection to ws://localhost.");
+}), "local to local: websocket success.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -162,7 +225,7 @@
     port: kPorts.wsLocal,
   },
   expected: kWebsocketTestResult.failure,
-}), "Private non-secure context cannot open connection to ws://localhost.");
+}), "private to local: websocket failure.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -173,7 +236,7 @@
     port: kPorts.wsLocal,
   },
   expected: kWebsocketTestResult.failure,
-}), "Public non-secure context cannot open connection to ws://localhost.");
+}), "public to local: websocket failure.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -185,4 +248,4 @@
     port: kPorts.wsLocal,
   },
   expected: kWebsocketTestResult.failure,
-}), "Treat-as-public non-secure context cannot open connection to ws://localhost.");
+}), "treat-as-public to local: websocket failure.");
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/fetcher.html b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/fetcher.html
index 6fc321f..000a5cc 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/fetcher.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/fetcher.html
@@ -3,8 +3,19 @@
 <title>Fetcher</title>
 <script>
   window.addEventListener("message", function (event) {
-    fetch(event.data)
-        .then(response => { parent.postMessage(response.ok, "*") })
-        .catch(error => { parent.postMessage(error.toString(), "*") });
+    const { url, options } = event.data;
+    fetch(url, options)
+        .then(async function(response) {
+          const body = await response.text();
+          const message = {
+            ok: response.ok,
+            type: response.type,
+            body: body,
+          };
+          parent.postMessage(message, "*");
+        })
+        .catch(error => {
+          parent.postMessage({ error: error.toString() }, "*");
+        });
   });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/preflight.py b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/preflight.py
new file mode 100644
index 0000000..4181210
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/preflight.py
@@ -0,0 +1,76 @@
+# This endpoint responds to both preflight requests and the subsequent requests.
+#
+# Its behavior can be configured with the following search/GET parameters:
+#
+# - preflight-uuid: Optional, must be a valid UUID if set.
+#   If set, then this endpoint expects to receive a preflight request first
+#   followed by a regular request, as in the regular CORS protocol.
+#   If unset, then this endpoint expects to receive no preflight request, only
+#   a regular (non-OPTIONS) request.
+# - preflight-headers: Optional, valid values are:
+#   - cors: this endpoint responds with valid CORS headers to preflights. These
+#     should be sufficient for non-PNA preflight requests to succeed, but not
+#     for PNA-specific preflight requests.
+#   - cors+pna: this endpoint responds with valid CORS and PNA headers to
+#     preflights. These should be sufficient for both non-PNA preflight
+#     requests and PNA-specific preflight requests to succeed.
+#   - unspecified, or any other value: this endpoint responds with no CORS or
+#     PNA headers. Preflight requests should fail.
+# - final-headers: Optional, valid values are:
+#   - cors: this endpoint responds with valid CORS headers to CORS-enabled
+#     non-preflight requests. These should be sufficient for non-preflighted
+#     CORS-enabled requests to succeed.
+#   - unspecified: this endpoint responds with no CORS headers to non-preflight
+#     requests. This should fail CORS-enabled requests, but be sufficient for
+#     no-CORS requests.
+#
+
+_ACAO = ("Access-Control-Allow-Origin", "*")
+_ACAPN = ("Access-Control-Allow-Private-Network", "true")
+
+def _get_response_headers(method, mode):
+  acam = ("Access-Control-Allow-Methods", method)
+
+  if mode == b"cors":
+    return [acam, _ACAO]
+
+  if mode == b"cors+pna":
+    return [acam, _ACAO, _ACAPN]
+
+  return []
+
+def _get_uuid(request):
+  return request.GET.get(b"preflight-uuid")
+
+def _handle_preflight_request(request, response):
+  uuid = _get_uuid(request)
+  if uuid is None:
+    raise Exception("missing `preflight-uuid` param from preflight URL")
+
+  request.server.stash.put(uuid, "")
+
+  method = request.headers.get("Access-Control-Request-Method")
+  mode = request.GET.get(b"preflight-headers")
+  headers = _get_response_headers(method, mode)
+
+  return (headers, "preflight")
+
+def _handle_final_request(request, response):
+  uuid = _get_uuid(request)
+  if uuid is not None and request.server.stash.take(uuid) is None:
+    raise Exception("no matching preflight request for {}".format(uuid))
+
+  mode = request.GET.get(b"final-headers")
+  headers = _get_response_headers(request.method, mode)
+
+  return (headers, "success")
+
+def main(request, response):
+  try:
+    if request.method == "OPTIONS":
+      return _handle_preflight_request(request, response)
+    else:
+      return _handle_final_request(request, response)
+  except BaseException as e:
+    # Surface exceptions to the client, where they show up as assertion errors.
+    return ([("X-exception", str(e))], "")#"exception: {}".format(e))
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
index 16494bf..e9e70fc 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.js
@@ -32,9 +32,6 @@
   });
 };
 
-const kTreatAsPublicAddressSuffix =
-      "?pipe=header(Content-Security-Policy,treat-as-public-address)";
-
 // Resolves a URL relative to the current location, returning an absolute URL.
 //
 // `url` specifies the relative URL, e.g. "foo.html" or "http://foo.example".
@@ -47,10 +44,11 @@
 //     // Optional. Overrides the port of the returned URL.
 //     port,
 //
-//     // Optional boolean. If defined and true, the returned URL path is altered
-//     // such that the response is served with a `treat-as-public-address` CSP
-//     // directive.
-//     treatAsPublicAddress,
+//     // Extra headers.
+//     headers,
+//
+//     // Extra search params.
+//     searchParams,
 //   }
 //
 function resolveUrl(url, options) {
@@ -59,24 +57,42 @@
     return result;
   }
 
-  const { port, protocol, treatAsPublicAddress } = options;
+  const { port, protocol, headers, searchParams } = options;
   if (port !== undefined) {
     result.port = port;
   }
   if (protocol !== undefined) {
     result.protocol = protocol;
   }
-  if (treatAsPublicAddress) {
-    result.searchParams.append(
-        "pipe", "header(Content-Security-Policy,treat-as-public-address)");
+  if (headers !== undefined) {
+    const pipes = [];
+    for (key in headers) {
+      pipes.push(`header(${key},${headers[key]})`);
+    }
+    result.searchParams.append("pipe", pipes.join("|"));
+  }
+  if (searchParams !== undefined) {
+    for (key in searchParams) {
+      result.searchParams.append(key, searchParams[key]);
+    }
   }
 
   return result;
 }
 
 const kFetchTestResult = {
-  success: true,
-  failure: "TypeError: Failed to fetch",
+  success: {
+    ok: true,
+    body: "success",
+  },
+  opaque: {
+    ok: false,
+    type: "opaque",
+    body: "",
+  },
+  failure: {
+    error: "TypeError: Failed to fetch",
+  },
 }
 
 // Runs a fetch test. Tries to fetch a given subresource from a given document.
@@ -88,20 +104,40 @@
 //     source,
 //
 //     // Optional. Options for `resolveUrl()` when computing the target URL.
+//     // See the documentation of `resources/preflight.py` for details on
+//     // valid `searchParams` and their effect.
 //     target,
 //
+//     // Fetch options.
+//     fetchOptions,
+//
 //     // Required. One of the values in `kFetchTestResult`.
 //     expected,
 //   }
 //
-async function fetchTest(t, { source, target, expected }) {
+async function fetchTest(t, { source, target, fetchOptions, expected }) {
   const sourceUrl = resolveUrl("resources/fetcher.html", source);
   const iframe = await appendIframe(t, document, sourceUrl);
 
-  const targetUrl = resolveUrl("/common/blank-with-cors.html", target);
+  const targetUrl = resolveUrl("resources/preflight.py", target);
+  const message = {
+    url: targetUrl.href,
+    options: fetchOptions,
+  };
+
   const reply = futureMessage();
-  iframe.contentWindow.postMessage(targetUrl.href, "*");
-  assert_equals(await reply, expected);
+  iframe.contentWindow.postMessage(message, "*");
+
+  const { error, ok, type, body } = await reply;
+
+  assert_equals(error, expected.error, "error");
+
+  assert_equals(ok, expected.ok, "response ok");
+  assert_equals(body, expected.body, "response body");
+
+  if (expected.type !== undefined) {
+    assert_equals(type, expected.type, "response type");
+  }
 }
 
 const kWebsocketTestResult = {
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt
new file mode 100644
index 0000000..b508d89
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt
@@ -0,0 +1,50 @@
+This is a testharness.js-based test.
+PASS local to local: no preflight required.
+PASS local to private: no preflight required.
+PASS local to public: no preflight required.
+PASS local to public: PUT preflight failure.
+PASS local to public: PUT preflight success,
+FAIL private to local: failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS private to local: missing CORS headers on preflight response.
+PASS private to local: missing PNA header on preflight response.
+PASS private to local: missing CORS headers on final response.
+FAIL private to local: success. assert_equals: error expected (undefined) undefined but got (string) "TypeError: Failed to fetch"
+PASS private to local: PUT success.
+FAIL private to local: no-CORS mode failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL private to local: no-CORS mode missing CORS headers on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL private to local: no-CORS mode missing PNA header on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS private to local: no-CORS mode success.
+PASS private to private: no preflight required.
+PASS private to public: no preflight required.
+FAIL public to local: failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS public to local: missing CORS headers on preflight response.
+PASS public to local: missing PNA header on preflight response.
+PASS public to local: missing CORS headers on final response.
+FAIL public to local: success. assert_equals: error expected (undefined) undefined but got (string) "TypeError: Failed to fetch"
+PASS public to local: PUT success.
+FAIL public to local: no-CORS mode failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL public to local: no-CORS mode missing CORS headers on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL public to local: no-CORS mode missing PNA header on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS public to local: no-CORS mode success.
+FAIL public to private: failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS public to private: missing CORS headers on preflight response.
+PASS public to private: missing PNA header on preflight response.
+PASS public to private: missing CORS headers on final response.
+FAIL public to private: success. assert_equals: error expected (undefined) undefined but got (string) "TypeError: Failed to fetch"
+PASS public to private: PUT success.
+FAIL public to private: no-CORS mode failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL public to private: no-CORS mode missing CORS headers on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL public to private: no-CORS mode missing PNA header on preflight response. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+PASS public to private: no-CORS mode success.
+PASS public to public: no preflight required.
+FAIL treat-as-public-address to local: failed preflight. assert_equals: error expected (string) "TypeError: Failed to fetch" but got (undefined) undefined
+FAIL treat-as-public-address to local: success. assert_equals: response body expected "success" but got ""
+PASS treat-as-public-address to private: failed preflight.
+FAIL treat-as-public-address to private: success. assert_equals: error expected (undefined) undefined but got (string) "TypeError: Failed to fetch"
+PASS treat-as-public-address to public: no preflight required.
+PASS local to local: websocket success.
+PASS private to local: websocket success.
+PASS public to local: websocket success.
+PASS treat-as-public to local: websocket success.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
index 1218700..f5714be 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/secure-context.https.window.js
@@ -1,3 +1,4 @@
+// META: script=/common/utils.js
 // META: script=resources/support.js
 // META: script=resources/ports.sub.js
 //
@@ -14,59 +15,246 @@
 // These tests verify that secure contexts can fetch subresources from all
 // address spaces.
 
+// Source: secure local context.
+//
+// All fetches unaffected by Private Network Access.
+
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsLocal },
   target: { port: kPorts.httpsLocal },
   expected: kFetchTestResult.success,
-}), "Local secure context can fetch local subresource.");
+}), "local to local: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsLocal },
-  target: { port: kPorts.httpsPrivate },
+  target: {
+    port: kPorts.httpsPrivate,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Local secure context can fetch private subresource.");
+}), "local to private: no preflight required.");
+
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsLocal },
-  target: { port: kPorts.httpsPublic },
+  target: {
+    port: kPorts.httpsPublic,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Local secure context can fetch public subresource.");
+}), "local to public: no preflight required.");
+
+// Strictly speaking, the following two tests do not exercise PNA-specific
+// logic, but they serve as a baseline for comparison, ensuring that non-PNA
+// preflight requests are sent and handled as expected.
 
 promise_test(t => fetchTest(t, {
+  source: { port: kPorts.httpsLocal },
+  target: {
+    port: kPorts.httpsPublic,
+    searchParams: {
+      // Missing "preflight-uuid" param: preflight will fail.
+      "preflight-headers": "cors",
+      "final-headers": "cors",
+    },
+  },
+  fetchOptions: { method: "PUT" },
+  expected: kFetchTestResult.failure,
+}), "local to public: PUT preflight failure.");
+
+promise_test(t => fetchTest(t, {
+  source: { port: kPorts.httpsLocal },
+  target: {
+    port: kPorts.httpsPublic,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors",
+      "final-headers": "cors",
+    },
+  },
+  fetchOptions: { method: "PUT" },
+  expected: kFetchTestResult.success,
+}), "local to public: PUT preflight success,");
+
+// Source: private secure context.
+//
+// Fetches to the local address space require a successful preflight response
+// carrying a PNA-specific header.
+
+function makePreflightTests({
+  source,
+  sourceDescription,
+  targetPort,
+  targetDescription,
+}) {
+  const prefix =
+      `${sourceDescription} to ${targetDescription}: `;
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        // Missing "preflight-uuid" param: preflight will fail.
+        "preflight-headers": "cors+pna",
+        "final-headers": "cors",
+      },
+    },
+    expected: kFetchTestResult.failure,
+  }), prefix + "failed preflight.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+      },
+    },
+    expected: kFetchTestResult.failure,
+  }), prefix + "missing CORS headers on preflight response.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors",
+      },
+    },
+    expected: kFetchTestResult.failure,
+  }), prefix + "missing PNA header on preflight response.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors+pna",
+      },
+    },
+    expected: kFetchTestResult.failure,
+  }), prefix + "missing CORS headers on final response.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors+pna",
+        "final-headers": "cors",
+      },
+    },
+    expected: kFetchTestResult.success,
+  }), prefix + "success.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors+pna",
+        "final-headers": "cors",
+      },
+    },
+    fetchOptions: { method: "PUT" },
+    expected: kFetchTestResult.success,
+  }), prefix + "PUT success.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: { port: targetPort },
+    fetchOptions: { mode: "no-cors" },
+    expected: kFetchTestResult.failure,
+  }), prefix + "no-CORS mode failed preflight.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: { "preflight-uuid": token() },
+    },
+    fetchOptions: { mode: "no-cors" },
+    expected: kFetchTestResult.failure,
+  }), prefix + "no-CORS mode missing CORS headers on preflight response.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors",
+      },
+    },
+    fetchOptions: { mode: "no-cors" },
+    expected: kFetchTestResult.failure,
+  }), prefix + "no-CORS mode missing PNA header on preflight response.");
+
+  promise_test(t => fetchTest(t, {
+    source,
+    target: {
+      port: targetPort,
+      searchParams: {
+        "preflight-uuid": token(),
+        "preflight-headers": "cors+pna",
+      },
+    },
+    fetchOptions: { mode: "no-cors" },
+    expected: kFetchTestResult.opaque,
+  }), prefix + "no-CORS mode success.");
+}
+
+makePreflightTests({
   source: { port: kPorts.httpsPrivate },
-  target: { port: kPorts.httpsLocal },
-  expected: kFetchTestResult.success,
-}), "Private secure context can fetch local subresource.");
+  sourceDescription: "private",
+  targetPort: kPorts.httpsLocal,
+  targetDescription: "local",
+});
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsPrivate },
   target: { port: kPorts.httpsPrivate },
   expected: kFetchTestResult.success,
-}), "Private secure context can fetch private subresource.");
+}), "private to private: no preflight required.");
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsPrivate },
-  target: { port: kPorts.httpsPublic },
+  target: {
+    port: kPorts.httpsPublic,
+    searchParams: { "final-headers": "cors" },
+  },
   expected: kFetchTestResult.success,
-}), "Private secure context can fetch public subresource.");
+}), "private to public: no preflight required.");
 
-promise_test(t => fetchTest(t, {
-  source: { port: kPorts.httpsPublic },
-  target: { port: kPorts.httpsLocal },
-  expected: kFetchTestResult.success,
-}), "Public secure context can fetch local subresource.");
+// Source: public secure context.
+//
+// Fetches to the local and private address spaces require a successful
+// preflight response carrying a PNA-specific header.
 
-promise_test(t => fetchTest(t, {
+makePreflightTests({
   source: { port: kPorts.httpsPublic },
-  target: { port: kPorts.httpsPrivate },
-  expected: kFetchTestResult.success,
-}), "Public secure context can fetch private subresource.");
+  sourceDescription: "public",
+  targetPort: kPorts.httpsLocal,
+  targetDescription: "local",
+});
+
+makePreflightTests({
+  source: { port: kPorts.httpsPublic },
+  sourceDescription: "public",
+  targetPort: kPorts.httpsPrivate,
+  targetDescription: "private",
+});
 
 promise_test(t => fetchTest(t, {
   source: { port: kPorts.httpsPublic },
   target: { port: kPorts.httpsPublic },
   expected: kFetchTestResult.success,
-}), "Public secure context can fetch public subresource.");
+}), "public to public: no preflight required.");
 
 // These tests verify that documents fetched from the `local` address space yet
 // carrying the `treat-as-public-address` CSP directive are treated as if they
@@ -75,29 +263,66 @@
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpsLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
   target: { port: kPorts.httpsLocal },
-  expected: kFetchTestResult.success,
-}), "Treat-as-public-address secure context can fetch local subresource.");
+  expected: kFetchTestResult.failure,
+}), "treat-as-public-address to local: failed preflight.");
 
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpsLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
+  },
+  target: {
+    port: kPorts.httpsLocal,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      // Interesting: no need for CORS headers on same-origin final response.
+    },
+  },
+  expected: kFetchTestResult.success,
+}), "treat-as-public-address to local: success.");
+
+promise_test(t => fetchTest(t, {
+  source: {
+    port: kPorts.httpsLocal,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
   target: { port: kPorts.httpsPrivate },
-  expected: kFetchTestResult.success,
-}), "Treat-as-public-address secure context can fetch private subresource.");
+  expected: kFetchTestResult.failure,
+}), "treat-as-public-address to private: failed preflight.");
 
 promise_test(t => fetchTest(t, {
   source: {
     port: kPorts.httpsLocal,
-    treatAsPublicAddress: true,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
   },
-  target: { port: kPorts.httpsPublic },
+  target: {
+    port: kPorts.httpsPrivate,
+    searchParams: {
+      "preflight-uuid": token(),
+      "preflight-headers": "cors+pna",
+      "final-headers": "cors",
+    },
+  },
   expected: kFetchTestResult.success,
-}), "Treat-as-public-address secure context can fetch public subresource.");
+}), "treat-as-public-address to private: success.");
+
+promise_test(t => fetchTest(t, {
+  source: {
+    port: kPorts.httpsLocal,
+    headers: { "Content-Security-Policy": "treat-as-public-address" },
+  },
+  target: {
+    port: kPorts.httpsPublic,
+    searchParams: {
+      "final-headers": "cors",
+    }
+  },
+  expected: kFetchTestResult.success,
+}), "treat-as-public-address to public: no preflight required.");
 
 // These tests verify that websocket connections behave similarly to fetches.
 
@@ -111,7 +336,7 @@
     port: kPorts.wssLocal,
   },
   expected: kWebsocketTestResult.success,
-}), "Local secure context can open connection to wss://localhost.");
+}), "local to local: websocket success.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -123,7 +348,7 @@
     port: kPorts.wssLocal,
   },
   expected: kWebsocketTestResult.success,
-}), "Private secure context can open connection to wss://localhost.");
+}), "private to local: websocket success.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -135,7 +360,7 @@
     port: kPorts.wssLocal,
   },
   expected: kWebsocketTestResult.success,
-}), "Public secure context can open connection to wss://localhost.");
+}), "public to local: websocket success.");
 
 promise_test(t => websocketTest(t, {
   source: {
@@ -148,4 +373,4 @@
     port: kPorts.wssLocal,
   },
   expected: kWebsocketTestResult.success,
-}), "Treat-as-public secure context can open connection to wss://localhost.");
+}), "treat-as-public to local: websocket success.");
diff --git a/third_party/blink/web_tests/external/wpt/xhr/status-error.htm b/third_party/blink/web_tests/external/wpt/xhr/status-error.htm
index a9c15c4..76709c2 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/status-error.htm
+++ b/third_party/blink/web_tests/external/wpt/xhr/status-error.htm
@@ -33,6 +33,30 @@
         })
       }
 
+      function unknownScheme() {
+        test(() => {
+          var client = new XMLHttpRequest();
+          client.open("GET", "foobar://dummy", false);
+          try {
+            client.send();
+          } catch(ex) {}
+          assert_equals(client.status, 0, "response data");
+        }, "Unknown scheme");
+      }
+
+
+      function postOnBlob() {
+        test(() => {
+          var u = URL.createObjectURL(new Blob([""], {type: 'text/plain'}));
+          var client = new XMLHttpRequest();
+          client.open("POST", u, false);
+          try {
+            client.send();
+          } catch(ex) {}
+          assert_equals(client.status, 0, "response data");
+        }, "POST on blob uri");
+      }
+
       noError('GET', 200)
       noError('GET', 400)
       noError('GET', 401)
@@ -55,6 +79,9 @@
       noError('PUT', 404)
       noError('PUT', 500)
       noError('PUT', 699)
+
+      unknownScheme();
+      postOnBlob();
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error.html b/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error.html
new file mode 100644
index 0000000..d0705bb
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error.html
@@ -0,0 +1,14 @@
+<!DOCTYPE>
+<style>
+  div {
+    text-decoration-line: grammar-error;
+    margin: 1em 10px;
+  }
+</style>
+<div style="font-size: 10px;">10px font size</div>
+<div style="font-size: 12px;">12px font size</div>
+<div style="font-size: 15px;">15px font size</div>
+<div style="font-size: 20px;">20px font size</div>
+<div style="font-size: 30px;">30px font size</div>
+<div style="font-size: 50px;">50px font size</div>
+<div style="font-size: 100px;">100px font size</div>
diff --git a/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error.html b/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error.html
new file mode 100644
index 0000000..d141d38
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error.html
@@ -0,0 +1,14 @@
+<!DOCTYPE>
+<style>
+  div {
+    text-decoration-line: spelling-error;
+    margin: 1em 10px;
+  }
+</style>
+<div style="font-size: 10px;">10px font size</div>
+<div style="font-size: 12px;">12px font size</div>
+<div style="font-size: 15px;">15px font size</div>
+<div style="font-size: 20px;">20px font size</div>
+<div style="font-size: 30px;">30px font size</div>
+<div style="font-size: 50px;">50px font size</div>
+<div style="font-size: 100px;">100px font size</div>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector-expected.html b/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector-expected.html
deleted file mode 100644
index 70d84c2..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector-expected.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-.backdrop {
-    position: absolute;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-</style>
-</head>
-<body>
-Test ::backdrop used in descendant selectors. The test passes if there are two green boxes and no red.
-<div class="backdrop" style="top: 100px; left: 100px"></div>
-<div class="backdrop" style="top: 100px; left: 300px"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector.html b/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector.html
deleted file mode 100644
index 06a0347..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-descendant-selector.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    visibility: hidden;
-}
-
-::backdrop {
-    position: absolute;
-    height: 100px;
-    width: 100px;
-    background: red;
-}
-
-/* This shouldn't be matched, dialog is not the parent of ::backdrop.
- * It is given high specificity so we actually test something.
- */
-#dialog-parent > #dialog > ::backdrop,
-#dialog-parent > #dialog ::backdrop {
-    background: red;
-}
-
-#dialog-parent > ::backdrop {
-    top: 100px;
-    left: 100px;
-    background: green;
-}
-
-#backdrop-ancestor ::backdrop {
-    top: 100px;
-    left: 300px;
-    background: green;
-}
-</style>
-</head>
-<body>
-Test ::backdrop used in descendant selectors. The test passes if there are two green boxes and no red.
-
-<div id="dialog-parent">
-    <dialog id="dialog"></dialog>
-</div>
-<div id="backdrop-ancestor">
-    <p><span><dialog></dialog></span></p>
-</div>
-<script>
-var dialogs = document.querySelectorAll('dialog');
-for (var i = 0; i < dialogs.length; ++i)
-    dialogs[i].showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit-expected.html b/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit-expected.html
deleted file mode 100644
index bdc8418..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit-expected.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<style>
-#backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-</style>
-<body>
-Test that ::backdrop does not inherit from anything. The test passes if there is
-a green box and no red.
-<div id="backdrop"></div>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit.html b/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit.html
deleted file mode 100644
index 725c448d..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-does-not-inherit.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog {
-    visibility: inherit;
-    background: red;
-}
-
-dialog::backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    visibility: inherit;
-    background: green;
-}
-</style>
-<body>
-Test that ::backdrop does not inherit from anything. The test passes if there is
-a green box and no red.
-<div style="visibility: hidden">
-    <dialog></dialog>
-</div>
-<script>
-document.querySelector('dialog').showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change-expected.html b/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change-expected.html
deleted file mode 100644
index 01cb93d..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change-expected.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-.backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background-color: green;
-}
-</style>
-</head>
-<body>
-Test dynamic changes to ::backdrop style. The test passes if there is a green box below.
-<div class="backdrop"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change.html b/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change.html
deleted file mode 100644
index 6e6967d..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-dynamic-style-change.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    visibility: hidden;
-}
-
-::backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background-color: red;
-}
-
-.green::backdrop {
-    background-color: green;
-}
-</style>
-</head>
-<body>
-Test dynamic changes to ::backdrop style. The test passes if there is a green box below.
-<dialog></dialog>
-<script>
-dialog = document.querySelector('dialog');
-dialog.showModal();
-dialog.classList.add('green');
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-in-flow-expected.html b/third_party/blink/web_tests/html/dialog/backdrop-in-flow-expected.html
deleted file mode 100644
index 4857557..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-in-flow-expected.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<style>
-#backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-</style>
-<body>
-Test that position 'static' or 'relative' for ::backdrop computes to 'absolute'.
-The test passes if there is a single green box.
-<div id="backdrop"></div>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-in-flow.html b/third_party/blink/web_tests/html/dialog/backdrop-in-flow.html
deleted file mode 100644
index 5e8e25f..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-in-flow.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog {
-    visibility: hidden;
-}
-
-dialog::backdrop {
-    height: 100px;
-    width: 50px;
-}
-
-#left::backdrop {
-    position: static;
-    top: 100px;
-    left: 100px;
-    background: green;
-}
-
-#right::backdrop {
-    position: relative;
-    background: green;
-    top: 100px;
-    left: 150px;
-}
-</style>
-<body>
-Test that position 'static' or 'relative' for ::backdrop computes to 'absolute'.
-The test passes if there is a single green box.
-<dialog id="left"></dialog>
-<dialog id="right"></dialog>
-</div>
-<script>
-document.querySelector('#left').showModal();
-document.querySelector('#right').showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-stacking-order-expected.html b/third_party/blink/web_tests/html/dialog/backdrop-stacking-order-expected.html
deleted file mode 100644
index d3f82de..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-stacking-order-expected.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE html>
-<style>
-div {
-    position: absolute;
-}
-
-#bottom-backdrop {
-    top: 100px;
-    left: 100px;
-    height: 300px;
-    width: 300px;
-    background-color: rgb(0, 50, 0);
-}
-
-#bottom {
-    top: 125px;
-    left: 125px;
-    height: 250px;
-    width: 250px;
-    background-color: rgb(0, 90, 0);
-}
-
-#middle-backdrop {
-    top: 150px;
-    left: 150px;
-    height: 200px;
-    width: 200px;
-    background-color: rgb(0, 130, 0);
-}
-
-#middle {
-    top: 175px;
-    left: 175px;
-    height: 150px;
-    width: 150px;
-    background-color: rgb(0, 170, 0);
-}
-
-#top-backdrop {
-    top: 200px;
-    left: 200px;
-    height: 100px;
-    width: 100px;
-    background-color: rgb(0, 210, 0);
-}
-
-#top {
-    top: 225px;
-    left: 225px;
-    height: 50px;
-    width: 50px;
-    background-color: rgb(0, 255, 0);
-}
-</style>
-<body>
-Test for dialog::backdrop stacking order. The test passes if there are 6
-boxes enclosed in each other, becoming increasingly smaller and brighter
-green.
-<div id="bottom-backdrop"></div>
-<div id="bottom"></div>
-<div id="middle-backdrop"></div>
-<div id="middle"></div>
-<div id="top-backdrop"></div>
-<div id="top"></div>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/backdrop-stacking-order.html b/third_party/blink/web_tests/html/dialog/backdrop-stacking-order.html
deleted file mode 100644
index c83a668..0000000
--- a/third_party/blink/web_tests/html/dialog/backdrop-stacking-order.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog {
-    padding: 0px;
-    border: none;
-    margin: 0px;
-}
-
-#bottom::backdrop {
-    top: 100px;
-    left: 100px;
-    height: 300px;
-    width: 300px;
-    background-color: rgb(0, 50, 0);
-    z-index: 100;  /* z-index has no effect. */
-}
-
-#bottom {
-    top: 125px;
-    left: 125px;
-    height: 250px;
-    width: 250px;
-    background-color: rgb(0, 90, 0);
-}
-
-#middle::backdrop {
-    top: 150px;
-    left: 150px;
-    height: 200px;
-    width: 200px;
-    background-color: rgb(0, 130, 0);
-    z-index: -100;  /* z-index has no effect. */
-}
-
-#middle {
-    top: 175px;
-    left: 175px;
-    height: 150px;
-    width: 150px;
-    background-color: rgb(0, 170, 0);
-}
-
-#top::backdrop {
-    top: 200px;
-    left: 200px;
-    height: 100px;
-    width: 100px;
-    background-color: rgb(0, 210, 0);
-    z-index: 0;  /* z-index has no effect. */
-}
-
-#top {
-    top: 225px;
-    left: 225px;
-    height: 50px;
-    width: 50px;
-    background-color: rgb(0, 255, 0);
-    z-index: -1000;  /* z-index has no effect. */
-}
-</style>
-<body>
-Test for dialog::backdrop stacking order. The test passes if there are 6
-boxes enclosed in each other, becoming increasingly smaller and brighter
-green.
-<dialog id="top"></dialog>
-<dialog id="middle"></dialog>
-<dialog id="bottom"></dialog>
-<script>
-var topDialog = document.getElementById('top');
-var middleDialog = document.getElementById('middle');
-var bottomDialog = document.getElementById('bottom');
-topDialog.showModal();
-bottomDialog.showModal();
-topDialog.close();  // Just to shuffle the top layer order around a little.
-middleDialog.showModal();
-topDialog.showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop-expected.html b/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop-expected.html
deleted file mode 100644
index 4b31dc7..0000000
--- a/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop-expected.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<body>
-Test that ::backdrop is not shown for non-open or non-modal dialogs.
-The test passes if there is no red shown.
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop.html b/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop.html
deleted file mode 100644
index 38a5943f..0000000
--- a/third_party/blink/web_tests/html/dialog/dialogs-with-no-backdrop.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog::backdrop {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background: red;
-}
-
-#display-none-backdrop::backdrop {
-    display: none;
-}
-</style>
-<body>
-Test that ::backdrop is not shown for non-open or non-modal dialogs.
-The test passes if there is no red shown.
-<dialog id="never-opened-dialog"></dialog>
-<dialog id="display-none-dialog" style="display: none"></dialog>
-<dialog id="non-modal-dialog" style="visibility: hidden"></dialog>
-<dialog id="display-none-backdrop" style="visibility: hidden"></dialog>
-<dialog id="closed-dialog"></dialog>
-<dialog id="removed-dialog"></dialog>
-<script>
-document.getElementById('display-none-dialog').showModal();
-document.getElementById('non-modal-dialog').show();
-document.getElementById('display-none-backdrop').showModal();
-
-var closedDialog = document.getElementById('closed-dialog');
-closedDialog.showModal();
-closedDialog.close();
-
-var removedDialog = document.getElementById('removed-dialog');
-removedDialog.showModal();
-removedDialog.parentNode.removeChild(removedDialog);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer-expected.html b/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer-expected.html
deleted file mode 100644
index 535ac93..0000000
--- a/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer-expected.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<style>
-#non-modal {
-    position: static;
-}
-</style>
-<p>Test that a non-top layer element doesn't share style with a top layer
-element. The test passes if you see two boxes.</p>
-<dialog id="non-modal" open></dialog>
-<dialog id="modal"></dialog>
-<script>
-document.querySelector('#modal').showModal();
-</script>
diff --git a/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer.html b/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer.html
deleted file mode 100644
index 1d0ad7d..0000000
--- a/third_party/blink/web_tests/html/dialog/dont-share-style-to-top-layer.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<style>
-dialog {
-  position: static;
-}
-</style>
-<p>Test that a non-top layer element doesn't share style with a top layer
-element. The test passes if you see two boxes.</p>
-<dialog open></dialog>
-<dialog id="modal"></dialog>
-<script>
-document.querySelector('#modal').showModal();
-</script>
diff --git a/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position-expected.html b/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position-expected.html
deleted file mode 100644
index c0b64e68..0000000
--- a/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position-expected.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-.green {
-    color: green;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/106538">106538</a>: Top layer fails for inline elements</p>
-<p>This tests that position 'static' no longer computes to 'absolute' for an
-element that has been removed from the top layer. The test passes if you see
-a single line of text.</p>
-<span class="green">This is the span.</span>
-<span class="green">This is the dialog following it.</span>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position.html b/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position.html
deleted file mode 100644
index 65437da..0000000
--- a/third_party/blink/web_tests/html/dialog/element-removed-from-top-layer-has-original-position.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-.green {
-    color: green;
-}
-
-#right-dialog {
-    display: inline;
-    position: static;
-    border: none;
-    padding: 0;
-    margin: 0;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/106538">106538</a>: Top layer fails for inline elements</p>
-<p>This tests that position 'static' no longer computes to 'absolute' for an
-element that has been removed from the top layer. The test passes if you see
-a single line of text.</p>
-<span class="green">This is the span.</span>
-<dialog class="green" id="right-dialog">This is the dialog following it.</dialog>
-<script>
-var dialog = document.getElementById('right-dialog');
-dialog.showModal();
-dialog.close();
-dialog.show();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted-expected.html b/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted-expected.html
deleted file mode 100644
index f4d0a41..0000000
--- a/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted-expected.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-body p, span {
-    -webkit-user-select: none;
-}
-
-::backdrop {
-    display: none;
-}
-</style>
-</head>
-<body>
-<p>Test that inert nodes are not painted as being selected. The test passes if
-none of the text outside the dialog is highlighted when selected.</p>
-
-<p>Although not shown as selected, the inert nodes are in window.getSelection()
-and copied to the clipboard, which is the same behavior as -webkit-user-select:
-none (crbug.com/147490).</p>
-
-<br><span>This text shouldn't be highlighted as selected.</span>
-
-<dialog>
-    <div id="selectable">I'm selectable.</div>
-</dialog>
-
-<script>
-dialog = document.querySelector('dialog');
-dialog.showModal();
-selectable = document.querySelector('#selectable');
-window.getSelection().selectAllChildren(selectable);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted.html b/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted.html
deleted file mode 100644
index d4aabf08..0000000
--- a/third_party/blink/web_tests/html/dialog/inert-node-is-not-highlighted.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-::backdrop {
-    display: none;
-}
-</style>
-</head>
-<body>
-<p>Test that inert nodes are not painted as being selected. The test passes if
-none of the text outside the dialog is highlighted when selected.</p>
-
-<p>Although not shown as selected, the inert nodes are in window.getSelection()
-and copied to the clipboard, which is the same behavior as -webkit-user-select:
-none (crbug.com/147490).</p>
-
-<br>  <!-- Needed to the trigger the bug. -->
-This text shouldn't be highlighted as selected.
-
-<dialog>
-    <div id="selectable">I'm selectable.</div>
-</dialog>
-
-<script>
-dialog = document.querySelector('dialog');
-dialog.showModal();
-document.execCommand('SelectAll');
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop-expected.html b/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop-expected.html
deleted file mode 100644
index d703b7f2..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop-expected.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<style>
-.dialog-default-ua-style {
-    position: absolute;
-    overflow: auto;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-    margin: auto;
-    border: solid;
-    padding: 1em;
-    background: white;
-    color: black;
-}
-
-#dialog {
-    margin: auto;
-    height: 100px;
-    width: 100px;
-    top: 100px;
-    z-index: 1000;
-    background: green;
-}
-
-#backdrop {
-    position: fixed;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background: rgba(0,0,0,0.1);
-    z-index: 100;
-}
-</style>
-<body>
-Test for the default user agent style of dialog::backdrop. The test passes if
-there is a green box, above a very lightly translucent gray box spanning the
-viewport.
-<div id="backdrop"></div>
-<div class="dialog-default-ua-style" id="dialog"></div>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop.html b/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop.html
deleted file mode 100644
index bab57f9..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-backdrop.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog {
-    top: 100px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-</style>
-<body>
-Test for the default user agent style of dialog::backdrop. The test passes if
-there is a green box, above a very lightly translucent gray box spanning the
-viewport.
-<dialog></dialog>
-<script>
-document.querySelector('dialog').showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content-expected.html b/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content-expected.html
deleted file mode 100644
index 10c9897..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content-expected.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<style>
-#dialog {
-    position: absolute;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-
-#dialog-before {
-    position: absolute;
-    top: 0px;
-}
-
-#dialog-after {
-    position: absolute;
-    bottom: 0px;
-}
-
-#dialog-backdrop {
-    position: absolute;
-    top: 100px;
-    left: 300px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-</style>
-<body>
-Test for a modal dialog with ::before, ::after, and ::backdrop. The test passes
-if there are two green boxes, one with the texts "::before" and "::after" in it.
-<div id="dialog">
-    <div id="dialog-before">::before</div>
-    <div id="dialog-after">::after</div>
-</div>
-<div id="dialog-backdrop"></div>
-<script>
-document.querySelector('dialog').showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content.html b/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content.html
deleted file mode 100644
index 55632bd..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-generated-content.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<style>
-dialog {
-    padding: 0px;
-    border: none;
-    margin: 0px;
-    top: 100px;
-    left: 100px;
-    height: 100px;
-    width: 100px;
-    background: green;
-}
-
-dialog::before {
-    content: '::before';
-    position: absolute;
-    top: 0px;
-}
-
-dialog::after {
-    content: '::after';
-    position: absolute;
-    bottom: 0px;
-}
-
-dialog::backdrop {
-    position: absolute;
-    top: 100px;
-    left: 300px;
-    height: 100px;
-    width: 100px;
-    background: green;
-    content: 'THIS TEXT SHOULD NOT BE SEEN';
-}
-
-dialog::backdrop::before {
-    content: '::backdrop::before';
-    position: absolute;
-    top: 0px;
-    background: red;
-}
-dialog::backdrop::after {
-    content: '::backdrop::after';
-    position: absolute;
-    bottom: 0px;
-    background: red;
-}
-</style>
-<body>
-Test for a modal dialog with ::before, ::after, and ::backdrop. The test passes
-if there are two green boxes, one with the texts "::before" and "::after" in it.
-<dialog></dialog>
-<script>
-document.querySelector('dialog').showModal();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer-expected.html b/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer-expected.html
deleted file mode 100644
index 6588615..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer-expected.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-div {
-    content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPAQMAAAABGAcJAAAAA1BMVEUAgACc+aWRAAAADElEQVR42mNgIAEAAAAtAAH7KhMqAAAAAElFTkSuQmCC);
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport.
-<div></div>
-<dialog id="dialog"></dialog>
-<script>
-document.getElementById('dialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer.html b/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer.html
deleted file mode 100644
index 55aa086b..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-in-replaced-renderer.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-div {
-    content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPAQMAAAABGAcJAAAAA1BMVEUAgACc+aWRAAAADElEQVR42mNgIAEAAAAtAAH7KhMqAAAAAElFTkSuQmCC);
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport.
-<div>
-<dialog id="dialog"></dialog>
-</div>
-<script>
-document.getElementById('dialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column-expected.html b/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column-expected.html
deleted file mode 100644
index 38b628c..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column-expected.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green rectangle in the center of the viewport.
-<dialog id="dialog"></dialog>
-<script>
-document.getElementById('dialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column.html b/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column.html
deleted file mode 100644
index 814c3537..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-in-table-column.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-div {
-    display: table-column;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green rectangle in the center of the viewport.
-<div>
-<dialog id="dialog"></dialog>
-</div>
-<script>
-document.getElementById('dialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-sibling-expected.html b/third_party/blink/web_tests/html/dialog/modal-dialog-sibling-expected.html
deleted file mode 100644
index 38b628c..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-sibling-expected.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green rectangle in the center of the viewport.
-<dialog id="dialog"></dialog>
-<script>
-document.getElementById('dialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/modal-dialog-sibling.html b/third_party/blink/web_tests/html/dialog/modal-dialog-sibling.html
deleted file mode 100644
index 43d0975..0000000
--- a/third_party/blink/web_tests/html/dialog/modal-dialog-sibling.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    background: green;
-    border-color: green;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
-NodeRenderingContext::parentRenderer and nextRenderer top layer aware
-<p>The test passes if you see a green rectangle in the center of the viewport.
-<div style="display: none" id="div"></div>
-<dialog id="dialog"></dialog>
-<script>
-document.getElementById('dialog').showModal();
-document.getElementById('dialog').offsetTop;  // force a layout/renderer creation
-document.getElementById('div').style.display = 'block';
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer-expected.html b/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer-expected.html
deleted file mode 100644
index 0856d6f..0000000
--- a/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer-expected.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-<style>
-.pseudodialog {
-    height: 100px;
-    width: 100px;
-}
-
-#bottomDialog {
-    background-color: blue;
-    top: 0px;
-}
-
-#topDialog {
-    background-color: green;
-    top: 50px;
-    left: 50px;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="https://bugs.webkit.org/show_bug.cgi?id=105489">105489</a>: Elements must be reattached when inserted/removed from top layer
-<p>The test passes if you see a green rectangle stacked on top of a blue rectangle.
-<div id="bottomDialog" class="pseudodialog"></div>
-<div id="topDialog" class="pseudodialog"></div>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer.html b/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer.html
deleted file mode 100644
index c377d8a..0000000
--- a/third_party/blink/web_tests/html/dialog/removed-element-is-removed-from-top-layer.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    height: 100px;
-    width: 100px;
-}
-
-::backdrop {
-    display: none;
-}
-
-#bottomDialog {
-    background-color: blue;
-    top: 231px;
-}
-
-#topDialog {
-    background-color: green;
-    top: 50px;
-    left: 50px;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="https://bugs.webkit.org/show_bug.cgi?id=105489">105489</a>: Elements must be reattached when inserted/removed from top layer
-<p>The test passes if you see a green rectangle stacked on top of a blue rectangle.
-<dialog id="bottomDialog"></dialog>
-<dialog id="topDialog"></dialog>
-<script>
-document.getElementById('topDialog').showModal();
-var bottomDialog = document.getElementById('bottomDialog');
-bottomDialog.showModal();
-bottomDialog.offsetTop;  // force a layout
-var parent = bottomDialog.parentNode;
-parent.removeChild(bottomDialog);
-parent.appendChild(bottomDialog);
-</script>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/html/dialog/resources/dialog.css b/third_party/blink/web_tests/html/dialog/resources/dialog.css
deleted file mode 100644
index f5345b00..0000000
--- a/third_party/blink/web_tests/html/dialog/resources/dialog.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.pseudodialog {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-    width: -webkit-fit-content;
-    height: -webkit-fit-content;
-    margin: auto;
-    border: solid;
-    padding: 1em;
-    background: white;
-    color: black;
-}
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-containing-block-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-containing-block-expected.html
deleted file mode 100644
index 40b72cf5e..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-containing-block-expected.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-</head>
-<body>
-<p>
-This tests that a modal dialog's containing block is in the initial containing block and that it is unaffected by
-ancestor elements with overflow or opacity.
-<div class="pseudodialog" style="position: absolute; top: 100px; height: 250px; width: 90%; background-color: yellow">
-    This dialog should be onscreen with a width of 90% of the page. It is the child of an narrow element
-    positioned off screen, but the containing block of a top layer element is the initial containing block, so its
-    position and percent lengths are relative to that.
-</div>
-<div class="pseudodialog" style="position: absolute; top: 200px; left: 0px; height: 100px; background-color: cyan">
-    This dialog should be unaffected by its ancestor with overflow. It should not be clipped.
-</div>
-<div class="pseudodialog" style="position: absolute; top: 250px; left: 0px; background-color: magenta">
-    This dialog should be unaffected by its ancestor with opacity.
-</div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-containing-block.html b/third_party/blink/web_tests/html/dialog/top-layer-containing-block.html
deleted file mode 100644
index 7c3f5efd..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-containing-block.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-::backdrop {
-    display: none;
-}
-</style>
-</head>
-<body>
-<p>
-This tests that a modal dialog's containing block is in the initial containing block and that it is unaffected by
-ancestor elements with overflow or opacity.
-<div style="position: absolute; top: 400px; opacity: 0.3">
-    <dialog id="opaqueDialog" style="position: absolute; top: 250px; left: 0px; background-color: magenta">
-        This dialog should be unaffected by its ancestor with opacity.
-    </dialog>
-</div>
-<div style="position: absolute; overflow: hidden; width: 500px; height: 150px; top: 400px; left: 300px">
-    <dialog id="unclippedDialog" style="position: absolute; top: 200px; left: 0px; height: 100px; background-color: cyan">
-        This dialog should be unaffected by its ancestor with overflow. It should not be clipped.
-    </dialog>
-</div>
-<div style="position: absolute; top: 1000px; left: 1000px; width: 20px;">
-    <dialog id="bottomDialog" style="position: absolute; top: 100px; height: 250px; width: 90%; background-color: yellow">
-        This dialog should be onscreen with a width of 90% of the page. It is the child of an narrow element
-        positioned off screen, but the containing block of a top layer element is the initial containing block, so its
-        position and percent lengths are relative to that.
-    </dialog>
-</div>
-<script>
-document.getElementById('bottomDialog').showModal();
-document.getElementById('unclippedDialog').showModal();
-document.getElementById('opaqueDialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-display-none-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-display-none-expected.html
deleted file mode 100644
index 1880668c..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-display-none-expected.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-<style>
-.pseudodialog {
-    height: 150px;
-    width: 150px;
-}
-</style>
-</head>
-<body>
-This tests that a top layer element is not rendered if it, or an ancestor, has display: none.
-It passes if you see a green rectangle stacked on top of a blue rectangle, and see no red rectangles.
-
-<div class="pseudodialog" style="top: 50px; background-color: blue"></div>
-<div class="pseudodialog" style="top: 100px; left: 50px; background-color: green"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-display-none.html b/third_party/blink/web_tests/html/dialog/top-layer-display-none.html
deleted file mode 100644
index 31b7446..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-display-none.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    height: 150px;
-    width: 150px;
-}
-
-::backdrop {
-    display: none;
-}
-
-.red {
-    background-color: red;
-    top: 200px;
-}
-
-#bottomDialog {
-    background-color: blue;
-    top: 50px;
-    display: none;
-}
-
-#topDialog {
-    background-color: green;
-    top: 100px;
-    left: 50px;
-}
-</style>
-</head>
-<body>
-This tests that a top layer element is not rendered if it, or an ancestor, has display: none.
-It passes if you see a green rectangle stacked on top of a blue rectangle, and see no red rectangles.
-
-<dialog id="hiddenDialog" class="red" style="display: none;"></dialog>
-<div id="container">
-    <div>
-        <dialog id="displayNoneChild1" class="red"></dialog>
-        <dialog id="displayNoneChild2" class="red"></dialog>
-    </div>
-</div>
-<dialog id="bottomDialog"></dialog>
-<dialog id="topDialog"></dialog>
-<script>
-document.getElementById('hiddenDialog').showModal();
-document.getElementById('displayNoneChild1').showModal();
-document.getElementById('container').style.display = 'none';
-document.getElementById('displayNoneChild2').showModal();
-
-// Test that stacking works even if an element is added to the top layer when it has no renderer.
-document.getElementById('bottomDialog').showModal();
-document.getElementById('topDialog').showModal();
-document.getElementById('bottomDialog').style.display = 'block';
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-nesting-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-nesting-expected.html
deleted file mode 100644
index 0a2936a..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-nesting-expected.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-.pseudodialog {
-    height: 150px;
-    width: 150px;
-    position: absolute;
-    top: 0; right: 0; bottom: 0; left: 0;
-    margin: auto;
-    border: solid;
-    padding: 1em;
-    background: white;
-    color: black;
-}
-</style>
-</head>
-<body>
-This tests that top layer elements are stacked correctly even if nested in the DOM tree.
-The test passes if you see no red rectangles and see 3 rectangles stacked in the following order (from bottom to top): yellow, blue, green.
-
-<div class="pseudodialog" style="top: 100px; background-color: yellow"></div>
-<div class="pseudodialog" style="top: 150px; left: 50px; background-color: blue"></div>
-<div class="pseudodialog" style="top: 200px; left: 100px; background-color: green"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-nesting.html b/third_party/blink/web_tests/html/dialog/top-layer-nesting.html
deleted file mode 100644
index 0fea7f87..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-nesting.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    height: 150px;
-    width: 150px;
-}
-
-::backdrop {
-    display: none;
-}
-
-#bottomDialog {
-    background-color: yellow;
-    top: 100px;
-    z-index: 1000;
-}
-
-#middleDialog {
-    background-color: blue;
-    top: 150px;
-    left: 50px;
-    z-index: -500;
-}
-
-#topDialog {
-    background-color: green;
-    top: 200px;
-    left: 100px;
-    z-index: -1000;
-}
-
-.red {
-    background-color: red;
-    top: 250px;
-    left: 0px;
-}
-</style>
-</head>
-<body>
-This tests that top layer elements are stacked correctly even if nested in the DOM tree.
-The test passes if you see no red rectangles and see 3 rectangles stacked in the following order (from bottom to top): yellow, blue, green.
-
-<dialog id="topDialog">
-    <dialog id="middleDialog">
-        <dialog id="bottomDialog">
-            <dialog id="hiddenDialog" class="red">
-                <dialog id="hiddenDialogChild" class="red"></dialog>
-            </dialog>
-        </dialog>
-    </dialog>
-</dialog>
-<script>
-document.getElementById('hiddenDialogChild').showModal();
-document.getElementById('hiddenDialog').showModal();
-document.getElementById('bottomDialog').showModal();
-document.getElementById('middleDialog').showModal();
-document.getElementById('topDialog').showModal();
-document.getElementById('hiddenDialog').close();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd-expected.html
deleted file mode 100644
index 392d1ca4..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd-expected.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-<style>
-.pseudodialog {
-    height: 100px;
-    width: 100px;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="https://bugs.webkit.org/show_bug.cgi?id=105489">105489</a>: Elements must be reattached when inserted/removed from top layer
-<p>The test passes if you see a green rectangle stacked on top of a blue rectangle.
-
-<div class="pseudodialog" style="top: 100px; background-color: blue"></div>
-<div class="pseudodialog" style="top: 150px; left: 50px; background-color: green"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd.html
deleted file mode 100644
index 8fa1751..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking-correct-order-remove-readd.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    height: 100px;
-    width: 100px;
-}
-
-::backdrop {
-    display: none;
-}
-
-#bottomDialog {
-    background-color: blue;
-    top: 100px;
-}
-
-#topDialog {
-    background-color: green;
-    top: 150px;
-    left: 50px;
-}
-</style>
-</head>
-<body>
-<p>Bug <a href="https://bugs.webkit.org/show_bug.cgi?id=105489">105489</a>: Elements must be reattached when inserted/removed from top layer
-<p>The test passes if you see a green rectangle stacked on top of a blue rectangle.
-
-<dialog id="topDialog"></dialog>
-<dialog id="bottomDialog"></dialog>
-<script>
-var topDialog = document.getElementById('topDialog');
-var bottomDialog = document.getElementById('bottomDialog');
-topDialog.showModal();
-bottomDialog.showModal();
-topDialog.offsetTop;  // force a layout
-topDialog.close();
-topDialog.showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic-expected.html
deleted file mode 100644
index 6ddb3176..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic-expected.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-<style>
-.pseudodialog {
-    height: 150px;
-    width: 150px;
-}
-</style>
-</head>
-<body>
-This tests top layer element stacking order after dynamically calling show/close and removal from the DOM tree.
-The test passes if you see a green rectangle stacked on top of a blue rectangle, and see no red rectangles.
-
-<div class="pseudodialog" style="top: 50px; background-color: blue"></div>
-<div class="pseudodialog" style="top: 100px; left: 50px; background-color: green"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic.html
deleted file mode 100644
index b74f1c9..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking-dynamic.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-dialog {
-    height: 150px;
-    width: 150px;
-}
-
-::backdrop {
-    display: none;
-}
-
-.red {
-    background-color: red;
-    top: 200px;
-}
-
-#bottomDialog {
-    background-color: blue;
-    top: 50px;
-}
-
-#topDialog {
-    background-color: green;
-    top: 100px;
-    left: 50px;
-}
-</style>
-</head>
-<body>
-This tests top layer element stacking order after dynamically calling show/close and removal from the DOM tree.
-The test passes if you see a green rectangle stacked on top of a blue rectangle, and see no red rectangles.
-
-<dialog id="topDialog"></dialog>
-<dialog id="bottomDialog"></dialog>
-<dialog id="removedDialog" class="red">
-    <dialog id="removedDialogChild" class="red"></dialog>
-</dialog>
-<script>
-document.getElementById('topDialog').showModal();
-var removedDialog = document.getElementById('removedDialog');
-removedDialog.showModal();
-document.getElementById('bottomDialog').showModal();
-document.getElementById('removedDialogChild').showModal();
-removedDialog.parentNode.removeChild(removedDialog);
-document.getElementById('topDialog').close();
-document.getElementById('topDialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking-expected.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking-expected.html
deleted file mode 100644
index ebf78aa..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking-expected.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" href="resources/dialog.css">
-</head>
-<style>
-.box {
-    height: 150px;
-    width: 150px;
-}
-.container {
-    -webkit-perspective: 500px;
-    border: 1px solid black;
-    background-color: magenta;
-}
-.transformed {
-    transform: rotateY(45deg);
-    background-color: cyan;
-}
-</style>
-<body>
-<div class="pseudodialog" style="position: fixed; top: 10px; z-index:3000">
-    This white box is the topmost modal dialog. It should be on top of everything.
-</div>
-<div style="position: absolute; top: 0px; z-index: 3; background-color: red; left: 0; right: 0; height: 200px;"></div>
-<div class="pseudodialog" style="position: absolute; top: 50px; background-color: green; width: 75%; height: 400px; z-index:2000; overflow: auto;">
-    This green box is also a modal dialog. It should be rendered above the red and yellow regions.
-    <div class="container box">
-        <div class="transformed box">A transform within the dialog's subtree.</div>
-    </div>
-    <div class="box" style="position: absolute; top:300px; z-index: 2; background-color: cyan">
-        This shows z-index stacking within the dialog's subtree. The cyan box should be on top of the magenta one.
-    </div>
-    <div class="box" style="position: absolute; top:350px; left:50px; z-index: 1; background-color: magenta"></div>
-    <div style="position: fixed; top: 90px; left: 30px; background-color: green">This is part of the green dialog.</div>
-</div>
-<div style="position: absolute; top: 100px; left: 0px; right: 0px; height: 200em; background-color: yellow; z-index:1000">
-</div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/html/dialog/top-layer-stacking.html b/third_party/blink/web_tests/html/dialog/top-layer-stacking.html
deleted file mode 100644
index 2916a2d..0000000
--- a/third_party/blink/web_tests/html/dialog/top-layer-stacking.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<!-- This tests that top layer elements are rendered above z-indexed elements
-and stacked in the correct order amongst themselves. Also, layer features like
-transforms and z-index are tested inside a top layer element subtree. -->
-<html>
-<head>
-<style>
-.box {
-    height:150px;
-    width:150px;
-}
-
-::backdrop {
-    display: none;
-}
-
-.container {
-    -webkit-perspective: 500px;
-    border: 1px solid black;
-    background-color: magenta;
-}
-.transformed {
-    transform: rotateY(45deg);
-    background-color: cyan;
-}
-</style>
-</head>
-<body>
-<dialog id="hiddenDialog" style="display: none; color: red">This should not be displayed.</dialog>
-<dialog id="topDialog" style="position: fixed; top: 10px; z-index: -10;">
-    This white box is the topmost modal dialog. It should be on top of everything.
-</dialog>
-<div style="position: absolute; top: 0px; z-index: 3; background-color: red; left: 0; right: 0; height: 200px;">
-    <dialog id="bottomDialog" style="position: absolute; top: 50px; background-color: green; width: 75%; height: 400px;">
-        This green box is also a modal dialog. It should be rendered above the red and yellow regions.
-        <div class="container box">
-            <div class="transformed box">A transform within the dialog's subtree.</div>
-        </div>
-        <div class="box" style="position: absolute; top:300px; z-index: 2; background-color: cyan">
-            This shows z-index stacking within the dialog's subtree. The cyan box should be on top of the magenta one.
-        </div>
-        <div class="box" style="position: absolute; top:350px; left:50px; z-index: 1; background-color: magenta"></div>
-        <div style="position: fixed; top: 90px; left: 30px; background-color: green">This is part of the green dialog.</div>
-    </dialog>
-</div>
-<div style="position: absolute; top: 100px; left: 0px; right: 0px; height: 200em; background-color: yellow; z-index:1000">
-</div>
-<script>
-document.getElementById('bottomDialog').showModal();
-document.getElementById('topDialog').showModal();
-document.getElementById('hiddenDialog').showModal();
-</script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet.js b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet.js
index 912d69d..4072562 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet.js
+++ b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet.js
@@ -26,10 +26,10 @@
     range: {
       startColumn: 11,
       startLine: 1,
-      endColumn: 29,
+      endColumn: 33,
       endLine: 1,
     },
-    text: '(max-width: 300px)',
+    text: 'size(max-width: 300px)',
   });
 
   await cssHelper.loadAndDumpMatchingRulesForNode(itemNodeId);
diff --git a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
index 3999780..b752e3e 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
@@ -1,6 +1,6 @@
 Tests CSS.setContainerQueryText method.
 ==== Initial style sheet text ====
-@container (max-width: 200px) and (min-height: 100px) {
+@container size((max-width: 200px) and (min-height: 100px)) {
   div {
     color: red;
   }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text.js b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text.js
index dcf74258..bf67815 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text.js
+++ b/third_party/blink/web_tests/inspector-protocol/css/container-queries/css-set-container-query-text.js
@@ -21,14 +21,14 @@
     startLine: 0,
     startColumn: 11,
     endLine: 0,
-    endColumn: 53,
+    endColumn: 59,
   };
 
   testRunner.runTestSuite([
     async function testSimpleEdit() {
       await setContainerQueryText({
         range: containerQueryRange,
-        text: '(min-width: 100px) and (max-height: 200px)',
+        text: 'size((min-width: 100px) and (max-height: 200px))',
       });
       await dp.DOM.undo();
     },
@@ -36,7 +36,7 @@
     async function testFeatureChange() {
       await setContainerQueryText({
         range: containerQueryRange,
-        text: '(min-aspect-ratio: 1 / 1000)',
+        text: 'size(min-aspect-ratio: 1 / 1000)',
       });
       await dp.DOM.undo();
     },
@@ -56,7 +56,7 @@
     },
 
     async function testEditSequentially() {
-      const newText = '(min-width: 50px)';
+      const newText = 'size(min-width: 50px)';
       const oldLength = containerQueryRange.endColumn - containerQueryRange.startColumn;
       const lengthDelta = newText.length - oldLength;
       await setContainerQueryText({
@@ -70,7 +70,7 @@
       };
       await setContainerQueryText({
         range: newRange,
-        text: '(min-height: 80px)'
+        text: 'size(min-height: 80px)'
       });
       await dp.DOM.undo();
     },
@@ -78,7 +78,7 @@
     async function testAfterSequentially() {
       await setContainerQueryText({
         range: containerQueryRange,
-        text: '(min-height: 20px)'
+        text: 'size(min-height: 20px)'
       });
       await dp.DOM.undo();
     },
diff --git a/third_party/blink/web_tests/inspector-protocol/css/resources/css-container-queries-in-constructed-stylesheet.html b/third_party/blink/web_tests/inspector-protocol/css/resources/css-container-queries-in-constructed-stylesheet.html
index 62ef2e08..6d2cd03 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/resources/css-container-queries-in-constructed-stylesheet.html
+++ b/third_party/blink/web_tests/inspector-protocol/css/resources/css-container-queries-in-constructed-stylesheet.html
@@ -8,7 +8,7 @@
     contain: layout style size;
   }
 
-  @container (min-width: 100px) {
+  @container size(min-width: 100px) {
     .item {
       font-size: 1px;
     }
@@ -20,7 +20,7 @@
     container-type: inline-size;
   }
 
-  @container container-1 (max-width: 300px) {
+  @container container-1 size(max-width: 300px) {
     .item {
       color: #abc;
     }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/resources/set-active-property-value.css b/third_party/blink/web_tests/inspector-protocol/css/resources/set-active-property-value.css
index f841698..c281911 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/resources/set-active-property-value.css
+++ b/third_party/blink/web_tests/inspector-protocol/css/resources/set-active-property-value.css
@@ -22,7 +22,7 @@
     container-type: size;
 }
 
-@container (min-width: 50px) {
+@container size(min-width: 50px) {
     #inspected {
         padding-right: 10px;
     }
diff --git a/third_party/blink/web_tests/inspector-protocol/css/resources/set-container-query-text.css b/third_party/blink/web_tests/inspector-protocol/css/resources/set-container-query-text.css
index e77247f..df913266 100644
--- a/third_party/blink/web_tests/inspector-protocol/css/resources/set-container-query-text.css
+++ b/third_party/blink/web_tests/inspector-protocol/css/resources/set-container-query-text.css
@@ -1,4 +1,4 @@
-@container (max-width: 200px) and (min-height: 100px) {
+@container size((max-width: 200px) and (min-height: 100px)) {
   div {
     color: red;
   }
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-container-for-node.html b/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-container-for-node.html
index 5ac68814..80261ee9 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-container-for-node.html
+++ b/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-container-for-node.html
@@ -15,13 +15,13 @@
   width: 50px;
 }
 
-@container container-with-name (min-width: 100px) {
+@container container-with-name size(min-width: 100px) {
   .item {
     margin-top: 10px;
   }
 }
 
-@container (max-width: 80px) {
+@container size(max-width: 80px) {
   .item {
     margin-bottom: 5px;
   }
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-querying-descendants-for-container.html b/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-querying-descendants-for-container.html
index fc84408..c215562 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-querying-descendants-for-container.html
+++ b/third_party/blink/web_tests/inspector-protocol/dom/resources/dom-get-querying-descendants-for-container.html
@@ -13,19 +13,19 @@
   height: 100px;
 }
 
-@container (min-width: 50px) and (min-height: 50px) {
+@container size((min-width: 50px) and (min-height: 50px)) {
   .query-unnamed { margin-top: 5px; }
 }
 
-@container container-named (min-width: 50px) {
+@container container-named size(min-width: 50px) {
   .query-named { margin-top: 10px; }
 }
 
-@container (min-width: 50px) {
+@container size(min-width: 50px) {
   .query-unnamed-inline { margin-top: 15px; }
 }
 
-@container container-named-other (min-height: 50px) {
+@container container-named-other size(min-height: 50px) {
   .query-named-other { margin-top: 20px; }
 }
 </style>
diff --git a/third_party/blink/web_tests/inspector-protocol/overlay/overlay-container-query.js b/third_party/blink/web_tests/inspector-protocol/overlay/overlay-container-query.js
index a9805f5..44ab2e08 100644
--- a/third_party/blink/web_tests/inspector-protocol/overlay/overlay-container-query.js
+++ b/third_party/blink/web_tests/inspector-protocol/overlay/overlay-container-query.js
@@ -6,7 +6,7 @@
         height: 500px;
         container-type: inline-size;
       }
-      @container (min-width: 100px) {
+      @container size(min-width: 100px) {
         .item {
           width: 100px;
           height: 100px;
diff --git a/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png b/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
new file mode 100644
index 0000000..800944c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png b/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
new file mode 100644
index 0000000..b9346e2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
new file mode 100644
index 0000000..1d5ab1b07
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
new file mode 100644
index 0000000..9fb5a21
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png b/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
new file mode 100644
index 0000000..ba87619
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png b/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
new file mode 100644
index 0000000..0b049a4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png b/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
new file mode 100644
index 0000000..6069802
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-grammar-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png b/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
new file mode 100644
index 0000000..59e24c6
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/css3-text/css3-text-decoration/text-decoration-line-spelling-error-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet-expected.txt b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet-expected.txt
index 49e1b951..a1b5308 100644
--- a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet-expected.txt
+++ b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-container-queries-in-constructed-stylesheet-expected.txt
@@ -1,26 +1,26 @@
 Test CSS.getMatchedStylesForNode and CSS.setContainerQueryText methods for container queries in a constructed stylesheet
-@container (min-width: 100px)
+@container size(min-width: 100px)
     *.item* {    regular
         font-size: 1px; @[2:10-2:25]
         font-size: 1px; @[undefined-undefined]
     }
 ==== Style sheet text ====
 #parent { width: 200px; contain: size layout style; }
-@container (max-width: 300px) {
+@container size(max-width: 300px) {
   .item { font-size: 1px; }
 }
 #named-container { width: 300px; container: inline-size / container-1; }
-@container container-1 (max-width: 300px) {
+@container container-1 size(max-width: 300px) {
   .item { color: rgb(170, 187, 204); }
 }
 
 Dumping matched rules: 
-@container (max-width: 300px)
+@container size(max-width: 300px)
     *.item* {    regular
         font-size: 1px; @[2:10-2:25]
         font-size: 1px; @[undefined-undefined]
     }
-@container container-1 (max-width: 300px)
+@container container-1 size(max-width: 300px)
     *.item* {    regular
         color: rgb(170, 187, 204); @[6:10-6:36]
         color: rgb(170, 187, 204); @[undefined-undefined]
diff --git a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
index 47b521a..5274993 100644
--- a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
+++ b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/container-queries/css-set-container-query-text-expected.txt
@@ -1,6 +1,6 @@
 Tests CSS.setContainerQueryText method.
 ==== Initial style sheet text ====
-@container (max-width: 200px) and (min-height: 100px) {
+@container size((max-width: 200px) and (min-height: 100px)) {
   div {
     color: red;
   }
@@ -9,7 +9,7 @@
 
 Running test: testSimpleEdit
 ==== Style sheet text ====
-@container (min-width: 100px) and (max-height: 200px) {
+@container size((min-width: 100px) and (max-height: 200px)) {
   div {
     color: red;
   }
@@ -18,7 +18,7 @@
 
 Running test: testFeatureChange
 ==== Style sheet text ====
-@container (min-aspect-ratio: 1 / 1000) {
+@container size(min-aspect-ratio: 1 / 1000) {
   div {
     color: red;
   }
@@ -33,14 +33,14 @@
 
 Running test: testEditSequentially
 ==== Style sheet text ====
-@container (min-width: 50px) {
+@container size(min-width: 50px) {
   div {
     color: red;
   }
 }
 
 ==== Style sheet text ====
-@container (min-height: 80px) {
+@container size(min-height: 80px) {
   div {
     color: red;
   }
@@ -49,7 +49,7 @@
 
 Running test: testAfterSequentially
 ==== Style sheet text ====
-@container (min-height: 20px) {
+@container size(min-height: 20px) {
   div {
     color: red;
   }
diff --git a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt
index 0c15df1..b102913 100644
--- a/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt
+++ b/third_party/blink/web_tests/virtual/container-queries/inspector-protocol/css/css-get-styles-for-node-expected.txt
@@ -45,7 +45,7 @@
         padding-left: 10px; @[undefined-undefined]
         margin-top: 15px !important; @[undefined-undefined]
     }
-@container (min-width: 50px)
+@container size(min-width: 50px)
     *#inspected* {    regular
         padding-right: 10px; @[26:8-26:28]
         padding-right: 10px; @[undefined-undefined]
diff --git a/third_party/blink/web_tests/virtual/private-network-access-preflights/README.md b/third_party/blink/web_tests/virtual/private-network-access-preflights/README.md
new file mode 100644
index 0000000..d10ea44dc
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/private-network-access-preflights/README.md
@@ -0,0 +1,4 @@
+This is a virtual test suite exercising Private Network Access preflights.
+
+TODO(https://crbug.com/1274094): Remove this virtual test suite once the flag is
+enabled by default.
diff --git a/third_party/blink/web_tests/virtual/private-network-access-preflights/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt b/third_party/blink/web_tests/virtual/private-network-access-preflights/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt
new file mode 100644
index 0000000..9ee8c82
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/private-network-access-preflights/external/wpt/fetch/private-network-access/secure-context.https.window-expected.txt
@@ -0,0 +1,50 @@
+This is a testharness.js-based test.
+PASS local to local: no preflight required.
+PASS local to private: no preflight required.
+PASS local to public: no preflight required.
+PASS local to public: PUT preflight failure.
+PASS local to public: PUT preflight success,
+PASS private to local: failed preflight.
+PASS private to local: missing CORS headers on preflight response.
+PASS private to local: missing PNA header on preflight response.
+PASS private to local: missing CORS headers on final response.
+PASS private to local: success.
+PASS private to local: PUT success.
+PASS private to local: no-CORS mode failed preflight.
+PASS private to local: no-CORS mode missing CORS headers on preflight response.
+PASS private to local: no-CORS mode missing PNA header on preflight response.
+PASS private to local: no-CORS mode success.
+PASS private to private: no preflight required.
+PASS private to public: no preflight required.
+PASS public to local: failed preflight.
+PASS public to local: missing CORS headers on preflight response.
+PASS public to local: missing PNA header on preflight response.
+PASS public to local: missing CORS headers on final response.
+PASS public to local: success.
+PASS public to local: PUT success.
+PASS public to local: no-CORS mode failed preflight.
+PASS public to local: no-CORS mode missing CORS headers on preflight response.
+PASS public to local: no-CORS mode missing PNA header on preflight response.
+PASS public to local: no-CORS mode success.
+PASS public to private: failed preflight.
+PASS public to private: missing CORS headers on preflight response.
+PASS public to private: missing PNA header on preflight response.
+PASS public to private: missing CORS headers on final response.
+PASS public to private: success.
+PASS public to private: PUT success.
+PASS public to private: no-CORS mode failed preflight.
+PASS public to private: no-CORS mode missing CORS headers on preflight response.
+PASS public to private: no-CORS mode missing PNA header on preflight response.
+PASS public to private: no-CORS mode success.
+PASS public to public: no preflight required.
+PASS treat-as-public-address to local: failed preflight.
+PASS treat-as-public-address to local: success.
+PASS treat-as-public-address to private: failed preflight.
+PASS treat-as-public-address to private: success.
+PASS treat-as-public-address to public: no preflight required.
+PASS local to local: websocket success.
+PASS private to local: websocket success.
+PASS public to local: websocket success.
+PASS treat-as-public to local: websocket success.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
index b7a43cbb..67ff614 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
@@ -14,6 +14,7 @@
 ch-ua-arch
 ch-ua-bitness
 ch-ua-full-version
+ch-ua-full-version-list
 ch-ua-mobile
 ch-ua-model
 ch-ua-platform
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-001.html
index c69562cd..8d47dc2 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-001.html
@@ -16,7 +16,7 @@
     background-color: green;
   }
 
-  @container (width: 200px) {
+  @container size(width: 200px) {
     #target {
       background-color: blue;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-002.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-002.html
index 3ea17e5..078a955e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-002.html
@@ -20,7 +20,7 @@
     background-color: green;
   }
 
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #target {
       animation: inner 1s linear paused;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-003.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-003.html
index b16b620..a4bf77b 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-003.html
@@ -16,7 +16,7 @@
     background-color: rgb(100, 100, 100);
   }
 
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #target {
       transition: background-color 100s steps(2, start);
       background-color: rgb(200, 200, 200);
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-004.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-004.html
index c9a8d8af..25679d6 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-004.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/animations-004.html
@@ -20,19 +20,19 @@
     width: 100px;
   }
 
-  @container (min-width: 250px) {
+  @container size(min-width: 250px) {
     #intermediate {
       container-type: inline-size;
     }
   }
 
-  @container (width: 200px) {
+  @container size(width: 200px) {
     #target {
       background-color: blue;
     }
   }
 
-  @container (width: 100px) {
+  @container size(width: 100px) {
     /* Initially queries  #container, but later queries #intermediate, when
        the other container query starts matching. */
     #target {
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/aspect-ratio.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/aspect-ratio.html
index a591fa3..151f803 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/aspect-ratio.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/aspect-ratio.html
@@ -11,10 +11,10 @@
   #block-size { container-type: block-size; }
   #size { container-type: size; }
   span { color: red }
-  @container (min-aspect-ratio: 1 / 1000) {
+  @container size(min-aspect-ratio: 1 / 1000) {
     span { color: green; }
   }
-  @container (min-aspect-ratio: 2 / 1) {
+  @container size(min-aspect-ratio: 2 / 1) {
     span { background-color: lime; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-001.html
index da4d487..88fa40e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-001.html
@@ -15,19 +15,19 @@
     height: 20px;
   }
 
-  @container (min-width: 30px) { .width .box { background-color: coral; } }
-  @container (min-width: 40px) { .width .box { background-color: skyblue; } }
-  @container (min-width: 50px) { .width .box { background-color: hotpink; } }
-  @container (min-width: 60px) { .width .box { background-color: seagreen; } }
+  @container size(min-width: 30px) { .width .box { background-color: coral; } }
+  @container size(min-width: 40px) { .width .box { background-color: skyblue; } }
+  @container size(min-width: 50px) { .width .box { background-color: hotpink; } }
+  @container size(min-width: 60px) { .width .box { background-color: seagreen; } }
 
-  @container (min-height: 50px) { .height .box { background-color: coral; } }
-  @container (min-height: 60px) { .height .box { background-color: skyblue; } }
-  @container (min-height: 70px) { .height .box { background-color: hotpink; } }
-  @container (min-height: 80px) { .height .box { background-color: seagreen; } }
+  @container size(min-height: 50px) { .height .box { background-color: coral; } }
+  @container size(min-height: 60px) { .height .box { background-color: skyblue; } }
+  @container size(min-height: 70px) { .height .box { background-color: hotpink; } }
+  @container size(min-height: 80px) { .height .box { background-color: seagreen; } }
 
   /* Should not apply to anything: */
-  @container (min-width: 9999px) { .width .box { background-color: red; } }
-  @container (min-height: 9999px) { .height .box { background-color: red; } }
+  @container size(min-width: 9999px) { .width .box { background-color: red; } }
+  @container size(min-height: 9999px) { .height .box { background-color: red; } }
 
 </style>
 <div class=width>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-002.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-002.html
index 3cd7863..6c33f16e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-002.html
@@ -17,19 +17,19 @@
   }
 
   /* Note: 150px - 2px, since .container has a 1px border */
-  @container (min-width: 148px) {
+  @container size(min-width: 148px) {
     div { display: flex; }
     span { flex: 1; }
   }
 
   /* Note: 200px - 2px, since .container has a 1px border */
-  @container (min-width: 198px) {
+  @container size(min-width: 198px) {
     div { display: revert; }
     span { display: block; }
   }
 
   /* Should not apply: */
-  @container (min-width: 199px) {
+  @container size(min-width: 199px) {
     * { color: red; background-color: red; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-003.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-003.html
index e7903a3..d5bc89e3 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-003.html
@@ -9,7 +9,7 @@
     height: 50px;
   }
   div { color: red; }
-  @container (min-width: 300px) {
+  @container size(min-width: 300px) {
     div { color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-004.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-004.html
index bec6c1c8..4cc71003 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-004.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-004.html
@@ -15,7 +15,7 @@
       height: 20px;
     }
     div#child { color: red; }
-    @container (min-width: 300px) {
+    @container size(min-width: 300px) {
       div#child { color: green; }
     }
   </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-005.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-005.html
index a54fe2f..7a8134f 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-005.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-005.html
@@ -13,7 +13,7 @@
     height: 40px;
   }
 
-  @container (min-width: 300px) {
+  @container size(min-width: 300px) {
     #container1 div::before { content: "before"; }
     #container1 div::after { content: "after"; }
     #container2 li::marker { color: green; }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-006.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-006.html
index f673732..024f99f 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-006.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-006.html
@@ -17,7 +17,7 @@
     background-color: black;
   }
 
-  @container (min-width: 300px) {
+  @container size(min-width: 300px) {
     ::backdrop {
       background-color: green;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-007.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-007.html
index 5e6e2b4..38e20313 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-007.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-007.html
@@ -25,11 +25,11 @@
     display: none;
   }
 
-  @container (width: 30px) {
+  @container size(width: 30px) {
     .target { --x:30; }
   }
 
-  @container (width: 50px) {
+  @container size(width: 50px) {
     .target { --x:50; }
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-008.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-008.html
index ad205b3..7880db8 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-008.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-008.html
@@ -22,21 +22,21 @@
     width: 200px;
   }
 
-  @container (width: 200px) { #unnamed .w200 { color:green; } }
-  @container (width: 300px) { #unnamed .w300 { color:red !important; } }
-  @container (width: 400px) { #unnamed .w400 { color:red !important; } }
+  @container size(width: 200px) { #unnamed .w200 { color:green; } }
+  @container size(width: 300px) { #unnamed .w300 { color:red !important; } }
+  @container size(width: 400px) { #unnamed .w400 { color:red !important; } }
 
-  @container c3 (width: 200px) { #q3 .w200 { color:green; } }
-  @container c3 (width: 300px) { #q3 .w300 { color:red !important; } }
-  @container c3 (width: 400px) { #q3 .w400 { color:red !important; } }
+  @container c3 size(width: 200px) { #q3 .w200 { color:green; } }
+  @container c3 size(width: 300px) { #q3 .w300 { color:red !important; } }
+  @container c3 size(width: 400px) { #q3 .w400 { color:red !important; } }
 
-  @container c2 (width: 200px) { #q2 .w200 { color:red !important; } }
-  @container c2 (width: 300px) { #q2 .w300 { color:green; } }
-  @container c2 (width: 400px) { #q2 .w400 { color:red !important; } }
+  @container c2 size(width: 200px) { #q2 .w200 { color:red !important; } }
+  @container c2 size(width: 300px) { #q2 .w300 { color:green; } }
+  @container c2 size(width: 400px) { #q2 .w400 { color:red !important; } }
 
-  @container c1 (width: 200px) { #q1 .w200 { color:red !important; } }
-  @container c1 (width: 300px) { #q1 .w300 { color:red !important; } }
-  @container c1 (width: 400px) { #q1 .w400 { color:green; } }
+  @container c1 size(width: 200px) { #q1 .w200 { color:red !important; } }
+  @container c1 size(width: 300px) { #q1 .w300 { color:red !important; } }
+  @container c1 size(width: 400px) { #q1 .w400 { color:green; } }
 
 </style>
 <div id=container1>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-009.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-009.html
index 765549b..9696c183 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-009.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-009.html
@@ -22,7 +22,7 @@
     width: 250px;
   }
 
-  @container c1 (width: 250px) {
+  @container c1 size(width: 250px) {
     #child {
       color: green;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-010.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-010.html
index 15a8ed0..562121f 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-010.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-010.html
@@ -18,7 +18,7 @@
     width: 200px;
   }
 
-  @container c1 (min-width: 300px) {
+  @container c1 size(min-width: 300px) {
     #child { color: green; }
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
index 7307dffc5e..cec6918 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-011.html
@@ -22,7 +22,7 @@
     container-type: inline-size;
   }
 
-  @container (max-width: 200px) or (min-width: 300px) {
+  @container size((max-width: 200px) or (min-width: 300px)) {
     #child { color: green; }
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-013.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-013.html
index 41a4265..4a8998b 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-013.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-013.html
@@ -13,7 +13,7 @@
   p {
     color: green;
   }
-  @container (min-width: 1px) {
+  @container size(min-width: 1px) {
     p { color: red; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-014.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-014.html
index 6e44bf95..9490e49 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-014.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-014.html
@@ -18,11 +18,11 @@
     display: none;
   }
 
-  @container (width: 30px) {
+  @container size(width: 30px) {
     .target { --x:30; }
   }
 
-  @container (width: 50px) {
+  @container size(width: 50px) {
     .target { --x:50; }
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-015.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-015.html
index 791e34cc..d5ec18e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-015.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-015.html
@@ -6,7 +6,7 @@
   .parent { width: 300px; }
   .child { width: 100px; }
   .parent, .child { container-type: inline-size; }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     .child { container-type: initial; }
     .grandchild { border: 3px solid green }
   }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-016.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-016.html
index feb0cf3..dcb06a0 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-016.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-016.html
@@ -12,7 +12,7 @@
     from { color: green; }
     to { color: green; }
   }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #div { animation: test 1s linear forwards; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-017.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-017.html
index 7c2b075..18a8643 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-017.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-017.html
@@ -5,29 +5,29 @@
 <style>
   .container { container-type: inline-size; }
 
-  @container (max-width: 100px) { #c1::before { content: "PASS" } }
-  @container (min-width: 150px) { #c1::before { content: "FAIL" } }
+  @container size(max-width: 100px) { #c1::before { content: "PASS" } }
+  @container size(min-width: 150px) { #c1::before { content: "FAIL" } }
 
-  @container (max-width: 100px) { #c2::before { content: "PASS" } }
-  @container (min-width: 150px) { #c2::before { content: "FAIL" } }
+  @container size(max-width: 100px) { #c2::before { content: "PASS" } }
+  @container size(min-width: 150px) { #c2::before { content: "FAIL" } }
 
-  @container (max-width: 100px) { #c3::after { content: "PASS" } }
-  @container (min-width: 150px) { #c3::after { content: "FAIL" } }
+  @container size(max-width: 100px) { #c3::after { content: "PASS" } }
+  @container size(min-width: 150px) { #c3::after { content: "FAIL" } }
 
-  @container (max-width: 100px) { #c4::after { content: "PASS" } }
-  @container (min-width: 150px) { #c4::after { content: "FAIL" } }
+  @container size(max-width: 100px) { #c4::after { content: "PASS" } }
+  @container size(min-width: 150px) { #c4::after { content: "FAIL" } }
 
-  @container (max-width: 300px) { #c5::first-letter { color: green } }
-  @container (max-width: 300px) { #c6::first-letter { color: green } }
+  @container size(max-width: 300px) { #c5::first-letter { color: green } }
+  @container size(max-width: 300px) { #c6::first-letter { color: green } }
 
-  @container (min-width: 400px) { #c7::first-letter { color: green } }
-  @container (min-width: 400px) { #c8::first-letter { color: green } }
+  @container size(min-width: 400px) { #c7::first-letter { color: green } }
+  @container size(min-width: 400px) { #c8::first-letter { color: green } }
 
-  @container (max-width: 300px) { #c9::first-line { color: green } }
-  @container (max-width: 300px) { #c10::first-line { color: green } }
+  @container size(max-width: 300px) { #c9::first-line { color: green } }
+  @container size(max-width: 300px) { #c10::first-line { color: green } }
 
-  @container (min-width: 400px) { #c11::first-line { color: green } }
-  @container (min-width: 400px) { #c12::first-line { color: green } }
+  @container size(min-width: 400px) { #c11::first-line { color: green } }
+  @container size(min-width: 400px) { #c12::first-line { color: green } }
 </style>
 <div id="c1" class="container" style="width:100px"></div>
 <div id="c2" class="container" style="width:200px"></div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-018.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-018.html
index 08ae5a9..6201211 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-018.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-018.html
@@ -6,19 +6,19 @@
 <style>
   .container { container-type: inline-size; }
   #target { display: list-item; }
-  @container (max-width: 200px) {
+  @container size(max-width: 200px) {
     #target::before { content: "PASS"; color: green; }
     #target::after { color: green; }
     #target::marker { color: green; }
     #target::first-line { color: green; }
     #target::first-letter { color: green; }
   }
-  @container (min-width: 300px) and (max-width: 350px) {
+  @container size((min-width: 300px) and (max-width: 350px)) {
     #outer::first-line { color: green; }
     #outer::first-letter { color: green; }
   }
   dialog::backdrop { background-color: lime; }
-  @container (max-width: 100px) {
+  @container size(max-width: 100px) {
     dialog::backdrop { background-color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html
index 912e825..ea1adca 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/at-container-parsing.html
@@ -34,7 +34,7 @@
       t.add_cleanup(cleanup_main);
       let style = set_style(`
         @container ${query} {}
-        @container (${query}) or (not (${query})) { main { --match:true; } }
+        @container (${query} or (not ${query})) { main { --match:true; } }
       `);
       assert_equals(style.sheet.rules.length, 2);
       assert_equals(getComputedStyle(main).getPropertyValue('--match'), 'true');
@@ -57,14 +57,14 @@
     }, `Container selector: ${container_selector}`);
   }
 
-  test_query_known('(width: 100px)');
-  test_query_known('((width: 100px))');
-  test_query_known('(not (width: 100px))');
-  test_query_known('(width: 100px) and (height: 100px)');
-  test_query_known('(width: 50px) or (height: 100px)');
-  test_query_known('(width < 100px)');
-  test_query_known('(100px < width)');
-  test_query_known('(100px < width < 200px)');
+  test_query_known('size(width: 100px)');
+  test_query_known('size((width: 100px))');
+  test_query_known('size(not (width: 100px))');
+  test_query_known('size((width: 100px) and (height: 100px))');
+  test_query_known('size((width: 50px) or (height: 100px))');
+  test_query_known('size(width < 100px)');
+  test_query_known('size(100px < width)');
+  test_query_known('size(100px < width < 200px)');
 
   test_query_invalid('screen');
   test_query_invalid('print');
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
index 0d4c0a9..f6158535 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
@@ -16,7 +16,7 @@
     height: 100px;
     border-bottom: 1px solid red;
   }
-  @container (max-width: 99px) {
+  @container size(max-width: 99px) {
     #inner {
       height: 50px;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-and-min-height.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-and-min-height.html
index 0240fba0..c024bdd1c 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-and-min-height.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-and-min-height.html
@@ -8,7 +8,7 @@
     container-type: block-size;
     min-height: 200px;
   }
-  @container (min-height: 200px) {
+  @container size(min-height: 200px) {
     #child { color: green }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-containment.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-containment.html
index fd67217..3275ea5 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/block-size-containment.html
@@ -3,10 +3,10 @@
 <style>
   #ancestry { display: flex; }
   #keg { container-type: block-size; display: flex; width: fit-content; }
-  @container (max-height: 200px) {
+  @container size(max-height: 200px) {
     #target { width: 400px; }
   }
-  @container (min-height: 400px) {
+  @container size(min-height: 400px) {
     #target { width: 20px; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/change-display-in-container.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/change-display-in-container.html
index c3df4de..18ac0ab9 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/change-display-in-container.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/change-display-in-container.html
@@ -5,7 +5,7 @@
   .fail { display: inline; }
   .pass { display: none; }
   #container { container-type: size; width: 100px; }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     .fail { display: none; }
     .pass { display: inline; }
   }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html
index b5c7220a..5c1f33e4 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-selection.html
@@ -123,40 +123,40 @@
   // and the outer container has a size of 32x32px.
 
   // "Nearest" selection:
-  test_applied('(width: 16px)', '.block > .inline > span');
-  test_applied('(height: 16px)', '.inline > .block > span');
-  test_rejected('(height)', '.block > .inline > span');
-  test_rejected('(width)', '.inline > .block > span');
+  test_applied('size(width: 16px)', '.block > .inline > span');
+  test_applied('size(height: 16px)', '.inline > .block > span');
+  test_rejected('size(height)', '.block > .inline > span');
+  test_rejected('size(width)', '.inline > .block > span');
 
   // type():
-  test_applied('type(inline-size) (width: 32px)', '.inline > .block > span');
-  test_applied('type(inline-size) (width: 16px)', '.block > .inline > span');
-  test_applied('type(inline-size) (width: 32px)', '.size > .block > span');
-  test_applied('type(inline-size) (width: 16px)', '.size > .inline > span');
+  test_applied('type(inline-size) size(width: 32px)', '.inline > .block > span');
+  test_applied('type(inline-size) size(width: 16px)', '.block > .inline > span');
+  test_applied('type(inline-size) size(width: 32px)', '.size > .block > span');
+  test_applied('type(inline-size) size(width: 16px)', '.size > .inline > span');
 
-  test_applied('type(block-size) (height: 16px)', '.inline > .block > span');
-  test_applied('type(block-size) (height: 32px)', '.block > .inline > span');
-  test_applied('type(block-size) (height: 16px)', '.size > .block > span');
-  test_applied('type(block-size) (height: 32px)', '.size > .inline > span');
+  test_applied('type(block-size) size(height: 16px)', '.inline > .block > span');
+  test_applied('type(block-size) size(height: 32px)', '.block > .inline > span');
+  test_applied('type(block-size) size(height: 16px)', '.size > .block > span');
+  test_applied('type(block-size) size(height: 32px)', '.size > .inline > span');
 
-  test_rejected('type(size) (height)', '.inline > .block > span');
-  test_rejected('type(size) (height)', '.block > .inline > span');
-  test_rejected('type(size) (width)', '.inline > .block > span');
-  test_rejected('type(size) (width)', '.block > .inline > span');
-  test_applied('type(size) (height: 32px)', '.size > .block > span');
-  test_applied('type(size) (height: 32px)', '.size > .inline > span');
+  test_rejected('type(size) size(height)', '.inline > .block > span');
+  test_rejected('type(size) size(height)', '.block > .inline > span');
+  test_rejected('type(size) size(width)', '.inline > .block > span');
+  test_rejected('type(size) size(width)', '.block > .inline > span');
+  test_applied('type(size) size(height: 32px)', '.size > .block > span');
+  test_applied('type(size) size(height: 32px)', '.size > .inline > span');
 
   // name():
-  test_applied('name(a) (width: 32px)', '.a-inline > .b-inline > span');
-  test_applied('name(b) (width: 16px)', '.a-inline > .b-inline > span');
-  test_rejected('name(c) (width)', '.a-inline > .b-inline > span');
-  test_applied('name(a) (width: 16px)', '.a-inline > .a-inline > span');
+  test_applied('name(a) size(width: 32px)', '.a-inline > .b-inline > span');
+  test_applied('name(b) size(width: 16px)', '.a-inline > .b-inline > span');
+  test_rejected('name(c) size(width)', '.a-inline > .b-inline > span');
+  test_applied('name(a) size(width: 16px)', '.a-inline > .a-inline > span');
 
   // Name as plain ident:
-  test_applied('a (width: 32px)', '.a-inline > .b-inline > span');
-  test_applied('b (width: 16px)', '.a-inline > .b-inline > span');
-  test_rejected('c (width)', '.a-inline > .b-inline > span');
-  test_applied('a (width: 16px)', '.a-inline > .a-inline > span');
+  test_applied('a size(width: 32px)', '.a-inline > .b-inline > span');
+  test_applied('b size(width: 16px)', '.a-inline > .b-inline > span');
+  test_rejected('c size(width)', '.a-inline > .b-inline > span');
+  test_applied('a size(width: 16px)', '.a-inline > .a-inline > span');
 
   // The following tests have three containers:
   //
@@ -165,15 +165,15 @@
   //  inner -> 8x8px
 
   // Mixing name() and type():
-  test_applied('name(a) type(inline-size) (width: 32px)', '.a-inline > .b-inline > .a-block > span');
-  test_applied('name(a) type(block-size) (height: 8px)', '.a-inline > .b-inline > .a-block > span');
-  test_rejected('name(a) type(size) (height)', '.a-inline > .b-inline > .a-block > span');
-  test_applied('name(b) type(inline-size) (width: 16px)', '.a-inline > .b-inline > .a-block > span');
-  test_rejected('name(b) type(block-size) (height)', '.a-inline > .b-inline > .a-block > span');
-  test_rejected('name(b) type(size) (height)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('name(a) type(inline-size) size(width: 32px)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('name(a) type(block-size) size(height: 8px)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(a) type(size) size(height)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('name(b) type(inline-size) size(width: 16px)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(b) type(block-size) size(height)', '.a-inline > .b-inline > .a-block > span');
+  test_rejected('name(b) type(size) size(height)', '.a-inline > .b-inline > .a-block > span');
 
   // type() first, then name():
-  test_applied('type(inline-size) name(a) (width: 32px)', '.a-inline > .b-inline > .a-block > span');
-  test_applied('type(block-size) name(a) (height: 8px)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('type(inline-size) name(a) size(width: 32px)', '.a-inline > .b-inline > .a-block > span');
+  test_applied('type(block-size) name(a) size(height: 8px)', '.a-inline > .b-inline > .a-block > span');
 
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-slotted.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-slotted.html
index 67d96d3..c4f0f70 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-slotted.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/container-slotted.html
@@ -22,7 +22,7 @@
 ::slotted(*) {
   background-color: green;
 }
-@container (max-height: 50px) {
+@container size(max-height: 50px) {
   ::slotted(*) {
     background-color: red;
   }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-flex-circular.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-flex-circular.html
index c78002a..e170d25 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-flex-circular.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-flex-circular.html
@@ -33,7 +33,7 @@
   /* The counter-increment inside the container should not affect the size of
      #item2 because of style containment. Otherwise we would have a
      circularity. */
-  @container (min-width: 125px) {
+  @container size(min-width: 125px) {
     #inner {
       counter-increment: my-count 10;
       background-color: green;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container-dynamic.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container-dynamic.html
index 2bdc1e1..2d422df 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container-dynamic.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container-dynamic.html
@@ -12,7 +12,7 @@
     content: counter(my-counter);
   }
 
-  @container (min-width: 300px) {
+  @container size(min-width: 300px) {
     #counter {
       counter-reset: my-counter 100;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container.html
index a0251d0..d400fb8 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/counters-in-container.html
@@ -12,7 +12,7 @@
     content: counter(my-counter);
   }
 
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #counter {
       counter-reset: my-counter 100;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/flex-cross-axis-stretch.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/flex-cross-axis-stretch.html
index 18d1cdd..e6a7604cb 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/flex-cross-axis-stretch.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/flex-cross-axis-stretch.html
@@ -3,7 +3,7 @@
 <link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
 <style>
   #target { height:10px; background:red; }
-  @container (min-height: 100px) {
+  @container size(min-height: 100px) {
       #target { height:100%; background:green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/focus-inside-content-visibility-crash.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/focus-inside-content-visibility-crash.html
index 3b33d56..b5f7888 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/focus-inside-content-visibility-crash.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/focus-inside-content-visibility-crash.html
@@ -18,7 +18,7 @@
   width: 100%;
   visibility: hidden;
 }
-@container (min-width: 150px) {
+@container size(min-width: 150px) {
   #input { visibility: visible; }
 }
 
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units-dynamic.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units-dynamic.html
index f6d3835..3c8e9c7 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units-dynamic.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units-dynamic.html
@@ -12,16 +12,16 @@
     width: 100px;
     color: red;
   }
-  @container (width: 5em) {
+  @container size(width: 5em) {
     #em_test { color: green }
   }
-  @container (width: 2rem) {
+  @container size(width: 2rem) {
     #rem_test { color: green }
   }
-  @container (max-width: 15ex) {
+  @container size(max-width: 15ex) {
     #ex_test { color: green }
   }
-  @container (max-width: 15ch) {
+  @container size(max-width: 15ch) {
     #ch_test { color: green }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units.html
index 2a943c4..3919f81 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/font-relative-units.html
@@ -20,16 +20,16 @@
     font-size: 50px;
     width: 10ch;
   }
-  @container (width: 1em) {
+  @container size(width: 1em) {
     #em_test { color: green }
   }
-  @container (width: 10rem) {
+  @container size(width: 10rem) {
     #rem_test { color: green }
   }
-  @container (width: 10ex) {
+  @container size(width: 10ex) {
     #ex_test { color: green }
   }
-  @container (width: 10ch) {
+  @container size(width: 10ch) {
     #ch_test { color: green }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-and-min-width.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-and-min-width.html
index 8921cf3b..df5c58c4 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-and-min-width.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-and-min-width.html
@@ -9,7 +9,7 @@
     min-width: 200px;
     width: fit-content;
   }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #child { color: green }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment-vertical-rl.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment-vertical-rl.html
index 401898e..e7a2b63d 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment-vertical-rl.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment-vertical-rl.html
@@ -3,10 +3,10 @@
 <style>
   #ancestry { writing-mode: vertical-rl; }
   #keg { container-type: inline-size; }
-  @container (max-height: 200px) {
+  @container size(max-height: 200px) {
     #target { width: 400px; }
   }
-  @container (min-height: 400px) {
+  @container size(min-height: 400px) {
     #target { width: 20px; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment.html
index 3afea1c7..fc534ce 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-containment.html
@@ -2,10 +2,10 @@
 <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
 <style>
   #keg { container-type: inline-size; }
-  @container (max-width: 200px) {
+  @container size(max-width: 200px) {
     #target { height: 400px; }
   }
-  @container (min-width: 400px) {
+  @container size(min-width: 400px) {
     #target { height: 20px; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-query-block-size-containment.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-query-block-size-containment.html
index 29951474..11366e2e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-query-block-size-containment.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/inline-size-query-block-size-containment.html
@@ -2,10 +2,10 @@
 <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
 <style>
   #keg { container-type: block-size; }
-  @container (max-width: 200px) {
+  @container size(max-width: 200px) {
     #target { height: 400px; }
   }
-  @container (min-width: 400px) {
+  @container size(min-width: 400px) {
     #target { height: 20px; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/orthogonal-wm-container-query.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/orthogonal-wm-container-query.html
index d8497a6d5..ae6708f 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/orthogonal-wm-container-query.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/orthogonal-wm-container-query.html
@@ -12,7 +12,7 @@
   #orthogonal {
     font: 50px/1 Ahem;
   }
-  @container (max-width: 100px) {
+  @container size(max-width: 100px) {
     #orthogonal {
       writing-mode: vertical-lr;
     }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/reattach-container-with-dirty-child.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/reattach-container-with-dirty-child.html
index 2513f88..b1af2ef 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/reattach-container-with-dirty-child.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/reattach-container-with-dirty-child.html
@@ -6,10 +6,10 @@
   #container {
     container-type: inline-size;
   }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     div { color: red }
   }
-  @container (max-width: 150px) {
+  @container size(max-width: 150px) {
     div { color: lime }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/resize-while-content-visibility-hidden.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/resize-while-content-visibility-hidden.html
index 240f887..3c85792 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/resize-while-content-visibility-hidden.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/resize-while-content-visibility-hidden.html
@@ -25,7 +25,7 @@
 #container.wide { width: 500px; }
 .locked { content-visibility: hidden; }
 
-@container container (min-width: 400px) { #child { background: green; } }
+@container container size(min-width: 400px) { #child { background: green; } }
 </style>
 
 <div id=container>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/size-container-no-principal-box.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/size-container-no-principal-box.html
index 5f2825a..154d308 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/size-container-no-principal-box.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/size-container-no-principal-box.html
@@ -15,10 +15,10 @@
     display: contents;
     container-type: inline-size;
   }
-  @container (min-width: 0) {
+  @container size(min-width: 0) {
     span { color: red; }
   }
-  @container (min-width: 0) {
+  @container size(min-width: 0) {
     #ref { color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/style-change-in-container.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/style-change-in-container.html
index 4d5e3fa..afceb7ef 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/style-change-in-container.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/style-change-in-container.html
@@ -4,7 +4,7 @@
 <script src="/resources/testharnessreport.js"></script>
 <style>
   #container { container-type: size; }
-  @container (min-width: 1px) {
+  @container size(min-width: 1px) {
     #content { color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/svg-layout-root-crash.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/svg-layout-root-crash.html
index 75a3839ad..2162e5db 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/svg-layout-root-crash.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/svg-layout-root-crash.html
@@ -8,7 +8,7 @@
       #container {
         container-type: inline-size;
       }
-      @container (min-width: 300px) {
+      @container size(min-width: 300px) {
         .hide { display: none; }
       }
     </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-001.html
index 4d05946..fff21eb 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-001.html
@@ -10,10 +10,10 @@
   dialog {
     color: red;
   }
-  @container (max-width: 200px) {
+  @container size(max-width: 200px) {
     dialog { color: green; }
   }
-  @container (max-width: 100px) {
+  @container size(max-width: 100px) {
     dialog { color: lime; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-002.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-002.html
index 27ff554e..4280210 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-002.html
@@ -11,7 +11,7 @@
     border: none;
   }
   #child { color: red; }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #child { color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-003.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-003.html
index eed842e..0018bb86 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-003.html
@@ -5,7 +5,7 @@
 <style>
   html { background: green; }
   #container { container-type: inline-size; }
-  @container (max-width: 200px) {
+  @container size(max-width: 200px) {
     ::backdrop { display: none; }
     #dialog { visibility: hidden; }
   }
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-004.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-004.html
index cbc78bd..e33ffe4 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-004.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/top-layer-004.html
@@ -7,10 +7,10 @@
   dialog { color: red; }
   #container { width: 100px; }
   #container, #outer { container-type: inline-size; }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #outer { width: 400px; color: lime; }
   }
-  @container (min-width: 400px) {
+  @container size(min-width: 400px) {
     #inner { color: green; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-001.html
index cc78ad9..a15de71 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-001.html
@@ -10,10 +10,10 @@
     width: 100px;
     color: green;
   }
-  @container (min-width: 200px) {
+  @container size(min-width: 200px) {
     #inner { color: red }
   }
-  @container (min-width: 400px) {
+  @container size(min-width: 400px) {
     #target {
       color: green;
       transition: color 1s step-start;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-002.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-002.html
index c1a82360..321fd66 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/transitions-002.html
@@ -17,14 +17,14 @@
   }
 
   /* Matches with or without a scrollbar: */
-  @container (max-width: 100px) {
+  @container size(max-width: 100px) {
     #target {
       background-color: blue;
     }
   }
 
   /* Matches only when there's a scrollbar: */
-  @container (max-width: 99px) {
+  @container size(max-width: 99px) {
     #target {
       background-color: green;
       font-size: 10px;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units-dynamic.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units-dynamic.html
index 6258aea3..9164cb7 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units-dynamic.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units-dynamic.html
@@ -15,16 +15,16 @@
       width: 100px;
     }
 
-    @container (min-width: 50vw) {
+    @container size(min-width: 50vw) {
       #vw span { color: green }
     }
-    @container (min-width: 100vw) {
+    @container size(min-width: 100vw) {
       #vw span { color: red }
     }
-    @container (min-width: 50vh) {
+    @container size(min-width: 50vh) {
       #vh span { color: green }
     }
-    @container (min-width: 100vh) {
+    @container size(min-width: 100vh) {
       #vh span { color: red }
     }
   </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units.html
index 9d8ae42e..5c8ec2b 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/viewport-units.html
@@ -6,16 +6,16 @@
   #vw { container-type: inline-size; width: 10vw; }
   #vh { container-type: inline-size; width: 10vh; }
 
-  @container (min-width: 10vw) {
+  @container size(min-width: 10vw) {
     #vw span { color: green }
   }
-  @container (min-width: 11vw) {
+  @container size(min-width: 11vw) {
     #vw span { color: red }
   }
-  @container (min-width: 10vh) {
+  @container size(min-width: 10vh) {
     #vh span { color: green }
   }
-  @container (min-width: 11vh) {
+  @container size(min-width: 11vh) {
     #vh span { color: red }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/whitespace-reattach.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/whitespace-reattach.html
index 077bc46..54c82af 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/whitespace-reattach.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/whitespace-reattach.html
@@ -8,7 +8,7 @@
     height: 200px;
   }
 
-  @container (min-width: 400px) {
+  @container size(min-width: 400px) {
     span { color: red; }
   }
 </style>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001-ref.html
index 688836d..a135624 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 
 <p>The test passes if "quikc" has a grammar error marker that is not the default color (usually green).</p>
 <div id="target" contenteditable spellcheck>The quikc brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001.html
index ae9824c..9b70d8d9 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-001.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-grammar-error">
 <meta name="assert" content="This test checks that it's possible to modify the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="mismatch" href="grammar-error-color-001-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::grammar-error {
     text-decoration-color: rgba(200, 225, 50, 0.75);
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-002.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-002.html
index 4433298..00856dc 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-002.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-grammar-error">
 <meta name="assert" content="This test checks that it's possible to modify the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="match" href="grammar-error-color-002-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   div {
     padding: 10px;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003-ref.html
index 5233177..882f8f1 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 
 <p>The test passes if "quikc" has a grammar error marker that is in the default color (usually green).</p>
 <div id="target" contenteditable spellcheck>The quikc brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003.html
index 37aa40e..686f8ab 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-003.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-grammar-error">
 <meta name="assert" content="This test checks that setting a property in ::grammar-error pseudo element, the grammar error marker color is still the default one.">
 <link rel="match" href="grammar-error-color-003-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::grammar-error {
     background: transparent;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001-ref.html
index 4efcfca..eb3a8de5 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::grammar-error {
     text-decoration-color: magenta;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001.html
index 61f0c162..941bc41 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-001.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="match" href="grammar-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::grammar-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-002.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-002.html
index 8ae67c79..c2043d5 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-002.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="match" href="grammar-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   .magenta-marker::grammar-error {
     text-decoration-color: magenta;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-003.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-003.html
index 2d1c6648..dc99d2c 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-003.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="match" href="grammar-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   #target::grammar-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-004.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-004.html
index a4b91473..ce41019e 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-004.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/grammar-error-color-dynamic-004.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a grammar error through ::grammar-error pseudo-element.">
 <link rel="match" href="grammar-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   #target::grammar-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001-ref.html
index ebdc822a..c8ff1a6 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 
 <p>The test passes if "quikc" has a spelling error marker that is not the default color (usually red).</p>
 <div id="target" contenteditable spellcheck>The quikc brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001.html
index 9876cae7..e0ff5a7 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-001.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-spelling-error">
 <meta name="assert" content="This test checks that it's possible to modify the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="mismatch" href="spelling-error-color-001-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::spelling-error {
     text-decoration-color: rgba(200, 225, 50, 0.75);
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-002.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-002.html
index 6cc9747..1709efd 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-002.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-spelling-error">
 <meta name="assert" content="This test checks that it's possible to modify the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="match" href="spelling-error-color-002-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   div {
     padding: 10px;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003-ref.html
index 1da2da7..0c57393 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 
 <p>The test passes if "quikc" has a spelling error marker that is in the default color (usually red).</p>
 <div id="target" contenteditable spellcheck>The quikc brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003.html
index d8b56a40..6849b40 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-003.html
@@ -6,7 +6,7 @@
 <link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-spelling-error">
 <meta name="assert" content="This test checks that setting a property in ::spelling-error pseudo element, the spelling error marker color is still the default one.">
 <link rel="match" href="spelling-error-color-003-ref.html">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::spelling-error {
     background: transparent;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001-ref.html
index 045330630..3744a50 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001-ref.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001-ref.html
@@ -3,7 +3,7 @@
 <meta charset="utf-8" />
 <title>CSS Pseudo-Elements Test: Reference</title>
 <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::spelling-error {
     text-decoration-color: magenta;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001.html
index 563ee994e..53ccf3a 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-001.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="match" href="spelling-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   ::spelling-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-002.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-002.html
index 2530abb0..73a6532 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-002.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-002.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="match" href="spelling-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   .magenta-marker::spelling-error {
     text-decoration-color: magenta;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-003.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-003.html
index c78d4fc..2b043794 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-003.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-003.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="match" href="spelling-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   #target::spelling-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-004.html b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-004.html
index 5c4cc62..5c8ecbe4 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-004.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-pseudo/spelling-error-color-dynamic-004.html
@@ -7,7 +7,7 @@
 <meta name="assert" content="This test checks that it's possible to modify dinamically the color of a spelling error through ::spelling-error pseudo-element.">
 <link rel="match" href="spelling-error-color-dynamic-001-ref.html">
 <script src="/common/reftest-wait.js"></script>
-<script src="support/markers.js"></script>
+<script src="../support/markers.js"></script>
 <style>
   #target::spelling-error {
     text-decoration-color: cyan;
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001-ref.html
new file mode 100644
index 0000000..b7a6ba6
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<script src="../support/markers.js"></script>
+
+<p>The test passes if "quikc" has a grammar error marker that looks like the default grammar error marker.</p>
+<div>The <span id="target">quikc</span> brown fox.</div>
+
+<script>
+  addSpellingMarker(target, 0, 5);
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001.html b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001.html
new file mode 100644
index 0000000..83e48e1b
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-grammar-error-001.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: grammar-error</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error">
+<meta name="assert" content="This test checks that the rendering of 'text-decoration-line: grammar-error' matches the default grammar markers.">
+<link rel="match" href="text-decoration-line-grammar-error-001-ref.html">
+<script src="../support/markers.js"></script>
+<style>
+  span {
+    text-decoration-line: grammar-error;
+  }
+</style>
+
+<p>The test passes if "quikc" has a grammar error marker that looks like the default grammar error marker.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001-ref.html
new file mode 100644
index 0000000..ee418b17
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: Reference</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<script src="../support/markers.js"></script>
+
+<p>The test passes if "quikc" has a spelling error marker that looks like the default spelling error marker.</p>
+<div>The <span id="target">quikc</span> brown fox.</div>
+
+<script>
+  addSpellingMarker(target, 0, 5);
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001.html b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001.html
new file mode 100644
index 0000000..166067a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-text-decor/text-decoration-line-spelling-error-001.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>CSS Text Decoration Test: text-decoration-line: spelling-error</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error">
+<meta name="assert" content="This test checks that the rendering of 'text-decoration-line: spelling-error' matches the default spelling markers.">
+<link rel="match" href="text-decoration-line-spelling-error-001-ref.html">
+<script src="../support/markers.js"></script>
+<style>
+  span {
+    text-decoration-line: spelling-error;
+  }
+</style>
+
+<p>The test passes if "quikc" has a spelling error marker that looks like the default spelling error marker.</p>
+<div>The <span>quikc</span> brown fox.</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-pseudo/support/markers.js b/third_party/blink/web_tests/wpt_internal/css/support/markers.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/css/css-pseudo/support/markers.js
rename to third_party/blink/web_tests/wpt_internal/css/support/markers.js
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index d03febce..32e9f98 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-11-0-183-gcff026d41
-Revision: cff026d41599945498044d2f4dcc0e610ffb6929
+Version: VER-2-11-0-186-g64e26ad3a
+Revision: 64e26ad3a2ef2e07190b2027b113a6b3f6eb8b0d
 CPEPrefix: cpe:/a:freetype:freetype:2.10.4
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/webrtc_overrides/metronome_task_queue_factory.cc b/third_party/webrtc_overrides/metronome_task_queue_factory.cc
index c4ab2cc..5174d81 100644
--- a/third_party/webrtc_overrides/metronome_task_queue_factory.cc
+++ b/third_party/webrtc_overrides/metronome_task_queue_factory.cc
@@ -31,6 +31,12 @@
 const base::FeatureParam<bool> kWebRtcMetronomeTaskQueueExcludePacer{
     &kWebRtcMetronomeTaskQueue, "exclude_pacer", /*default_value=*/true};
 
+const base::FeatureParam<bool> kWebRtcMetronomeTaskQueueExcludeDecoders{
+    &kWebRtcMetronomeTaskQueue, "exclude_decoders", /*default_value=*/true};
+
+const base::FeatureParam<bool> kWebRtcMetronomeTaskQueueExcludeMisc{
+    &kWebRtcMetronomeTaskQueue, "exclude_misc", /*default_value=*/false};
+
 namespace {
 
 class WebRtcMetronomeTaskQueue : public webrtc::TaskQueueBase {
@@ -184,12 +190,23 @@
       scoped_refptr<MetronomeSource> metronome_source)
       : metronome_source_(std::move(metronome_source)),
         high_priority_task_queue_factory_(CreateWebRtcTaskQueueFactory()),
-        exclude_pacer_(kWebRtcMetronomeTaskQueueExcludePacer.Get()) {}
+        exclude_pacer_(kWebRtcMetronomeTaskQueueExcludePacer.Get()),
+        exclude_decoders_(kWebRtcMetronomeTaskQueueExcludeDecoders.Get()),
+        exclude_misc_(kWebRtcMetronomeTaskQueueExcludeMisc.Get()) {}
 
   std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>
   CreateTaskQueue(absl::string_view name, Priority priority) const override {
-    if ((priority == webrtc::TaskQueueFactory::Priority::HIGH) ||
-        (exclude_pacer_ && name.compare("TaskQueuePacedSender") == 0)) {
+    bool use_metronome;
+    if (name.compare("TaskQueuePacedSender") == 0) {
+      use_metronome = !exclude_pacer_;
+    } else if (name.compare("DecodingQueue") == 0) {
+      use_metronome = !exclude_decoders_;
+    } else if (priority == webrtc::TaskQueueFactory::Priority::HIGH) {
+      use_metronome = false;
+    } else {
+      use_metronome = !exclude_misc_;
+    }
+    if (!use_metronome) {
       return high_priority_task_queue_factory_->CreateTaskQueue(name, priority);
     }
     return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>(
@@ -203,6 +220,8 @@
   const std::unique_ptr<webrtc::TaskQueueFactory>
       high_priority_task_queue_factory_;
   const bool exclude_pacer_;
+  const bool exclude_decoders_;
+  const bool exclude_misc_;
 };
 
 }  // namespace
diff --git a/third_party/webrtc_overrides/metronome_task_queue_factory.h b/third_party/webrtc_overrides/metronome_task_queue_factory.h
index f7493cb..48cb5663 100644
--- a/third_party/webrtc_overrides/metronome_task_queue_factory.h
+++ b/third_party/webrtc_overrides/metronome_task_queue_factory.h
@@ -18,8 +18,15 @@
 // Whether WebRTC should use a metronome-backed task queue. Default: disabled.
 RTC_EXPORT extern const base::Feature kWebRtcMetronomeTaskQueue;
 
-// Feature params for the metronome task queue. Example usage:
+// Feature params for the metronome task queue. Example uses:
+//
 // --enable-features=WebRtcMetronomeTaskQueue:tick/10ms/exclude_pacer/false
+//
+// Maximum usage of metronome, including decoding queues:
+// --enable-features=WebRtcMetronomeTaskQueue:exclude_decoders/false/exclude_pacer/false/exclude_misc/false
+//
+// Metronoome decoding queues, but nothing else:
+// --enable-features=WebRtcMetronomeTaskQueue:exclude_decoders/false/exclude_pacer/true/exclude_misc/true
 
 // Specify the desired metronome tick interval with "tick". Default: 64 Hz.
 RTC_EXPORT extern const base::FeatureParam<base::TimeDelta>
@@ -27,6 +34,14 @@
 // Specify if the pacer should be excluded with "exclude_pacer". Default: true.
 RTC_EXPORT extern const base::FeatureParam<bool>
     kWebRtcMetronomeTaskQueueExcludePacer;
+// Specify if decoding queues should be excluded with "exclude_decoders".
+// Default: true.
+RTC_EXPORT extern const base::FeatureParam<bool>
+    kWebRtcMetronomeTaskQueueExcludeDecoders;
+// Specify if other tasks (tasks not specified by above arguments) should be
+// excluded with "exclude_misc". Default: false.
+RTC_EXPORT extern const base::FeatureParam<bool>
+    kWebRtcMetronomeTaskQueueExcludeMisc;
 
 }  // namespace blink
 
diff --git a/tools/accessibility/inspect/ax_dump_events.cc b/tools/accessibility/inspect/ax_dump_events.cc
index 44c2d5f..ffa7ced 100644
--- a/tools/accessibility/inspect/ax_dump_events.cc
+++ b/tools/accessibility/inspect/ax_dump_events.cc
@@ -39,6 +39,7 @@
   printf("\nusage: ax_dump_events <options>\n");
   printf("options:\n");
   tools::PrintHelpForTreeSelectors();
+  tools::PrintHelpFooter();
 }
 
 }  // namespace
diff --git a/tools/accessibility/inspect/ax_dump_tree.cc b/tools/accessibility/inspect/ax_dump_tree.cc
index dffff9a..df746fd 100644
--- a/tools/accessibility/inspect/ax_dump_tree.cc
+++ b/tools/accessibility/inspect/ax_dump_tree.cc
@@ -36,7 +36,9 @@
   tools::PrintHelpForTreeSelectors();
   printf(
       "  --filters\tfile containing property filters used to filter out\n"
-      "  \t\taccessible tree, see example-tree-filters.txt as an example\n");
+      "  \t\taccessible tree, for example:\n"
+      "  \t\t--filters=/absolute/path/to/filters/file\n");
+  tools::PrintHelpFooter();
 }
 
 int main(int argc, char** argv) {
@@ -55,6 +57,10 @@
 
   base::FilePath filters_path =
       command_line->GetSwitchValuePath(kFiltersSwitch);
+  if (filters_path.empty() && command_line->HasSwitch(kFiltersSwitch)) {
+    LOG(ERROR) << "Error: empty filter path given. Run with --help for help.";
+    return 0;
+  }
 
   absl::optional<AXTreeSelector> selector =
       tools::TreeSelectorFromCommandLine(*command_line);
@@ -65,8 +71,6 @@
     return 0;
   }
 
-  LOG(ERROR)
-      << "* Error: no accessible tree was identified to dump. Run with --help "
-         "for help.";
+  LOG(ERROR) << "Error: no accessible tree to dump. Run with --help for help.";
   return 1;
 }
diff --git a/tools/accessibility/inspect/ax_utils.cc b/tools/accessibility/inspect/ax_utils.cc
index a981c508..7836d55b 100644
--- a/tools/accessibility/inspect/ax_utils.cc
+++ b/tools/accessibility/inspect/ax_utils.cc
@@ -63,7 +63,14 @@
   printf("    --safari\tSafari browser\n");
 #endif
   printf(
-      "  --active-tab\tActive tab of browser, if application is a browser\n");
+      "  --active-tab\tactive tab of browser, if application is a browser\n");
+}
+
+void PrintHelpFooter() {
+  printf(
+      "\nmore info at "
+      "https://www.chromium.org/developers/accessibility/testing/"
+      "automated-testing/ax-inspect\n");
 }
 
 absl::optional<AXTreeSelector> TreeSelectorFromCommandLine(
diff --git a/tools/accessibility/inspect/ax_utils.h b/tools/accessibility/inspect/ax_utils.h
index 30860a61..fb538afe 100644
--- a/tools/accessibility/inspect/ax_utils.h
+++ b/tools/accessibility/inspect/ax_utils.h
@@ -14,6 +14,9 @@
 // Prints help for tree selectors like --pattern, --chromium etc.
 void PrintHelpForTreeSelectors();
 
+// Prints the help footer portion.
+void PrintHelpFooter();
+
 // Returns tree selector from command line arguments.
 absl::optional<ui::AXTreeSelector> TreeSelectorFromCommandLine(
     const base::CommandLine& command_line);
diff --git a/tools/binary_size/sizes.py b/tools/binary_size/sizes.py
index 4cf0aff..8b42d21 100755
--- a/tools/binary_size/sizes.py
+++ b/tools/binary_size/sizes.py
@@ -78,9 +78,8 @@
 
 
 def run_process(result, command):
-  # TODO: When converting to Python 3, pass param encoding='ascii'.
   p = subprocess.Popen(command, stdout=subprocess.PIPE)
-  stdout = p.communicate()[0]
+  stdout = p.communicate()[0].decode()
   if p.returncode != 0:
     print('ERROR from command "%s": %d' % (' '.join(command), p.returncode))
     if result == 0:
@@ -399,7 +398,7 @@
   # 1. Add a top-level "benchmark_name" key.
   # 2. Pull out the "identifier" value to be the story name.
   formatted_data = {}
-  for metric, metric_data in data.iteritems():
+  for metric, metric_data in data.items():
     story = metric_data['identifier']
     formatted_data[metric] = {story: metric_data.copy()}
     del formatted_data[metric][story]['identifier']
@@ -501,7 +500,7 @@
             'chartjson conversion failed: %s\n' % histogram_result.stdout)
         rc = rc or histogram_result.returncode
       else:
-        with open(histogram_path, 'w') as f:
+        with open(histogram_path, 'wb') as f:
           f.write(histogram_result.stdout)
     if result_sink_client:
       status = result_types.PASS
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 5cf7099..c4f1693 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -1003,6 +1003,10 @@
           '--unwindlib=none',
       ]
 
+      if target_arch == 'aarch64':
+        # Use PAC/BTI instructions for AArch64
+        cflags += [ '-mbranch-protection=standard' ]
+
       android_args = base_cmake_args + [
         '-DCMAKE_C_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang'),
         '-DCMAKE_CXX_COMPILER=' + os.path.join(LLVM_BUILD_DIR, 'bin/clang++'),
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 6dd392e..8e9495d3 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -35,7 +35,7 @@
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
 CLANG_REVISION = 'llvmorg-14-init-8564-g34b903d8'
-CLANG_SUB_REVISION = 8
+CLANG_SUB_REVISION = 9
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '14.0.0'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d714413..976710f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5520,6 +5520,18 @@
   <int value="2" label="Import with section union"/>
 </enum>
 
+<enum name="AutofillAssistantCaller">
+  <int value="0" label="UNKNOWN_CALLER"/>
+  <int value="1" label="ASSISTANT"/>
+  <int value="2" label="SEARCH"/>
+  <int value="3" label="STARTER_APP"/>
+  <int value="4" label="SEARCH_ADS"/>
+  <int value="5" label="SHOPPING_PROPERTY"/>
+  <int value="6" label="EMULATOR"/>
+  <int value="7" label="IN_CHROME"/>
+  <int value="8" label="DIRECT_ACTION"/>
+</enum>
+
 <enum name="AutofillAssistantCollectUserDataResult">
   <int value="0" label="Unknown result"/>
   <int value="1" label="Success"/>
@@ -5587,6 +5599,22 @@
   <int value="4" label="Trigger script requested"/>
 </enum>
 
+<enum name="AutofillAssistantIntent">
+  <int value="0" label="UNDEFINED_INTENT"/>
+  <int value="3" label="BUY_MOVIE_TICKET"/>
+  <int value="9" label="RENT_CAR"/>
+  <int value="10" label="SHOPPING"/>
+  <int value="11" label="TELEPORT"/>
+  <int value="14" label="SHOPPING_ASSISTED_CHECKOUT"/>
+  <int value="15" label="FLIGHTS_CHECKIN"/>
+  <int value="17" label="FOOD_ORDERING"/>
+  <int value="18" label="PASSWORD_CHANGE"/>
+  <int value="19" label="FOOD_ORDERING_PICKUP"/>
+  <int value="20" label="FOOD_ORDERING_DELIVERY"/>
+  <int value="22" label="UNLAUNCHED_VERTICAL_1"/>
+  <int value="25" label="FIND_COUPONS"/>
+</enum>
+
 <enum name="AutofillAssistantLiteScriptFinished">
   <int value="0" label="Unknown failure"/>
   <int value="1" label="Service deleted"/>
@@ -5690,6 +5718,28 @@
   <int value="3" label="Initially incomplete &amp; Failure"/>
 </enum>
 
+<enum name="AutofillAssistantSource">
+  <int value="0" label="UNKNOWN_SOURCE"/>
+  <int value="1" label="ORGANIC"/>
+  <int value="2" label="FRESH_DEEPLINK"/>
+  <int value="3" label="STARTER_APP"/>
+  <int value="4" label="EMULATOR_VALIDATION"/>
+  <int value="5" label="S_API"/>
+  <int value="6" label="C_CARD"/>
+  <int value="7" label="MD_CARD"/>
+  <int value="8" label="C_NOTIFICATION"/>
+  <int value="9" label="G_CAROUSEL"/>
+</enum>
+
+<enum name="AutofillAssistantStarted">
+  <int value="0" label="FAILED_FEATURE_DISABLED"/>
+  <int value="1" label="FAILED_MANDATORY_PARAMETER_MISSING"/>
+  <int value="2" label="FAILED_SETTING_DISABLED"/>
+  <int value="3" label="FAILED_NO_INITIAL_URL"/>
+  <int value="4" label="OK_DELAYED_START"/>
+  <int value="5" label="OK_IMMEDIATE_START"/>
+</enum>
+
 <enum name="AutofillAssistantTextToSpeechButtonAction">
   <int value="0" label="Play TTS"/>
   <int value="1" label="Disable button"/>
@@ -52400,6 +52450,8 @@
   <int value="628302973" label="NTPSnippets:enabled"/>
   <int value="628570445" label="AndroidAutofillAccessibility:enabled"/>
   <int value="629549626" label="ContextualSearchMlTapSuppression:enabled"/>
+  <int value="629635604"
+      label="AutofillVisualImprovementsForSuggestionUi:enabled"/>
   <int value="630244477" label="ServiceWorkerPaymentApps:enabled"/>
   <int value="630308195" label="SignInProfileCreation:enabled"/>
   <int value="630776247" label="USBGuard:disabled"/>
@@ -53847,6 +53899,8 @@
       label="AutofillUseUnassociatedListedElements:enabled"/>
   <int value="1710630380"
       label="AutofillEnableSupportForMoreStructureInNames:enabled"/>
+  <int value="1711037950"
+      label="AutofillVisualImprovementsForSuggestionUi:disabled"/>
   <int value="1711286384" label="ContextMenuCopyImage:disabled"/>
   <int value="1712622545" label="Memories:disabled"/>
   <int value="1712697097" label="QuickAnswersV2:disabled"/>
@@ -73520,7 +73574,8 @@
       label="Remote and local bookmarks types don't match (URL vs. Folder)"/>
   <int value="1" label="Invalid specifics"/>
   <int value="2" label="Invalid unique position (deprecated)"/>
-  <int value="3" label="Permanent node creation in an incremental update"/>
+  <int value="3"
+      label="Permanent node creation in an incremental update (deprecated)"/>
   <int value="4" label="Parent entity not found in server"/>
   <int value="5" label="Parent node not found locally"/>
   <int value="6"
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 2ed6c1ad..3cd07270 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -296,6 +296,9 @@
 
 <histogram name="Android.AutofillAssistant.OnBoarding{Intent}"
     enum="AutofillAssistantOnBoarding" expires_after="2022-06-08">
+  <obsolete>
+    Removed in November 2021.
+  </obsolete>
   <owner>lsuder@chromium.org</owner>
   <owner>mcarlen@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/crostini/histograms.xml b/tools/metrics/histograms/metadata/crostini/histograms.xml
index 0f44aff27..dcb358e7 100644
--- a/tools/metrics/histograms/metadata/crostini/histograms.xml
+++ b/tools/metrics/histograms/metadata/crostini/histograms.xml
@@ -36,9 +36,9 @@
 </variants>
 
 <histogram name="Crostini.AppLaunch" enum="CrostiniAppLaunchAppType"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time a Crostini app is launched, recording whether the app is
     the built in terminal, a registered app, or an unknown app.
@@ -48,14 +48,14 @@
 <histogram name="Crostini.AppLaunchResult" enum="CrostiniResult"
     expires_after="2022-05-01">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The result of attempting to launch a Crostini app (including Terminal).
   </summary>
 </histogram>
 
 <histogram name="Crostini.AppLaunchResult.{Variant}" enum="CrostiniResult"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>davidmunro@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>The result of attempting to launch {Variant}.</summary>
@@ -69,7 +69,7 @@
 <histogram name="Crostini.AppsInstalledAtLogin" units="apps"
     expires_after="2022-05-01">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Records the number of Crostini apps that surface in the launcher at login
     time (not including the Terminal). This only logs if Crostini is enabled for
@@ -78,9 +78,9 @@
 </histogram>
 
 <histogram name="Crostini.AvailableDiskCancel" units="MiB"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The available disk space at the start of the crostini install flow, recorded
     when installation was canceled. This is recorded any time the user cancels
@@ -90,9 +90,9 @@
 </histogram>
 
 <histogram name="Crostini.AvailableDiskError" units="MiB"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The available disk space at the start of the crostini install flow, recorded
     when installation returned an error. This is recorded any time the user
@@ -102,9 +102,9 @@
 </histogram>
 
 <histogram name="Crostini.AvailableDiskSuccess" units="MiB"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The available disk space at the start of the crostini install flow, recorded
     when installation succeeded. This is recorded any time the user successfully
@@ -116,14 +116,14 @@
 <histogram name="Crostini.Backup" enum="CrostiniExportContainerResult"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Result of crostini backup.</summary>
 </histogram>
 
 <histogram name="Crostini.BackupCompressedSizeLog2" units="units"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     log base 2 of compressed container backup size in bytes, rounded to the
     nearest integer. Value is between 0 and 50, to give good granularity for
@@ -132,9 +132,9 @@
 </histogram>
 
 <histogram name="Crostini.BackupContainerSizeLog2" units="units"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     log base 2 of uncompressed container image size in bytes, rounded to the
     nearest integer. Value is between 0 and 50, to give good granularity for
@@ -143,9 +143,9 @@
 </histogram>
 
 <histogram name="Crostini.BackupSizeRatio" units="units"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     100 * compressed size / container size. The conventional compression ratio
     of input / output has not been used as the resulting value is unbounded.
@@ -153,23 +153,23 @@
 </histogram>
 
 <histogram name="Crostini.BackupTimeFailed" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Time taken for failed backup.</summary>
 </histogram>
 
 <histogram name="Crostini.BackupTimeSuccess" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Time taken for successful backup.</summary>
 </histogram>
 
 <histogram name="Crostini.CleanSession.RestarterResult" enum="CrostiniResult"
     expires_after="2022-05-01">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The result of a single run of CrostiniRestarter. This is the same as
     Crostini.RestarterResult except only emitted in sessions that happen after a
@@ -180,7 +180,7 @@
 <histogram name="Crostini.ContainerOsVersion" enum="CrostiniContainerOsVersion"
     expires_after="2022-04-10">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time a Crostini container is launched, recording the OS
     version running inside the container.
@@ -190,7 +190,7 @@
 <histogram name="Crostini.Crosvm.CpuPercentage" units="%"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The percentage of the system CPU that crosvm processes used during the
     10-minute measuring period. This is recorded once every 10 minutes when
@@ -201,7 +201,7 @@
 <histogram name="Crostini.Crosvm.Processes.Count" units="processes"
     expires_after="2022-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The number of crosvm processes that are running at the end of the 10-minute
     interval. This is recorded once every 10 minutes when crosvm is running.
@@ -211,7 +211,7 @@
 <histogram name="Crostini.Crosvm.RssPercentage" units="%"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The percentage of the system memory that crosvm processes used at the end of
     the 10-minute measuring period. This is recorded once every 10 minutes when
@@ -230,7 +230,7 @@
 </histogram>
 
 <histogram name="Crostini.DiskResize.Started" enum="BooleanAttempted"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
   <owner>davidmunro@google.com</owner>
   <summary>
@@ -255,7 +255,7 @@
 </histogram>
 
 <histogram name="Crostini.EngagementTime.{Variant}" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>davidmunro@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>
@@ -289,7 +289,7 @@
 <histogram name="Crostini.FilesystemCorruption" enum="CorruptionStates"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Filesystem corruption events in the crostini VM, recorded every time
     corruption is observed to affect the state of the system.
@@ -308,9 +308,9 @@
 </histogram>
 
 <histogram name="Crostini.InvalidStateTransition" enum="CrostiniInstallerState"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Emitted when an invalid request to transition states during the Crostini
     restarter flow is received. For example, when a container start signal is
@@ -321,9 +321,9 @@
 </histogram>
 
 <histogram name="Crostini.RecoverySource" enum="CrostiniUISurface"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the CrostiniRecoveryView is show, on detecting that a VM
     is still running after a Chrome crash.
@@ -333,7 +333,7 @@
 <histogram name="Crostini.Restarter.Started" enum="BooleanAttempted"
     expires_after="2022-05-01">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Emitted whenever a run of CrostiniRestarter is triggered except during the
     initial install.
@@ -343,7 +343,7 @@
 <histogram name="Crostini.RestarterResult" enum="CrostiniResult"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The result of a single run of CrostiniRestarter. This is recorded any time
     the crostini restart flow is triggered except during the initial install.
@@ -351,12 +351,12 @@
 </histogram>
 
 <histogram name="Crostini.RestarterTimeInState.{state}" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <obsolete>
     Removed in M93, and had misleading data before M93. Do not use.
   </obsolete>
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Was intended to be time spent in each state in the restarter flow, but there
     were some issues with how the metric was emitted. Use
@@ -366,9 +366,9 @@
 </histogram>
 
 <histogram name="Crostini.RestarterTimeInState2.{state}" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Base histogram for measuring how much time the restarter flow spends in the
     {state} state, used to set timeouts. Note that this since this is for any
@@ -381,30 +381,30 @@
 </histogram>
 
 <histogram name="Crostini.Restore" enum="CrostiniImportContainerResult"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Result of crostini restore.</summary>
 </histogram>
 
 <histogram name="Crostini.RestoreTimeFailed" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Time taken for failed restore.</summary>
 </histogram>
 
 <histogram name="Crostini.RestoreTimeSuccess" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>Time taken for successful restore.</summary>
 </histogram>
 
 <histogram name="Crostini.SettingsEvent" enum="CrostiniSettingsEvent"
     expires_after="2022-04-24">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <owner>victorhsieh@chromium.org</owner>
   <summary>Record user's choice in Crostini Settings</summary>
 </histogram>
@@ -412,7 +412,7 @@
 <histogram name="Crostini.Setup.Started" enum="BooleanAttempted"
     expires_after="2022-05-01">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Emitted whenever a run of CrostiniRestarter is triggered during the initial
     install.
@@ -434,7 +434,7 @@
 <histogram name="Crostini.SetupResult" enum="CrostiniSetupResult"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user completes the Crostini setup UI, recording the
     result of the setup.
@@ -442,9 +442,9 @@
 </histogram>
 
 <histogram name="Crostini.SetupSource" enum="CrostiniUISurface"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user initiates the Crostini setup UI, recording the
     UI surface that invoked the setup.
@@ -503,7 +503,7 @@
 <histogram name="Crostini.Stability" enum="GuestOsFailureClasses"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     A record of post-startup failures in crostini components. Buckets are
     recorded to whenever we become aware that the corresponding component has
@@ -514,7 +514,7 @@
 <histogram name="Crostini.TerminalSettingsChanged"
     enum="CrostiniTerminalSetting" expires_after="2022-04-17">
   <owner>joelhockey@chromium.org</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Record which settings in terminal are changed by users. This is captured
     each time terminal is launched and fetches the current settings, and not
@@ -524,9 +524,9 @@
 </histogram>
 
 <histogram name="Crostini.TimeFromDeviceSetupToInstall" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The time from a user setting up their device, to the user enabling Crostini.
   </summary>
@@ -535,7 +535,7 @@
 <histogram name="Crostini.TimeToInstallCancel" units="ms"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The time taken for the crostini installer to be canceled by the user. This
     is recorded any time the user cancels the install before it finishes. This
@@ -544,9 +544,9 @@
 </histogram>
 
 <histogram name="Crostini.TimeToInstallError" units="ms"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The time taken for the crostini installer to fail due to an error. This is
     recorded any time the user tries to install install crostini and gets an
@@ -558,7 +558,7 @@
 <histogram name="Crostini.TimeToInstallSuccess" units="ms"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The time taken for the crostini installer to finish successfully. This is
     recorded any time the user successfully installs crostini. This includes
@@ -567,9 +567,9 @@
 </histogram>
 
 <histogram name="Crostini.UncleanSession.RestarterResult" enum="CrostiniResult"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     The result of a single run of CrostiniRestarter. This is the same as
     Crostini.RestarterResult except only emitted in sessions that happen after
@@ -580,7 +580,7 @@
 <histogram name="Crostini.UninstallResult" enum="CrostiniUninstallResult"
     expires_after="2022-05-15">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user completes the Crostini uninstall UI, recording
     the result of the uninstall.
@@ -588,9 +588,9 @@
 </histogram>
 
 <histogram name="Crostini.UninstallSource" enum="CrostiniUISurface"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user initiates the Crostini uninstall UI, recording
     the UI surface that initiated the uninstall.
@@ -600,7 +600,7 @@
 <histogram base="true" name="Crostini.UnsupportedNotification.Reason"
     enum="CrostiniUnsupportedNotificationReason" expires_after="2022-04-17">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time we display (or would display, see suffixes) a
     notification that the user is trying to do something Crostini doesn't
@@ -610,9 +610,9 @@
 
 <histogram name="Crostini.UpgradeAvailable"
     enum="CrostiniUpgradeAvailableNotificationClosed"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user sees the Crostini upgrade Notifiation, recording
     the action that closded the notification.
@@ -620,9 +620,9 @@
 </histogram>
 
 <histogram name="Crostini.UpgradeDialogEvent" enum="CrostiniUpgradeDialogEvent"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     A collection of events that can occur while upgrading the crostini
     container, recorded as they occur.
@@ -630,9 +630,9 @@
 </histogram>
 
 <histogram name="Crostini.UpgradeSource" enum="CrostiniUISurface"
-    expires_after="2022-01-06">
+    expires_after="2023-01-06">
   <owner>clumptini@google.com</owner>
-  <owner>tbuckley@chromium.org</owner>
+  <owner>laurentt@google.com</owner>
   <summary>
     Recorded each time the user sees the Crostini upgrade UI, recording the UI
     surface that initiated the upgrade.
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 857720b..7b6ea81 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -271,6 +271,20 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Cellular.ESim.Policy.EuiccStatusUploadResult"
+    enum="BooleanSuccess" expires_after="2022-05-01">
+  <owner>azeemarshad@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>jiajunz@google.com</owner>
+  <summary>
+    Tracks the result of an attempt to upload euicc status to DM server. This
+    metric provides the insights on how often ICCID/SM-DP+ get uploaded to the
+    DM server and whether the upload operation is successful or not.
+
+    Emitted once the euicc status upload operation completes.
+  </summary>
+</histogram>
+
 <histogram name="Network.Cellular.ESim.Policy.ResetEuicc.Duration" units="ms"
     expires_after="2022-09-01">
   <owner>azeemarshad@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index d4eee3b..ef1007d 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -315,18 +315,6 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="PasswordManager.AccountsPerSiteHiRes"
-    units="units" expires_after="2022-04-24">
-  <owner>kazinova@google.com</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    The number of accounts stored per site in the password manager's
-    profile-scoped store. Records one event per site, split by whether created
-    by the user or generated by Chrome, and further by whether the user used
-    sync with custom passphrase or not.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.AccountStorage.ClearedOnStartup"
     enum="PasswordAccountStoreClearedOnStartup" expires_after="2022-05-31">
   <owner>mamir@chromium.org</owner>
@@ -472,19 +460,6 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="PasswordManager.AccountStore.AccountsPerSiteHiRes"
-    units="units" expires_after="2022-05-01">
-  <owner>mamir@chromium.org</owner>
-  <owner>treib@chromium.org</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    The number of accounts stored per site in the password manager's
-    account-scoped store. Records one event per site, split by whether created
-    by the user or generated by Chrome, and further by whether the user used
-    sync with custom passphrase or not.
-  </summary>
-</histogram>
-
 <histogram base="true"
     name="PasswordManager.AccountStore.BlacklistedSitesHiRes" units="sites"
     expires_after="2022-05-01">
@@ -2979,6 +2954,24 @@
   <summary>Logs the loading time for the gstatic file request.</summary>
 </histogram>
 
+<histogram base="true" name="PasswordManager.{Store}AccountsPerSiteHiRes"
+    units="units" expires_after="2022-04-24">
+  <owner>kazinova@google.com</owner>
+  <owner>vasilii@chromium.org</owner>
+  <owner>mamir@chromium.org</owner>
+  <owner>treib@chromium.org</owner>
+  <summary>
+    The number of accounts stored per site in the password manager's {Store}.
+    Records one event per site, split by whether created by the user or
+    generated by Chrome, and further by whether the user use sync with custom
+    passphrase or not.
+  </summary>
+  <token key="Store">
+    <variant name="" summary="for profile-scoped store"/>
+    <variant name="AccountStore." summary="for account-scoped store"/>
+  </token>
+</histogram>
+
 <histogram name="PasswordProtection.AndroidVisualFeaturesNativeViewHeight"
     units="dip" expires_after="2021-10-04">
   <obsolete>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index 3d20969a5..510484aca 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -35,6 +35,16 @@
       summary="Renderer process was alive for up to one minute."/>
 </variants>
 
+<histogram name="Renderer.BrowserLaunchToRunLoopStart" units="ms"
+    expires_after="M104">
+  <owner>sky@chromium.org</owner>
+  <owner>jam@chromium.org</owner>
+  <summary>
+    Time (in milliseconds) between when browser launches renderer and renderer
+    message loop starts.
+  </summary>
+</histogram>
+
 <histogram name="Renderer.CompositedScrolling" enum="CompositedScrolling"
     expires_after="M85">
   <obsolete>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index 61d6427..a06a0010 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -950,7 +950,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.TargetJitterBufferDelayMs" units="ms"
-    expires_after="2021-12-26">
+    expires_after="2022-12-26">
   <owner>hlundin@chromium.org</owner>
   <summary>
     The target jitter buffer delay for the receiving side. Sampled once every 10
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index f37f5c6..2b86fc8ec 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -2359,6 +2359,90 @@
   </metric>
 </event>
 
+<event name="AutofillAssistant.RegularScriptOnboarding">
+  <owner>arbesser@google.com</owner>
+  <owner>hluca@google.com</owner>
+  <owner>autofill_assistant@google.com</owner>
+  <summary>
+    Various metrics related to the onboarding during regular scripts. This is
+    recorded at the start of a regular script.
+  </summary>
+  <metric name="Onboarding" enum="AutofillAssistantOnBoarding">
+    <summary>
+      The various ways in which the onboarding may complete or fail.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+</event>
+
+<event name="AutofillAssistant.StartRequest">
+  <owner>arbesser@google.com</owner>
+  <owner>hluca@google.com</owner>
+  <owner>autofill_assistant@google.com</owner>
+  <summary>
+    Metrics collected at the very beginning of an autofill-assistant flow.
+  </summary>
+  <metric name="Caller" enum="AutofillAssistantCaller">
+    <summary>
+      The caller that requested the start of a flow.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+  <metric name="Experiments">
+    <summary>
+      Bitmask of the running experiments.
+    </summary>
+  </metric>
+  <metric name="Intent" enum="AutofillAssistantIntent">
+    <summary>
+      The autofill-assistant intent of a flow.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+  <metric name="Source" enum="AutofillAssistantSource">
+    <summary>
+      The source that requested the start of a flow.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+  <metric name="Started" enum="AutofillAssistantStarted">
+    <summary>
+      The various ways that a start request may succeed or fail.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+</event>
+
 <event name="AutofillAssistant.Timing">
   <owner>arbesser@google.com</owner>
   <owner>hluca@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d9dcc7b..918be97 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,11 +6,11 @@
         },
         "win": {
             "hash": "801822775cfa442ec07be8385f42d95a8eb81d07",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/c4b9d71ef44ddbf48ca74f35c166eaeb1f709dfb/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/889d9a924c20a88305e1c82ab9a4273e664c0410/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "87ea36cb679df339c481aa3f0e23a6d3fc96a876",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/c4b9d71ef44ddbf48ca74f35c166eaeb1f709dfb/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/889d9a924c20a88305e1c82ab9a4273e664c0410/trace_processor_shell"
         },
         "linux_arm64": {
             "hash": "5074025a2898ec41a872e70a5719e417acb0a380",
@@ -18,7 +18,7 @@
         },
         "linux": {
             "hash": "de1e69173caee82057527f96d693b457363e05d3",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/c4b9d71ef44ddbf48ca74f35c166eaeb1f709dfb/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/889d9a924c20a88305e1c82ab9a4273e664c0410/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/events/devices/haptic_touchpad_effects.h b/ui/events/devices/haptic_touchpad_effects.h
index 711c3e7..a117d93 100644
--- a/ui/events/devices/haptic_touchpad_effects.h
+++ b/ui/events/devices/haptic_touchpad_effects.h
@@ -8,11 +8,16 @@
 namespace ui {
 
 enum class HapticTouchpadEffect {
-  kSnap = 0,    // UI feedback for snapping into place.
-  kKnock = 1,   // UI feedback for reaching a limit or boundary.
-  kTick = 2,    // UI feedback for discrete state changes.
-  kPress = 3,   // Standard touchpad button down effect.
-  kRelease = 4  // Standard touchpad button up effect.
+  kSnap = 0,         // UI feedback for snapping into place.
+  kSnapReverse = 1,  // UI feedback for snapping out of place.
+  kKnock = 2,        // UI feedback for reaching a limit or boundary.
+  kTick = 3,         // UI feedback for discrete state changes.
+  kToggleOn = 4,     // UI feedback for activating a feature.
+  kToggleOff = 5,    // UI feedback for deactivating a feature.
+  kPress = 6,        // Standard touchpad button down effect.
+  kRelease = 7,      // Standard touchpad button up effect.
+  kDeepPress = 8,    // Deeper (more force) touchpad button down effect.
+  kDeepRelease = 9   // Deeper (more force) touchpad button up effect.
 };
 
 // Modifies the intensity of effects.
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
index 3139e148..8e9ebadf 100644
--- a/ui/events/ozone/evdev/event_device_info.cc
+++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -39,6 +39,7 @@
     {0x045e, 0x0821},  // Microsoft Surface Precision Mouse
     {0x045e, 0x082a},  // Microsoft Pro IntelliMouse
     {0x045e, 0x082f},  // Microsoft Bluetooth Mouse
+    {0x045e, 0x095d},  // Microsoft Surface Mobile Mouse
     {0x045e, 0x0b05},  // Xbox One Elite Series 2 gamepad
     {0x046d, 0x4026},  // Logitech T400
     {0x046d, 0x405e},  // Logitech M720 Triathlon (Unifying)
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 821acfd..111d8de8 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -218,6 +218,8 @@
       sources += [
         "gl_angle_util_vulkan.cc",
         "gl_angle_util_vulkan.h",
+        "gl_image_egl_angle_vulkan.cc",
+        "gl_image_egl_angle_vulkan.h",
       ]
     }
 
diff --git a/ui/gl/egl_bindings_autogen_mock.cc b/ui/gl/egl_bindings_autogen_mock.cc
index 465eb12..76aa03a6 100644
--- a/ui/gl/egl_bindings_autogen_mock.cc
+++ b/ui/gl/egl_bindings_autogen_mock.cc
@@ -214,6 +214,16 @@
 }
 
 EGLBoolean GL_BINDING_CALL
+MockEGLInterface::Mock_eglExportVkImageANGLE(EGLDisplay dpy,
+                                             EGLImageKHR image,
+                                             void* vk_image,
+                                             void* vk_image_create_info) {
+  MakeEglMockFunctionUnique("eglExportVkImageANGLE");
+  return interface_->ExportVkImageANGLE(dpy, image, vk_image,
+                                        vk_image_create_info);
+}
+
+EGLBoolean GL_BINDING_CALL
 MockEGLInterface::Mock_eglGetCompositorTimingANDROID(EGLDisplay dpy,
                                                      EGLSurface surface,
                                                      EGLint numTimestamps,
@@ -717,6 +727,8 @@
   if (strcmp(name, "eglExportDMABUFImageQueryMESA") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_eglExportDMABUFImageQueryMESA);
+  if (strcmp(name, "eglExportVkImageANGLE") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_eglExportVkImageANGLE);
   if (strcmp(name, "eglGetCompositorTimingANDROID") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_eglGetCompositorTimingANDROID);
diff --git a/ui/gl/egl_bindings_autogen_mock.h b/ui/gl/egl_bindings_autogen_mock.h
index 9ac9b43..ef02cce 100644
--- a/ui/gl/egl_bindings_autogen_mock.h
+++ b/ui/gl/egl_bindings_autogen_mock.h
@@ -97,6 +97,11 @@
                                    int* num_planes,
                                    EGLuint64KHR* modifiers);
 static EGLBoolean GL_BINDING_CALL
+Mock_eglExportVkImageANGLE(EGLDisplay dpy,
+                           EGLImageKHR image,
+                           void* vk_image,
+                           void* vk_image_create_info);
+static EGLBoolean GL_BINDING_CALL
 Mock_eglGetCompositorTimingANDROID(EGLDisplay dpy,
                                    EGLSurface surface,
                                    EGLint numTimestamps,
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index fd3a1667..e9d6bf9 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -46,6 +46,11 @@
 """
 GL_FUNCTIONS = [
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glAcquireTexturesANGLE',
+                 'extensions': ['GL_ANGLE_vulkan_image'] }],
+  'arguments': 'GLuint numTextures, const GLuint* textures, '
+               'const GLenum* layouts', },
+{ 'return_type': 'void',
   'names': ['glActiveShaderProgram'],
   'arguments': 'GLuint pipeline, GLuint program', },
 { 'return_type': 'void',
@@ -1814,6 +1819,10 @@
   'names': ['glReleaseShaderCompiler'],
   'arguments': 'void', },
 { 'return_type': 'void',
+  'versions': [{ 'name': 'glReleaseTexturesANGLE',
+                 'extensions': ['GL_ANGLE_vulkan_image'] }],
+  'arguments': 'GLuint numTextures, const GLuint* textures, GLenum* layouts', },
+{ 'return_type': 'void',
   'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
   'arguments':
       'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
@@ -2492,6 +2501,12 @@
   'arguments': 'EGLDisplay dpy, EGLImageKHR image, int* fourcc, '
                'int* num_planes, EGLuint64KHR* modifiers', },
 { 'return_type': 'EGLBoolean',
+    'versions': [{'name': 'eglExportVkImageANGLE',
+                  'extensions':
+                      ['EGL_ANGLE_vulkan_image']}],
+  'arguments': 'EGLDisplay dpy, EGLImageKHR image, void* vk_image, '
+               'void* vk_image_create_info', },
+{ 'return_type': 'EGLBoolean',
   'versions': [{ 'name': 'eglGetCompositorTimingANDROID',
                  'extensions': [
                    'EGL_ANDROID_get_frame_timestamps'
diff --git a/ui/gl/gl_bindings_api_autogen_egl.h b/ui/gl/gl_bindings_api_autogen_egl.h
index 1b49caa5..b89993c 100644
--- a/ui/gl/gl_bindings_api_autogen_egl.h
+++ b/ui/gl/gl_bindings_api_autogen_egl.h
@@ -81,6 +81,10 @@
                                            int* fourcc,
                                            int* num_planes,
                                            EGLuint64KHR* modifiers) override;
+EGLBoolean eglExportVkImageANGLEFn(EGLDisplay dpy,
+                                   EGLImageKHR image,
+                                   void* vk_image,
+                                   void* vk_image_create_info) override;
 EGLBoolean eglGetCompositorTimingANDROIDFn(EGLDisplay dpy,
                                            EGLSurface surface,
                                            EGLint numTimestamps,
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index 7925a744..fa7b5eab 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -12,6 +12,9 @@
 // no-include-guard-because-multiply-included
 // NOLINT(build/header_guard)
 
+void glAcquireTexturesANGLEFn(GLuint numTextures,
+                              const GLuint* textures,
+                              const GLenum* layouts) override;
 void glActiveShaderProgramFn(GLuint pipeline, GLuint program) override;
 void glActiveTextureFn(GLenum texture) override;
 void glAttachShaderFn(GLuint program, GLuint shader) override;
@@ -1208,6 +1211,9 @@
                                GLsizei* rows,
                                void* pixels) override;
 void glReleaseShaderCompilerFn(void) override;
+void glReleaseTexturesANGLEFn(GLuint numTextures,
+                              const GLuint* textures,
+                              GLenum* layouts) override;
 void glRenderbufferStorageEXTFn(GLenum target,
                                 GLenum internalformat,
                                 GLsizei width,
diff --git a/ui/gl/gl_bindings_autogen_egl.cc b/ui/gl/gl_bindings_autogen_egl.cc
index f1dc692..748eed9 100644
--- a/ui/gl/gl_bindings_autogen_egl.cc
+++ b/ui/gl/gl_bindings_autogen_egl.cc
@@ -203,6 +203,8 @@
       extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle");
   ext.b_EGL_ANGLE_sync_control_rate =
       gfx::HasExtension(extensions, "EGL_ANGLE_sync_control_rate");
+  ext.b_EGL_ANGLE_vulkan_image =
+      gfx::HasExtension(extensions, "EGL_ANGLE_vulkan_image");
   ext.b_EGL_CHROMIUM_sync_control =
       gfx::HasExtension(extensions, "EGL_CHROMIUM_sync_control");
   ext.b_EGL_EXT_image_flush_external =
@@ -270,6 +272,11 @@
             GetGLProcAddress("eglExportDMABUFImageQueryMESA"));
   }
 
+  if (ext.b_EGL_ANGLE_vulkan_image) {
+    fn.eglExportVkImageANGLEFn = reinterpret_cast<eglExportVkImageANGLEProc>(
+        GetGLProcAddress("eglExportVkImageANGLE"));
+  }
+
   if (ext.b_EGL_ANDROID_get_frame_timestamps) {
     fn.eglGetCompositorTimingANDROIDFn =
         reinterpret_cast<eglGetCompositorTimingANDROIDProc>(
@@ -566,6 +573,14 @@
                                                      num_planes, modifiers);
 }
 
+EGLBoolean EGLApiBase::eglExportVkImageANGLEFn(EGLDisplay dpy,
+                                               EGLImageKHR image,
+                                               void* vk_image,
+                                               void* vk_image_create_info) {
+  return driver_->fn.eglExportVkImageANGLEFn(dpy, image, vk_image,
+                                             vk_image_create_info);
+}
+
 EGLBoolean EGLApiBase::eglGetCompositorTimingANDROIDFn(
     EGLDisplay dpy,
     EGLSurface surface,
@@ -1090,6 +1105,15 @@
                                                    num_planes, modifiers);
 }
 
+EGLBoolean TraceEGLApi::eglExportVkImageANGLEFn(EGLDisplay dpy,
+                                                EGLImageKHR image,
+                                                void* vk_image,
+                                                void* vk_image_create_info) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceEGLAPI::eglExportVkImageANGLE");
+  return egl_api_->eglExportVkImageANGLEFn(dpy, image, vk_image,
+                                           vk_image_create_info);
+}
+
 EGLBoolean TraceEGLApi::eglGetCompositorTimingANDROIDFn(
     EGLDisplay dpy,
     EGLSurface surface,
@@ -1777,6 +1801,20 @@
   return result;
 }
 
+EGLBoolean LogEGLApi::eglExportVkImageANGLEFn(EGLDisplay dpy,
+                                              EGLImageKHR image,
+                                              void* vk_image,
+                                              void* vk_image_create_info) {
+  GL_SERVICE_LOG("eglExportVkImageANGLE"
+                 << "(" << dpy << ", " << image << ", "
+                 << static_cast<const void*>(vk_image) << ", "
+                 << static_cast<const void*>(vk_image_create_info) << ")");
+  EGLBoolean result = egl_api_->eglExportVkImageANGLEFn(dpy, image, vk_image,
+                                                        vk_image_create_info);
+  GL_SERVICE_LOG("GL_RESULT: " << result);
+  return result;
+}
+
 EGLBoolean LogEGLApi::eglGetCompositorTimingANDROIDFn(EGLDisplay dpy,
                                                       EGLSurface surface,
                                                       EGLint numTimestamps,
diff --git a/ui/gl/gl_bindings_autogen_egl.h b/ui/gl/gl_bindings_autogen_egl.h
index 09ca4f2..f8f266b7 100644
--- a/ui/gl/gl_bindings_autogen_egl.h
+++ b/ui/gl/gl_bindings_autogen_egl.h
@@ -106,6 +106,11 @@
     int* fourcc,
     int* num_planes,
     EGLuint64KHR* modifiers);
+typedef EGLBoolean(GL_BINDING_CALL* eglExportVkImageANGLEProc)(
+    EGLDisplay dpy,
+    EGLImageKHR image,
+    void* vk_image,
+    void* vk_image_create_info);
 typedef EGLBoolean(GL_BINDING_CALL* eglGetCompositorTimingANDROIDProc)(
     EGLDisplay dpy,
     EGLSurface surface,
@@ -312,6 +317,7 @@
   bool b_EGL_ANGLE_stream_producer_d3d_texture;
   bool b_EGL_ANGLE_surface_d3d_texture_2d_share_handle;
   bool b_EGL_ANGLE_sync_control_rate;
+  bool b_EGL_ANGLE_vulkan_image;
   bool b_EGL_CHROMIUM_sync_control;
   bool b_EGL_EXT_image_flush_external;
   bool b_EGL_KHR_fence_sync;
@@ -354,6 +360,7 @@
   eglDupNativeFenceFDANDROIDProc eglDupNativeFenceFDANDROIDFn;
   eglExportDMABUFImageMESAProc eglExportDMABUFImageMESAFn;
   eglExportDMABUFImageQueryMESAProc eglExportDMABUFImageQueryMESAFn;
+  eglExportVkImageANGLEProc eglExportVkImageANGLEFn;
   eglGetCompositorTimingANDROIDProc eglGetCompositorTimingANDROIDFn;
   eglGetCompositorTimingSupportedANDROIDProc
       eglGetCompositorTimingSupportedANDROIDFn;
@@ -499,6 +506,10 @@
       int* fourcc,
       int* num_planes,
       EGLuint64KHR* modifiers) = 0;
+  virtual EGLBoolean eglExportVkImageANGLEFn(EGLDisplay dpy,
+                                             EGLImageKHR image,
+                                             void* vk_image,
+                                             void* vk_image_create_info) = 0;
   virtual EGLBoolean eglGetCompositorTimingANDROIDFn(
       EGLDisplay dpy,
       EGLSurface surface,
@@ -702,6 +713,8 @@
   ::gl::g_current_egl_context->eglExportDMABUFImageMESAFn
 #define eglExportDMABUFImageQueryMESA \
   ::gl::g_current_egl_context->eglExportDMABUFImageQueryMESAFn
+#define eglExportVkImageANGLE \
+  ::gl::g_current_egl_context->eglExportVkImageANGLEFn
 #define eglGetCompositorTimingANDROID \
   ::gl::g_current_egl_context->eglGetCompositorTimingANDROIDFn
 #define eglGetCompositorTimingSupportedANDROID \
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 9ee7dc86..767e864e 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -309,6 +309,8 @@
       gfx::HasExtension(extensions, "GL_ANGLE_texture_external_update");
   ext.b_GL_ANGLE_translated_shader_source =
       gfx::HasExtension(extensions, "GL_ANGLE_translated_shader_source");
+  ext.b_GL_ANGLE_vulkan_image =
+      gfx::HasExtension(extensions, "GL_ANGLE_vulkan_image");
   ext.b_GL_ANGLE_webgl_compatibility =
       gfx::HasExtension(extensions, "GL_ANGLE_webgl_compatibility");
   ext.b_GL_APPLE_fence = gfx::HasExtension(extensions, "GL_APPLE_fence");
@@ -475,6 +477,11 @@
   ext.b_GL_QCOM_tiled_rendering =
       gfx::HasExtension(extensions, "GL_QCOM_tiled_rendering");
 
+  if (ext.b_GL_ANGLE_vulkan_image) {
+    fn.glAcquireTexturesANGLEFn = reinterpret_cast<glAcquireTexturesANGLEProc>(
+        GetGLProcAddress("glAcquireTexturesANGLE"));
+  }
+
   if (ver->IsAtLeastGL(4u, 1u) || ver->IsAtLeastGLES(3u, 1u)) {
     fn.glActiveShaderProgramFn = reinterpret_cast<glActiveShaderProgramProc>(
         GetGLProcAddress("glActiveShaderProgram"));
@@ -2518,6 +2525,11 @@
             GetGLProcAddress("glReleaseShaderCompiler"));
   }
 
+  if (ext.b_GL_ANGLE_vulkan_image) {
+    fn.glReleaseTexturesANGLEFn = reinterpret_cast<glReleaseTexturesANGLEProc>(
+        GetGLProcAddress("glReleaseTexturesANGLE"));
+  }
+
   if (ver->IsAtLeastGL(3u, 0u) || ver->is_es) {
     fn.glRenderbufferStorageEXTFn =
         reinterpret_cast<glRenderbufferStorageEXTProc>(
@@ -3048,6 +3060,12 @@
   memset(this, 0, sizeof(*this));
 }
 
+void GLApiBase::glAcquireTexturesANGLEFn(GLuint numTextures,
+                                         const GLuint* textures,
+                                         const GLenum* layouts) {
+  driver_->fn.glAcquireTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void GLApiBase::glActiveShaderProgramFn(GLuint pipeline, GLuint program) {
   driver_->fn.glActiveShaderProgramFn(pipeline, program);
 }
@@ -5522,6 +5540,12 @@
   driver_->fn.glReleaseShaderCompilerFn();
 }
 
+void GLApiBase::glReleaseTexturesANGLEFn(GLuint numTextures,
+                                         const GLuint* textures,
+                                         GLenum* layouts) {
+  driver_->fn.glReleaseTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void GLApiBase::glRenderbufferStorageEXTFn(GLenum target,
                                            GLenum internalformat,
                                            GLsizei width,
@@ -6410,6 +6434,13 @@
   driver_->fn.glWindowRectanglesEXTFn(mode, n, box);
 }
 
+void TraceGLApi::glAcquireTexturesANGLEFn(GLuint numTextures,
+                                          const GLuint* textures,
+                                          const GLenum* layouts) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glAcquireTexturesANGLE");
+  gl_api_->glAcquireTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void TraceGLApi::glActiveShaderProgramFn(GLuint pipeline, GLuint program) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glActiveShaderProgram");
   gl_api_->glActiveShaderProgramFn(pipeline, program);
@@ -9345,6 +9376,13 @@
   gl_api_->glReleaseShaderCompilerFn();
 }
 
+void TraceGLApi::glReleaseTexturesANGLEFn(GLuint numTextures,
+                                          const GLuint* textures,
+                                          GLenum* layouts) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReleaseTexturesANGLE");
+  gl_api_->glReleaseTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void TraceGLApi::glRenderbufferStorageEXTFn(GLenum target,
                                             GLenum internalformat,
                                             GLsizei width,
@@ -10379,6 +10417,16 @@
   gl_api_->glWindowRectanglesEXTFn(mode, n, box);
 }
 
+void LogGLApi::glAcquireTexturesANGLEFn(GLuint numTextures,
+                                        const GLuint* textures,
+                                        const GLenum* layouts) {
+  GL_SERVICE_LOG("glAcquireTexturesANGLE"
+                 << "(" << numTextures << ", "
+                 << static_cast<const void*>(textures) << ", "
+                 << static_cast<const void*>(layouts) << ")");
+  gl_api_->glAcquireTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void LogGLApi::glActiveShaderProgramFn(GLuint pipeline, GLuint program) {
   GL_SERVICE_LOG("glActiveShaderProgram"
                  << "(" << pipeline << ", " << program << ")");
@@ -14208,6 +14256,16 @@
   gl_api_->glReleaseShaderCompilerFn();
 }
 
+void LogGLApi::glReleaseTexturesANGLEFn(GLuint numTextures,
+                                        const GLuint* textures,
+                                        GLenum* layouts) {
+  GL_SERVICE_LOG("glReleaseTexturesANGLE"
+                 << "(" << numTextures << ", "
+                 << static_cast<const void*>(textures) << ", "
+                 << static_cast<const void*>(layouts) << ")");
+  gl_api_->glReleaseTexturesANGLEFn(numTextures, textures, layouts);
+}
+
 void LogGLApi::glRenderbufferStorageEXTFn(GLenum target,
                                           GLenum internalformat,
                                           GLsizei width,
@@ -15555,6 +15613,12 @@
 }
 }  // namespace
 
+void NoContextGLApi::glAcquireTexturesANGLEFn(GLuint numTextures,
+                                              const GLuint* textures,
+                                              const GLenum* layouts) {
+  NoContextHelper("glAcquireTexturesANGLE");
+}
+
 void NoContextGLApi::glActiveShaderProgramFn(GLuint pipeline, GLuint program) {
   NoContextHelper("glActiveShaderProgram");
 }
@@ -17995,6 +18059,12 @@
   NoContextHelper("glReleaseShaderCompiler");
 }
 
+void NoContextGLApi::glReleaseTexturesANGLEFn(GLuint numTextures,
+                                              const GLuint* textures,
+                                              GLenum* layouts) {
+  NoContextHelper("glReleaseTexturesANGLE");
+}
+
 void NoContextGLApi::glRenderbufferStorageEXTFn(GLenum target,
                                                 GLenum internalformat,
                                                 GLsizei width,
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index 4b381f8..039891f 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -17,6 +17,10 @@
 
 class GLContext;
 
+typedef void(GL_BINDING_CALL* glAcquireTexturesANGLEProc)(
+    GLuint numTextures,
+    const GLuint* textures,
+    const GLenum* layouts);
 typedef void(GL_BINDING_CALL* glActiveShaderProgramProc)(GLuint pipeline,
                                                          GLuint program);
 typedef void(GL_BINDING_CALL* glActiveTextureProc)(GLenum texture);
@@ -1412,6 +1416,10 @@
                                                            GLsizei* rows,
                                                            void* pixels);
 typedef void(GL_BINDING_CALL* glReleaseShaderCompilerProc)(void);
+typedef void(GL_BINDING_CALL* glReleaseTexturesANGLEProc)(
+    GLuint numTextures,
+    const GLuint* textures,
+    GLenum* layouts);
 typedef void(GL_BINDING_CALL* glRenderbufferStorageEXTProc)(
     GLenum target,
     GLenum internalformat,
@@ -1967,6 +1975,7 @@
   bool b_GL_ANGLE_semaphore_fuchsia;
   bool b_GL_ANGLE_texture_external_update;
   bool b_GL_ANGLE_translated_shader_source;
+  bool b_GL_ANGLE_vulkan_image;
   bool b_GL_ANGLE_webgl_compatibility;
   bool b_GL_APPLE_fence;
   bool b_GL_APPLE_sync;
@@ -2059,6 +2068,7 @@
 };
 
 struct ProcsGL {
+  glAcquireTexturesANGLEProc glAcquireTexturesANGLEFn;
   glActiveShaderProgramProc glActiveShaderProgramFn;
   glActiveTextureProc glActiveTextureFn;
   glAttachShaderProc glAttachShaderFn;
@@ -2450,6 +2460,7 @@
   glReadPixelsProc glReadPixelsFn;
   glReadPixelsRobustANGLEProc glReadPixelsRobustANGLEFn;
   glReleaseShaderCompilerProc glReleaseShaderCompilerFn;
+  glReleaseTexturesANGLEProc glReleaseTexturesANGLEFn;
   glRenderbufferStorageEXTProc glRenderbufferStorageEXTFn;
   glRenderbufferStorageMultisampleProc glRenderbufferStorageMultisampleFn;
   glRenderbufferStorageMultisampleAdvancedAMDProc
@@ -2589,6 +2600,9 @@
 
   virtual void SetDisabledExtensions(const std::string& disabled_extensions) {}
 
+  virtual void glAcquireTexturesANGLEFn(GLuint numTextures,
+                                        const GLuint* textures,
+                                        const GLenum* layouts) = 0;
   virtual void glActiveShaderProgramFn(GLuint pipeline, GLuint program) = 0;
   virtual void glActiveTextureFn(GLenum texture) = 0;
   virtual void glAttachShaderFn(GLuint program, GLuint shader) = 0;
@@ -3830,6 +3844,9 @@
                                          GLsizei* rows,
                                          void* pixels) = 0;
   virtual void glReleaseShaderCompilerFn(void) = 0;
+  virtual void glReleaseTexturesANGLEFn(GLuint numTextures,
+                                        const GLuint* textures,
+                                        GLenum* layouts) = 0;
   virtual void glRenderbufferStorageEXTFn(GLenum target,
                                           GLenum internalformat,
                                           GLsizei width,
@@ -4322,6 +4339,8 @@
 
 }  // namespace gl
 
+#define glAcquireTexturesANGLE \
+  ::gl::g_current_gl_context->glAcquireTexturesANGLEFn
 #define glActiveShaderProgram \
   ::gl::g_current_gl_context->glActiveShaderProgramFn
 #define glActiveTexture ::gl::g_current_gl_context->glActiveTextureFn
@@ -4871,6 +4890,8 @@
   ::gl::g_current_gl_context->glReadPixelsRobustANGLEFn
 #define glReleaseShaderCompiler \
   ::gl::g_current_gl_context->glReleaseShaderCompilerFn
+#define glReleaseTexturesANGLE \
+  ::gl::g_current_gl_context->glReleaseTexturesANGLEFn
 #define glRenderbufferStorageEXT \
   ::gl::g_current_gl_context->glRenderbufferStorageEXTFn
 #define glRenderbufferStorageMultisample \
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index 17bee48..c0c4dc1 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -25,6 +25,14 @@
 namespace gl {
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glAcquireTexturesANGLE(GLuint numTextures,
+                                             const GLuint* textures,
+                                             const GLenum* layouts) {
+  MakeGlMockFunctionUnique("glAcquireTexturesANGLE");
+  interface_->AcquireTexturesANGLE(numTextures, textures, layouts);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glActiveShaderProgram(GLuint pipeline, GLuint program) {
   MakeGlMockFunctionUnique("glActiveShaderProgram");
   interface_->ActiveShaderProgram(pipeline, program);
@@ -4066,6 +4074,14 @@
 }
 
 void GL_BINDING_CALL
+MockGLInterface::Mock_glReleaseTexturesANGLE(GLuint numTextures,
+                                             const GLuint* textures,
+                                             GLenum* layouts) {
+  MakeGlMockFunctionUnique("glReleaseTexturesANGLE");
+  interface_->ReleaseTexturesANGLE(numTextures, textures, layouts);
+}
+
+void GL_BINDING_CALL
 MockGLInterface::Mock_glRenderbufferStorage(GLenum target,
                                             GLenum internalformat,
                                             GLsizei width,
@@ -5394,6 +5410,8 @@
 
 GLFunctionPointerType GL_BINDING_CALL
 MockGLInterface::GetGLProcAddress(const char* name) {
+  if (strcmp(name, "glAcquireTexturesANGLE") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glAcquireTexturesANGLE);
   if (strcmp(name, "glActiveShaderProgram") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glActiveShaderProgram);
   if (strcmp(name, "glActiveTexture") == 0)
@@ -6557,6 +6575,8 @@
   if (strcmp(name, "glReleaseShaderCompiler") == 0)
     return reinterpret_cast<GLFunctionPointerType>(
         Mock_glReleaseShaderCompiler);
+  if (strcmp(name, "glReleaseTexturesANGLE") == 0)
+    return reinterpret_cast<GLFunctionPointerType>(Mock_glReleaseTexturesANGLE);
   if (strcmp(name, "glRenderbufferStorage") == 0)
     return reinterpret_cast<GLFunctionPointerType>(Mock_glRenderbufferStorage);
   if (strcmp(name, "glRenderbufferStorageEXT") == 0)
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 29b9cb5..570fd56 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -12,6 +12,9 @@
 // no-include-guard-because-multiply-included
 // NOLINT(build/header_guard)
 
+static void GL_BINDING_CALL Mock_glAcquireTexturesANGLE(GLuint numTextures,
+                                                        const GLuint* textures,
+                                                        const GLenum* layouts);
 static void GL_BINDING_CALL Mock_glActiveShaderProgram(GLuint pipeline,
                                                        GLuint program);
 static void GL_BINDING_CALL Mock_glActiveTexture(GLenum texture);
@@ -1743,6 +1746,9 @@
                                                           GLsizei* rows,
                                                           void* data);
 static void GL_BINDING_CALL Mock_glReleaseShaderCompiler(void);
+static void GL_BINDING_CALL Mock_glReleaseTexturesANGLE(GLuint numTextures,
+                                                        const GLuint* textures,
+                                                        GLenum* layouts);
 static void GL_BINDING_CALL Mock_glRenderbufferStorage(GLenum target,
                                                        GLenum internalformat,
                                                        GLsizei width,
diff --git a/ui/gl/gl_image_egl_angle_vulkan.cc b/ui/gl/gl_image_egl_angle_vulkan.cc
new file mode 100644
index 0000000..f26c107
--- /dev/null
+++ b/ui/gl/gl_image_egl_angle_vulkan.cc
@@ -0,0 +1,70 @@
+// 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 "ui/gl/gl_image_egl_angle_vulkan.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace gl {
+
+GLImageEGLAngleVulkan::GLImageEGLAngleVulkan(const gfx::Size& size)
+    : GLImageEGL(size) {}
+
+GLImageEGLAngleVulkan::~GLImageEGLAngleVulkan() = default;
+
+bool GLImageEGLAngleVulkan::Initialize(unsigned int texture) {
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+  if (egl_display == EGL_NO_DISPLAY) {
+    LOG(ERROR) << "Failed to retrieve EGLDisplay";
+    return false;
+  }
+
+  GLContext* current_context = GLContext::GetCurrent();
+  if (!current_context || !current_context->IsCurrent(nullptr)) {
+    LOG(ERROR) << "No gl context bound to the current thread";
+    return false;
+  }
+
+  EGLContext context_handle =
+      reinterpret_cast<EGLContext>(current_context->GetHandle());
+  DCHECK_NE(context_handle, EGL_NO_CONTEXT);
+  bool result = GLImageEGL::Initialize(
+      context_handle, EGL_GL_TEXTURE_2D_KHR,
+      reinterpret_cast<EGLClientBuffer>(texture), nullptr);
+
+  if (!result) {
+    LOG(ERROR) << "Create EGLImage from texture failed";
+    return false;
+  }
+
+  return true;
+}
+
+VkImage GLImageEGLAngleVulkan::ExportVkImage(VkImageCreateInfo* info) {
+  DCHECK(info);
+
+  EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+  if (egl_display == EGL_NO_DISPLAY) {
+    LOG(ERROR) << "Failed to retrieve EGLDisplay";
+    return VK_NULL_HANDLE;
+  }
+
+  VkImage vk_image = VK_NULL_HANDLE;
+  if (!eglExportVkImageANGLE(egl_display, egl_image_, &vk_image, info)) {
+    LOG(ERROR) << "Export VkImage from EGLImage failed";
+    return VK_NULL_HANDLE;
+  }
+
+  DCHECK_NE(vk_image, VK_NULL_HANDLE);
+  DCHECK_EQ(info->sType, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
+  DCHECK_EQ(size_, gfx::Size(info->extent.width, info->extent.height));
+  return vk_image;
+}
+
+}  // namespace gl
diff --git a/ui/gl/gl_image_egl_angle_vulkan.h b/ui/gl/gl_image_egl_angle_vulkan.h
new file mode 100644
index 0000000..81dc41c
--- /dev/null
+++ b/ui/gl/gl_image_egl_angle_vulkan.h
@@ -0,0 +1,33 @@
+// 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 UI_GL_GL_IMAGE_EGL_ANGLE_VULKAN_H_
+#define UI_GL_GL_IMAGE_EGL_ANGLE_VULKAN_H_
+
+#include <stdint.h>
+#include <vulkan/vulkan_core.h>
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_export.h"
+#include "ui/gl/gl_image_egl.h"
+
+namespace gl {
+
+class GL_EXPORT GLImageEGLAngleVulkan : public GLImageEGL {
+ public:
+  explicit GLImageEGLAngleVulkan(const gfx::Size& size);
+
+  GLImageEGLAngleVulkan(const GLImageEGLAngleVulkan&) = delete;
+  GLImageEGLAngleVulkan& operator=(const GLImageEGLAngleVulkan&) = delete;
+
+  bool Initialize(unsigned int texture);
+  VkImage ExportVkImage(VkImageCreateInfo* info);
+
+ protected:
+  ~GLImageEGLAngleVulkan() override;
+};
+
+}  // namespace gl
+
+#endif  // UI_GL_GL_IMAGE_EGL_ANGLE_VULKAN_H_
diff --git a/ui/gl/gl_mock_autogen_egl.h b/ui/gl/gl_mock_autogen_egl.h
index f8ccf51b..497a7d1 100644
--- a/ui/gl/gl_mock_autogen_egl.h
+++ b/ui/gl/gl_mock_autogen_egl.h
@@ -89,6 +89,11 @@
                         int* fourcc,
                         int* num_planes,
                         EGLuint64KHR* modifiers));
+MOCK_METHOD4(ExportVkImageANGLE,
+             EGLBoolean(EGLDisplay dpy,
+                        EGLImageKHR image,
+                        void* vk_image,
+                        void* vk_image_create_info));
 MOCK_METHOD5(GetCompositorTimingANDROID,
              EGLBoolean(EGLDisplay dpy,
                         EGLSurface surface,
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index e370fd0..b4c90e6 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -12,6 +12,10 @@
 // no-include-guard-because-multiply-included
 // NOLINT(build/header_guard)
 
+MOCK_METHOD3(AcquireTexturesANGLE,
+             void(GLuint numTextures,
+                  const GLuint* textures,
+                  const GLenum* layouts));
 MOCK_METHOD2(ActiveShaderProgram, void(GLuint pipeline, GLuint program));
 MOCK_METHOD1(ActiveTexture, void(GLenum texture));
 MOCK_METHOD2(AttachShader, void(GLuint program, GLuint shader));
@@ -1177,6 +1181,8 @@
 // TODO(zmo): crbug.com/456340
 // glReadPixelsRobustANGLE cannot be mocked because it has 11 args.
 MOCK_METHOD0(ReleaseShaderCompiler, void());
+MOCK_METHOD3(ReleaseTexturesANGLE,
+             void(GLuint numTextures, const GLuint* textures, GLenum* layouts));
 MOCK_METHOD4(
     RenderbufferStorageEXT,
     void(GLenum target, GLenum internalformat, GLsizei width, GLsizei height));
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h
index a934627..1fef9f3e 100644
--- a/ui/gl/gl_stub_autogen_gl.h
+++ b/ui/gl/gl_stub_autogen_gl.h
@@ -11,6 +11,9 @@
 #ifndef UI_GL_GL_STUB_AUTOGEN_GL_H_
 #define UI_GL_GL_STUB_AUTOGEN_GL_H_
 
+void glAcquireTexturesANGLEFn(GLuint numTextures,
+                              const GLuint* textures,
+                              const GLenum* layouts) override {}
 void glActiveShaderProgramFn(GLuint pipeline, GLuint program) override {}
 void glActiveTextureFn(GLenum texture) override {}
 void glAttachShaderFn(GLuint program, GLuint shader) override {}
@@ -1221,6 +1224,9 @@
                                GLsizei* rows,
                                void* pixels) override {}
 void glReleaseShaderCompilerFn() override {}
+void glReleaseTexturesANGLEFn(GLuint numTextures,
+                              const GLuint* textures,
+                              GLenum* layouts) override {}
 void glRenderbufferStorageEXTFn(GLenum target,
                                 GLenum internalformat,
                                 GLsizei width,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 2d1b712..033acf24 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -212,6 +212,7 @@
 bool g_egl_angle_external_context_and_surface_supported = false;
 bool g_egl_ext_query_device_supported = false;
 bool g_egl_angle_context_virtualization_supported = false;
+bool g_EGL_ANGLE_vulkan_image_supported = false;
 EGLGpuSwitchingObserver* g_egl_gpu_switching_observer = nullptr;
 
 constexpr const char kSwapEventTraceCategories[] = "gpu";
@@ -1128,6 +1129,9 @@
   g_egl_angle_context_virtualization_supported =
       HasEGLExtension("EGL_ANGLE_context_virtualization");
 
+  g_EGL_ANGLE_vulkan_image_supported =
+      HasEGLExtension("EGL_ANGLE_vulkan_image");
+
   if (g_egl_angle_power_preference_supported) {
     g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver();
     ui::GpuSwitchingManager::GetInstance()->AddObserver(
@@ -1298,6 +1302,11 @@
   return g_egl_angle_context_virtualization_supported;
 }
 
+// static
+bool GLSurfaceEGL::IsANGLEVulkanImageClientBufferSupported() {
+  return g_EGL_ANGLE_vulkan_image_supported;
+}
+
 bool GLSurfaceEGL::IsEGLQueryDeviceSupported() {
   return g_egl_ext_query_device_supported;
 }
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index d9c4819..3aac23c 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -133,6 +133,8 @@
   static bool IsANGLEDisplayPowerPreferenceSupported();
   static bool IsANGLEExternalContextAndSurfaceSupported();
   static bool IsANGLEContextVirtualizationSupported();
+  static bool IsANGLEVulkanImageClientBufferSupported();
+
   static bool IsEGLQueryDeviceSupported();
 
  protected:
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 6b79c6b..5279a9f9 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -294,8 +294,10 @@
 void GbmSurfaceless::OnSubmission(gfx::SwapResult result,
                                   gfx::GpuFenceHandle release_fence) {
   submitted_frame_->swap_result = result;
-  // TODO(edcourtney): Re-enable fences here after fixing performance
-  // regression.
+  if (!release_fence.is_null()) {
+    std::move(submitted_frame_->completion_callback)
+        .Run(gfx::SwapCompletionResult(result, std::move(release_fence)));
+  }
 }
 
 void GbmSurfaceless::OnPresentation(const gfx::PresentationFeedback& feedback) {
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 41e947f7..51518e1 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "base/containers/adapters.h"
+#include "base/containers/contains.h"
 #include "base/i18n/case_conversion.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_action_data.h"
@@ -157,7 +158,8 @@
 void MenuItemView::OnThemeChanged() {
   View::OnThemeChanged();
   // Force updating as the colors may have changed.
-  UpdateSelectionBasedState(ShouldPaintAsSelected(PaintMode::kNormal));
+  if (!IsScheduledForDeletion())
+    UpdateSelectionBasedState(ShouldPaintAsSelected(PaintMode::kNormal));
 }
 
 void MenuItemView::ViewHierarchyChanged(
@@ -1464,8 +1466,10 @@
 }
 
 void MenuItemView::UpdateSelectionBasedStateIfChanged(PaintMode mode) {
-  // Selection state depends upon NativeTheme.
-  if (!GetWidget())
+  // Selection state depends upon NativeTheme. Selection based state could also
+  // depend on the menu model so avoid the update if the item is scheduled to be
+  // deleted.
+  if (!GetWidget() || IsScheduledForDeletion())
     return;
 
   const bool paint_as_selected = ShouldPaintAsSelected(mode);
@@ -1508,6 +1512,12 @@
           (NonIconChildViewsCount() == 0));
 }
 
+bool MenuItemView::IsScheduledForDeletion() const {
+  const MenuItemView* parent = GetParentMenuItem();
+  return parent && (base::Contains(parent->removed_items_, this) ||
+                    parent->IsScheduledForDeletion());
+}
+
 BEGIN_METADATA(MenuItemView, View)
 END_METADATA
 
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index b09f8fd..8369aaca 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -377,6 +377,10 @@
   // item.
   bool IsTraversableByKeyboard() const;
 
+  bool last_paint_as_selected_for_testing() const {
+    return last_paint_as_selected_;
+  }
+
  protected:
   // Creates a MenuItemView. This is used by the various AddXXX methods.
   MenuItemView(MenuItemView* parent, int command, Type type);
@@ -539,6 +543,15 @@
   // Returns true if the MenuItemView should be painted as selected.
   bool ShouldPaintAsSelected(PaintMode mode) const;
 
+  // Returns true if this item or any anscestor menu items have been removed and
+  // are currently scheduled for deletion. Items can exist in this state after
+  // they have been removed from the menu but before ChildrenChanged() has been
+  // called.
+  // Menu items scheduled for deletion may not accurately reflect the state of
+  // the menu model and this should be checked when performing actions that
+  // could interact with model state.
+  bool IsScheduledForDeletion() const;
+
   // The delegate. This is only valid for the root menu item. You shouldn't
   // use this directly, instead use GetDelegate() which walks the tree as
   // as necessary.
diff --git a/ui/views/controls/menu/menu_item_view_unittest.cc b/ui/views/controls/menu/menu_item_view_unittest.cc
index 5979488a..a408129 100644
--- a/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -479,6 +479,68 @@
   EXPECT_FALSE(ViewTestApi(submenu_arrow_image_view).needs_paint());
 }
 
+// Tests to ensure that selection based state is not updated if a menu item or
+// an anscestor item has been scheduled for deletion. This guards against
+// removed but not-yet-deleted MenuItemViews using stale model data to update
+// state.
+TEST_F(MenuItemViewPaintUnitTest,
+       SelectionBasedStateNotUpdatedWhenScheduledForDeletion) {
+  MenuItemView* submenu_item =
+      menu_item_view()->AppendSubMenu(1, u"submenu_item");
+  MenuItemView* submenu_child =
+      submenu_item->AppendMenuItem(1, u"submenu_child");
+
+  menu_runner()->RunMenuAt(widget(), nullptr, gfx::Rect(),
+                           MenuAnchorPosition::kTopLeft,
+                           ui::MENU_SOURCE_KEYBOARD);
+
+  // Show both the root and nested menus.
+  SubmenuView* submenu = submenu_item->GetSubmenu();
+  MenuHost::InitParams params;
+  params.parent = widget();
+  params.bounds = submenu_item->bounds();
+  submenu->ShowAt(params);
+
+  // The selected bit and selection based state should both update for all menu
+  // items while they and their anscestors remain part of the menu.
+  EXPECT_FALSE(submenu_item->IsSelected());
+  EXPECT_FALSE(submenu_item->last_paint_as_selected_for_testing());
+  submenu_item->SetSelected(true);
+  EXPECT_TRUE(submenu_item->IsSelected());
+  EXPECT_TRUE(submenu_item->last_paint_as_selected_for_testing());
+  submenu_item->SetSelected(false);
+  EXPECT_FALSE(submenu_item->IsSelected());
+  EXPECT_FALSE(submenu_item->last_paint_as_selected_for_testing());
+
+  EXPECT_FALSE(submenu_child->IsSelected());
+  EXPECT_FALSE(submenu_child->last_paint_as_selected_for_testing());
+  submenu_child->SetSelected(true);
+  EXPECT_TRUE(submenu_child->IsSelected());
+  EXPECT_TRUE(submenu_child->last_paint_as_selected_for_testing());
+  submenu_child->SetSelected(false);
+  EXPECT_FALSE(submenu_child->IsSelected());
+  EXPECT_FALSE(submenu_child->last_paint_as_selected_for_testing());
+
+  // Remove the child items from the root.
+  menu_item_view()->RemoveAllMenuItems();
+
+  // The selected bit should still update but selection based state, proxied by
+  // `last_paint_as_selected_`, should remain unchanged.
+  submenu_item->SetSelected(true);
+  EXPECT_TRUE(submenu_item->IsSelected());
+  EXPECT_FALSE(submenu_item->last_paint_as_selected_for_testing());
+  submenu_item->SetSelected(false);
+  EXPECT_FALSE(submenu_item->IsSelected());
+  EXPECT_FALSE(submenu_item->last_paint_as_selected_for_testing());
+
+  submenu_child->SetSelected(true);
+  EXPECT_TRUE(submenu_child->IsSelected());
+  EXPECT_FALSE(submenu_child->last_paint_as_selected_for_testing());
+  submenu_child->SetSelected(false);
+  EXPECT_FALSE(submenu_child->IsSelected());
+  EXPECT_FALSE(submenu_child->last_paint_as_selected_for_testing());
+}
+
 // Sets up a custom MenuDelegate that expects functions aren't called. See
 // DontAskForFontsWhenAddingSubmenu.
 class MenuItemViewAccessTest : public MenuItemViewPaintUnitTest {